Commit 029e240b authored by Nigel Kukard's avatar Nigel Kukard
Browse files

Merge branch 'nk-autotopup' into 'master'

FEATURE: Auto-topup



See merge request !419
parents 9440002c 4297ea5c
Pipeline #290 passed with stages
in 3 minutes and 17 seconds
...@@ -27,7 +27,7 @@ make-test: ...@@ -27,7 +27,7 @@ make-test:
- apt-get install -y git make - apt-get install -y git make
- apt-get install -y libdevel-cover-perl libpod-coverage-perl libtest-most-perl - apt-get install -y libdevel-cover-perl libpod-coverage-perl libtest-most-perl
- apt-get install -y libnet-server-perl libconfig-inifiles-perl libdatetime-perl libcache-fastmmap-perl libtimedate-perl - apt-get install -y libnet-server-perl libconfig-inifiles-perl libdatetime-perl libcache-fastmmap-perl libtimedate-perl
libcrypt-des-perl libcrypt-rc4-perl libdigest-sha-perl libdigest-md4-perl libcrypt-des-perl libcrypt-rc4-perl libdigest-sha-perl libdigest-md4-perl libmime-lite-perl
- apt-get install -y mysql-server - apt-get install -y mysql-server
# Start services and create dirs we need # Start services and create dirs we need
......
#!/bin/bash
# Database translation/creation script
# Copyright (C) 2009-2016, AllWorldIT
# Copyright (C) 2008, LinuxRulz
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
database="$1"
file="$2"
prefix="$3"
# Display usage info
display_usage() {
echo "Usage: $0 <database type> <file> [prefix]"
echo
echo "Valid database types:"
echo " mysql - For MySQL v5.5+"
echo " pgsql - For PostgreSQL"
echo " sqlite - For SQLite v3"
echo
exit
}
# Check we have our params
if [ -z "$database" -o -z "$file" ]
then
display_usage
fi
# Check file exists
if [ ! -f "$file" ]
then
echo "ERROR: Cannot open file '$file'"
exit 1
fi
# Check what we converting for
case "$database" in
"mysql")
sed \
-e "s/@PREFIX@/$prefix/g" \
-e 's/@PRELOAD@/SET FOREIGN_KEY_CHECKS=0;/' \
-e 's/@POSTLOAD@/SET FOREIGN_KEY_CHECKS=1;/' \
-e 's/@CREATE_TABLE_SUFFIX@/ENGINE=InnoDB CHARACTER SET latin1 COLLATE latin1_bin/' \
-e 's/@SERIAL_TYPE@/SERIAL/' \
-e 's/@BIGINT_UNSIGNED@/BIGINT UNSIGNED/' \
-e 's/@INT_UNSIGNED@/INT UNSIGNED/' \
-e 's/@TRACK_KEY_LEN@/512/' \
-e 's/@SERIAL_REF_TYPE@/BIGINT UNSIGNED/' < "$file"
;;
"pgsql")
sed \
-e "s/@PREFIX@/$prefix/g" \
-e 's/@PRELOAD@/SET CONSTRAINTS ALL DEFERRED;/' \
-e 's/@POSTLOAD@//' \
-e 's/@CREATE_TABLE_SUFFIX@//' \
-e 's/@SERIAL_TYPE@/SERIAL PRIMARY KEY/' \
-e 's/@BIGINT_UNSIGNED@/INT8/' \
-e 's/@INT_UNSIGNED@/INT8/' \
-e 's/@TRACK_KEY_LEN@/512/' \
-e 's/@SERIAL_REF_TYPE@/INT8/' < "$file"
;;
"sqlite")
sed \
-e "s/@PREFIX@/$prefix/g" \
-e 's/@PRELOAD@//' \
-e 's/@POSTLOAD@//' \
-e 's/@CREATE_TABLE_SUFFIX@//' \
-e 's/@SERIAL_TYPE@/INTEGER PRIMARY KEY AUTOINCREMENT/' \
-e 's/@BIGINT_UNSIGNED@/INT8/' \
-e 's/@INT_UNSIGNED@/INT8/' \
-e 's/@TRACK_KEY_LEN@/512/' \
-e 's/@SERIAL_REF_TYPE@/INT8/' < "$file"
;;
*)
echo "ERROR: Invalid database type '$database'"
exit 1
;;
esac
...@@ -68,7 +68,19 @@ my @attributeReplyIgnoreList = ( ...@@ -68,7 +68,19 @@ my @attributeReplyIgnoreList = (
'SMRadius-Username-Transform', 'SMRadius-Username-Transform',
'SMRadius-Evaluate', 'SMRadius-Evaluate',
'SMRadius-Peer-Address', 'SMRadius-Peer-Address',
'SMRadius-Disable-WebUITopup' 'SMRadius-Disable-WebUITopup',
'SMRadius-AutoTopup-Traffic-Enabled',
'SMRadius-AutoTopup-Traffic-Amount',
'SMRadius-AutoTopup-Traffic-Limit',
'SMRadius-AutoTopup-Traffic-Notify',
'SMRadius-AutoTopup-Traffic-NotifyTemplate',
'SMRadius-AutoTopup-Traffic-Threshold',
'SMRadius-AutoTopup-Uptime-Enabled',
'SMRadius-AutoTopup-Uptime-Amount',
'SMRadius-AutoTopup-Uptime-Limit',
'SMRadius-AutoTopup-Uptime-Notify',
'SMRadius-AutoTopup-Uptime-NotifyTemplate',
'SMRadius-AutoTopup-Uptime-Threshold',
); );
my @attributeVReplyIgnoreList = ( my @attributeVReplyIgnoreList = (
); );
......
...@@ -80,6 +80,12 @@ if (!eval {require Cache::FastMmap; 1;}) { ...@@ -80,6 +80,12 @@ if (!eval {require Cache::FastMmap; 1;}) {
eval {use AWITPT::Cache;}; eval {use AWITPT::Cache;};
} }
# Check MIME::Lite is installed
if (!eval {require MIME::Lite; 1;}) {
print STDERR "You're missing MIME::Lite, try 'apt-get install libmime-lite-perl'\n";
exit 1;
}
## no critic (BuiltinFunctions::ProhibitStringyEval) ## no critic (BuiltinFunctions::ProhibitStringyEval)
eval qq{ eval qq{
...@@ -817,15 +823,6 @@ sub process_request { ...@@ -817,15 +823,6 @@ sub process_request {
} }
} }
# Tell the NAS we got its packet
my $resp = smradius::Radius::Packet->new($self->{'radius'}->{'dictionary'});
$resp->set_code('Accounting-Response');
$resp->set_identifier($pkt->identifier);
$resp->set_authenticator($pkt->authenticator);
$server->{'client'}->send(
auth_resp($resp->pack, getAttributeValue($user->{'ConfigAttributes'},"SMRadius-Config-Secret"))
);
# Are we going to POD the user? # Are we going to POD the user?
my $PODUser = 0; my $PODUser = 0;
...@@ -860,6 +857,15 @@ sub process_request { ...@@ -860,6 +857,15 @@ sub process_request {
} }
} }
# Tell the NAS we got its packet
my $resp = smradius::Radius::Packet->new($self->{'radius'}->{'dictionary'});
$resp->set_code('Accounting-Response');
$resp->set_identifier($pkt->identifier);
$resp->set_authenticator($pkt->authenticator);
$server->{'client'}->send(
auth_resp($resp->pack, getAttributeValue($user->{'ConfigAttributes'},"SMRadius-Config-Secret"))
);
# Build a list of our attributes in the packet # Build a list of our attributes in the packet
my $acctAttributes; my $acctAttributes;
foreach my $attr ($pkt->attributes) { foreach my $attr ($pkt->attributes) {
......
...@@ -355,7 +355,7 @@ sub getUsage ...@@ -355,7 +355,7 @@ sub getUsage
# Fetch data # Fetch data
my $sth = DBSelect(@dbDoParams); my $sth = DBSelect(@dbDoParams);
if (!$sth) { if (!$sth) {
$server->log(LOG_ERR,"[MOD_ACCOUNTING_SQL] Database query failed: %s",AWITPT::DB::DBLayer::Error()); $server->log(LOG_ERR,"[MOD_ACCOUNTING_SQL] Database query failed: %s",AWITPT::DB::DBLayer::error());
return; return;
} }
...@@ -463,7 +463,7 @@ sub acct_log ...@@ -463,7 +463,7 @@ sub acct_log
# Fetch previous records of the same session # Fetch previous records of the same session
my $sth = DBSelect(@dbDoParams); my $sth = DBSelect(@dbDoParams);
if (!$sth) { if (!$sth) {
$server->log(LOG_ERR,"[MOD_ACCOUNTING_SQL] Database query failed: %s",AWITPT::DB::DBLayer::Error()); $server->log(LOG_ERR,"[MOD_ACCOUNTING_SQL] Database query failed: %s",AWITPT::DB::DBLayer::error());
return; return;
} }
...@@ -555,7 +555,7 @@ sub acct_log ...@@ -555,7 +555,7 @@ sub acct_log
$sth = DBDo(@dbDoParams); $sth = DBDo(@dbDoParams);
if (!$sth) { if (!$sth) {
$server->log(LOG_ERR,"[MOD_ACCOUNTING_SQL] Failed to update accounting ALIVE record: ". $server->log(LOG_ERR,"[MOD_ACCOUNTING_SQL] Failed to update accounting ALIVE record: ".
AWITPT::DB::DBLayer::Error()); AWITPT::DB::DBLayer::error());
return MOD_RES_NACK; return MOD_RES_NACK;
} }
...@@ -584,7 +584,7 @@ sub acct_log ...@@ -584,7 +584,7 @@ sub acct_log
my $sth = DBDo(@dbDoParams); my $sth = DBDo(@dbDoParams);
if (!$sth) { if (!$sth) {
$server->log(LOG_ERR,"[MOD_ACCOUNTING_SQL] Failed to insert accounting START record: ". $server->log(LOG_ERR,"[MOD_ACCOUNTING_SQL] Failed to insert accounting START record: ".
AWITPT::DB::DBLayer::Error()); AWITPT::DB::DBLayer::error());
return MOD_RES_NACK; return MOD_RES_NACK;
} }
# Update first login? # Update first login?
...@@ -611,7 +611,7 @@ sub acct_log ...@@ -611,7 +611,7 @@ sub acct_log
# Update database (status) # Update database (status)
my $sth = DBDo(@dbDoParams); my $sth = DBDo(@dbDoParams);
if (!$sth) { if (!$sth) {
$server->log(LOG_ERR,"[MOD_ACCOUNTING_SQL] Failed to update accounting STOP record: %s",AWITPT::DB::DBLayer::Error()); $server->log(LOG_ERR,"[MOD_ACCOUNTING_SQL] Failed to update accounting STOP record: %s",AWITPT::DB::DBLayer::error());
return MOD_RES_NACK; return MOD_RES_NACK;
} }
} }
...@@ -633,7 +633,7 @@ sub fixDuplicates ...@@ -633,7 +633,7 @@ sub fixDuplicates
# Select duplicates # Select duplicates
my $sth = DBSelect(@dbDoParams); my $sth = DBSelect(@dbDoParams);
if (!$sth) { if (!$sth) {
$server->log(LOG_ERR,"[MOD_ACCOUNTING_SQL] Database query failed: %s",AWITPT::DB::DBLayer::Error()); $server->log(LOG_ERR,"[MOD_ACCOUNTING_SQL] Database query failed: %s",AWITPT::DB::DBLayer::error());
return; return;
} }
...@@ -656,7 +656,7 @@ sub fixDuplicates ...@@ -656,7 +656,7 @@ sub fixDuplicates
# Delete duplicates # Delete duplicates
$sth = DBDo(@dbDoParams); $sth = DBDo(@dbDoParams);
if (!$sth) { if (!$sth) {
$server->log(LOG_ERR,"[MOD_ACCOUNTING_SQL] Database query failed: %s",AWITPT::DB::DBLayer::Error()); $server->log(LOG_ERR,"[MOD_ACCOUNTING_SQL] Database query failed: %s",AWITPT::DB::DBLayer::error());
DBRollback(); DBRollback();
return; return;
} }
...@@ -704,7 +704,7 @@ sub cleanup ...@@ -704,7 +704,7 @@ sub cleanup
); );
if (!$sth) { if (!$sth) {
$server->log(LOG_ERR,"[MOD_ACCOUNTING_SQL] Cleanup => Failed to delete accounting summary record: ". $server->log(LOG_ERR,"[MOD_ACCOUNTING_SQL] Cleanup => Failed to delete accounting summary record: ".
AWITPT::DB::DBLayer::Error()); AWITPT::DB::DBLayer::error());
DBRollback(); DBRollback();
return; return;
} }
...@@ -729,7 +729,7 @@ sub cleanup ...@@ -729,7 +729,7 @@ sub cleanup
); );
if (!$sth) { if (!$sth) {
$server->log(LOG_ERR,"[MOD_ACCOUNTING_SQL] Cleanup => Failed to select accounting record: ". $server->log(LOG_ERR,"[MOD_ACCOUNTING_SQL] Cleanup => Failed to select accounting record: ".
AWITPT::DB::DBLayer::Error()); AWITPT::DB::DBLayer::error());
return; return;
} }
...@@ -836,7 +836,7 @@ sub cleanup ...@@ -836,7 +836,7 @@ sub cleanup
); );
if (!$sth) { if (!$sth) {
$server->log(LOG_ERR,"[MOD_ACCOUNTING_SQL] Cleanup => Failed to create accounting summary record: ". $server->log(LOG_ERR,"[MOD_ACCOUNTING_SQL] Cleanup => Failed to create accounting summary record: ".
AWITPT::DB::DBLayer::Error()); AWITPT::DB::DBLayer::error());
DBRollback(); DBRollback();
return; return;
} }
......
...@@ -27,7 +27,9 @@ use smradius::logging; ...@@ -27,7 +27,9 @@ use smradius::logging;
use smradius::util; use smradius::util;
use AWITPT::Util; use AWITPT::Util;
use POSIX qw(floor); use List::Util qw( min );
use MIME::Lite;
use POSIX qw( floor );
# Load exporter # Load exporter
...@@ -59,9 +61,6 @@ my $UPTIME_LIMIT_ATTRIBUTE = 'SMRadius-Capping-Uptime-Limit'; ...@@ -59,9 +61,6 @@ my $UPTIME_LIMIT_ATTRIBUTE = 'SMRadius-Capping-Uptime-Limit';
my $TRAFFIC_TOPUP_ATTRIBUTE = 'SMRadius-Capping-Traffic-Topup'; my $TRAFFIC_TOPUP_ATTRIBUTE = 'SMRadius-Capping-Traffic-Topup';
my $TIME_TOPUP_ATTRIBUTE = 'SMRadius-Capping-Uptime-Topup'; my $TIME_TOPUP_ATTRIBUTE = 'SMRadius-Capping-Uptime-Topup';
my $TRAFFIC_AUTOTOPUP_ATTRIBUTE = 'SMRadius-Capping-Traffic-AutoTopup';
my $TIME_AUTOTOPUP_ATTRIBUTE = 'SMRadius-Capping-Uptime-AutoTopup';
my $config; my $config;
...@@ -137,19 +136,15 @@ sub post_auth_hook ...@@ -137,19 +136,15 @@ sub post_auth_hook
# Get valid traffic and uptime topups # Get valid traffic and uptime topups
# #
# Check if there was any data returned at all # Check if there was any data returned at all
my $uptimeTopupAmount = _getConfigAttributeNumeric($server,$user,$TIME_TOPUP_ATTRIBUTE) // 0; my $uptimeTopupAmount = _getConfigAttributeNumeric($server,$user,$TIME_TOPUP_ATTRIBUTE) // 0;
my $trafficTopupAmount = _getConfigAttributeNumeric($server,$user,$TRAFFIC_TOPUP_ATTRIBUTE) // 0; my $trafficTopupAmount = _getConfigAttributeNumeric($server,$user,$TRAFFIC_TOPUP_ATTRIBUTE) // 0;
my $uptimeAutoTopupAmount = _getConfigAttributeNumeric($server,$user,$TIME_AUTOTOPUP_ATTRIBUTE) // 0;
my $trafficAutoTopupAmount = _getConfigAttributeNumeric($server,$user,$TRAFFIC_AUTOTOPUP_ATTRIBUTE) // 0;
# #
# Set the new uptime and traffic limits (limit, if any.. + topups) # Set the new uptime and traffic limits (limit, if any.. + topups)
# #
# Uptime.. # Uptime..
# // is a defined operator, $a ? defined($a) : $b # // is a defined operator, $a ? defined($a) : $b
my $uptimeLimitWithTopups = ($uptimeLimit // 0) + $uptimeTopupAmount; my $uptimeLimitWithTopups = ($uptimeLimit // 0) + $uptimeTopupAmount;
...@@ -159,18 +154,35 @@ sub post_auth_hook ...@@ -159,18 +154,35 @@ sub post_auth_hook
my $trafficLimitWithTopups = ($trafficLimit // 0) + $trafficTopupAmount; my $trafficLimitWithTopups = ($trafficLimit // 0) + $trafficTopupAmount;
#
# Do auto-topups for both traffic and uptime
#
my $autoTopupTrafficAdded = _doAutoTopup($server,$user,$accountingUsage->{'TotalDataUsage'},"traffic",
$trafficLimitWithTopups,1);
if (defined($autoTopupTrafficAdded)) {
$trafficLimitWithTopups += $autoTopupTrafficAdded;
}
my $autoTopupUptimeAdded = _doAutoTopup($server,$user,$accountingUsage->{'TotalSessionTime'},"uptime",
$uptimeLimitWithTopups,2);
if (defined($autoTopupUptimeAdded)) {
$uptimeLimitWithTopups += $autoTopupUptimeAdded;
}
# #
# Display our usages # Display our usages
# #
_logUptimeUsage($server,$accountingUsage,$uptimeLimit,$uptimeTopupAmount);
_logTrafficUsage($server,$accountingUsage,$trafficLimit,$trafficTopupAmount); _logUsage($server,$accountingUsage->{'TotalDataUsage'},$uptimeLimit,$uptimeTopupAmount,'traffic');
_logUsage($server,$accountingUsage->{'TotalSessionTime'},$uptimeLimit,$uptimeTopupAmount,'uptime');
# #
# Add conditional variables # Add conditional variables
# #
# Add attribute conditionals BEFORE override
addAttributeConditionalVariable($user,"SMRadius_Capping_TotalDataUsage",$accountingUsage->{'TotalDataUsage'}); addAttributeConditionalVariable($user,"SMRadius_Capping_TotalDataUsage",$accountingUsage->{'TotalDataUsage'});
addAttributeConditionalVariable($user,"SMRadius_Capping_TotalSessionTime",$accountingUsage->{'TotalSessionTime'}); addAttributeConditionalVariable($user,"SMRadius_Capping_TotalSessionTime",$accountingUsage->{'TotalSessionTime'});
...@@ -334,8 +346,6 @@ sub post_acct_hook ...@@ -334,8 +346,6 @@ sub post_acct_hook
# Check if there was any data returned at all # Check if there was any data returned at all
my $uptimeTopupAmount = _getConfigAttributeNumeric($server,$user,$TIME_TOPUP_ATTRIBUTE) // 0; my $uptimeTopupAmount = _getConfigAttributeNumeric($server,$user,$TIME_TOPUP_ATTRIBUTE) // 0;
my $trafficTopupAmount = _getConfigAttributeNumeric($server,$user,$TRAFFIC_TOPUP_ATTRIBUTE) // 0; my $trafficTopupAmount = _getConfigAttributeNumeric($server,$user,$TRAFFIC_TOPUP_ATTRIBUTE) // 0;
my $uptimeAutoTopupAmount = _getConfigAttributeNumeric($server,$user,$TIME_AUTOTOPUP_ATTRIBUTE) // 0;
my $trafficAutoTopupAmount = _getConfigAttributeNumeric($server,$user,$TRAFFIC_AUTOTOPUP_ATTRIBUTE) // 0;
# #
...@@ -350,12 +360,30 @@ sub post_acct_hook ...@@ -350,12 +360,30 @@ sub post_acct_hook
# // is a defined operator, $a ? defined($a) : $b # // is a defined operator, $a ? defined($a) : $b
my $trafficLimitWithTopups = ($trafficLimit // 0) + $trafficTopupAmount; my $trafficLimitWithTopups = ($trafficLimit // 0) + $trafficTopupAmount;
#
# Do auto-topups for both traffic and uptime
#
my $autoTopupTrafficAdded = _doAutoTopup($server,$user,$accountingUsage->{'TotalDataUsage'},"traffic",
$trafficLimitWithTopups,1);
if (defined($autoTopupTrafficAdded)) {
$trafficLimitWithTopups += $autoTopupTrafficAdded;
}
my $autoTopupUptimeAdded = _doAutoTopup($server,$user,$accountingUsage->{'TotalSessionTime'},"uptime",
$uptimeLimitWithTopups,2);
if (defined($autoTopupUptimeAdded)) {
$uptimeLimitWithTopups += $autoTopupUptimeAdded;
}
# #
# Display our usages # Display our usages
# #
_logUptimeUsage($server,$accountingUsage,$uptimeLimit,$uptimeTopupAmount); _logUsage($server,$accountingUsage->{'TotalDataUsage'},$uptimeLimit,$uptimeTopupAmount,'traffic');
_logTrafficUsage($server,$accountingUsage,$trafficLimit,$trafficTopupAmount); _logUsage($server,$accountingUsage->{'TotalSessionTime'},$uptimeLimit,$uptimeTopupAmount,'uptime');
# #
...@@ -476,62 +504,30 @@ sub _getAccountingUsage ...@@ -476,62 +504,30 @@ sub _getAccountingUsage
## @internal ## @internal
# Code snippet to log our uptime usage # Code snippet to log our uptime usage
sub _logUptimeUsage sub _logUsage
{ {
my ($server,$accountingUsage,$uptimeLimit,$uptimeTopupAmount) = @_; my ($server,$accountingUsage,$limit,$topupAmount,$type) = @_;
# Check if our limit is defined my $typeKey = ucfirst($type);
if (!defined($uptimeLimit)) {
$server->log(LOG_DEBUG,"[MOD_FEATURE_CAPPING] Uptime => Usage total: ".$accountingUsage->{'TotalSessionTime'}.
"min (Limit: Prepaid, Topups: ".$uptimeTopupAmount."min)");
return;
}
# If so, check if its > 0, which would depict its capped
if ($uptimeLimit > 0) {
$server->log(LOG_DEBUG,"[MOD_FEATURE_CAPPING] Uptime => Usage total: ".$accountingUsage->{'TotalSessionTime'}.
"min (Limit: ".$uptimeLimit."min, Topups: ".$uptimeTopupAmount."min)");
} else {
$server->log(LOG_DEBUG,"[MOD_FEATURE_CAPPING] Uptime => Usage total: ".$accountingUsage->{'TotalSessionTime'}.
"min (Limit: none, Topups: ".$uptimeTopupAmount."min)");
}
return;
}
## @internal
# Code snippet to log our traffic usage
sub _logTrafficUsage
{
my ($server,$accountingUsage,$trafficLimit,$trafficTopupAmount) = @_;
# Check if our limit is defined # Check if our limit is defined
if (!defined($trafficLimit)) { if (defined($limit) && !$limit) {
$server->log(LOG_DEBUG,"[MOD_FEATURE_CAPPING] Bandwidth => Usage total: ".$accountingUsage->{'TotalDataUsage'}. $limit = '-none-';
"Mbyte (Limit: Prepaid, Topups: ".$trafficTopupAmount."Mbyte)");
return;
}
# If so, check if its > 0, which would depict its capped
if ($trafficLimit > 0) {
$server->log(LOG_DEBUG,"[MOD_FEATURE_CAPPING] Bandwidth => Usage total: ".$accountingUsage->{'TotalDataUsage'}.
"Mbyte (Limit: ".$trafficLimit."Mbyte, Topups: ".$trafficTopupAmount."Mbyte)");
} else { } else {
$server->log(LOG_DEBUG,"[MOD_FEATURE_CAPPING] Bandwidth => Usage total: ".$accountingUsage->{'TotalDataUsage'}. $limit = '-topup-';
"Mbyte (Limit: none, Topups: ".$trafficTopupAmount."Mbyte)");
} }
$server->log(LOG_INFO,"[MOD_FEATURE_CAPPING] Capping information [type: %s, total: %s, limit: %s, topups: %s]",
$type,$accountingUsage,$limit,$topupAmount);
return; return;
} }
## @internal ## @internal
# Function snippet to return a numeric configuration attribute # Function snippet to return a user attribute
sub _getConfigAttributeNumeric sub _getConfigAttributeNumeric
{ {
my ($server,$user,$attributeName) = @_; my ($server,$user,$attributeName) = @_;
...@@ -559,5 +555,255 @@ sub _getConfigAttributeNumeric ...@@ -559,5 +555,255 @@ sub _getConfigAttributeNumeric
## @internal
# Function snippet to return a attribute
sub _getAttribute
{
my ($server,$user,$attributeName) = @_;
# Check the attribute exists
return if (!defined($user->{'Attributes'}->{$attributeName}));
$server->log(LOG_DEBUG,"[MOD_FEATURE_CAPPING] User attribute '".$attributeName."' is defined");
# Check the required operator is present in this case :=
if (!defined($user->{'Attributes'}->{$attributeName}->{':='})) {
$server->log(LOG_NOTICE,"[MOD_FEATURE_CAPPING] User attribute '".$attributeName."' has no ':=' operator");
return;