New Redis structure for services
This commit is contained in:
@@ -7,11 +7,12 @@ class UserConfig:
|
||||
|
||||
USER_CONFIG_KEYS = ['is_organization', 'entity_name']
|
||||
|
||||
def __init__(self, user_config_json):
|
||||
def __init__(self, user_config_json, db_user_id = None):
|
||||
config = json.loads(user_config_json)
|
||||
filtered_config = { key: config[key] for key in self.USER_CONFIG_KEYS if key in config.keys() }
|
||||
self.__check_config(filtered_config)
|
||||
self.__parse_config(filtered_config)
|
||||
self._user_id = self.__extract_uuid(db_user_id)
|
||||
|
||||
def __check_config(self, filtered_config):
|
||||
if len(filtered_config.keys()) != len(self.USER_CONFIG_KEYS):
|
||||
@@ -19,10 +20,6 @@ class UserConfig:
|
||||
|
||||
return True
|
||||
|
||||
def __parse_config(self, filtered_config):
|
||||
self._is_organization = filtered_config['is_organization']
|
||||
self._entity_name = filtered_config['entity_name']
|
||||
|
||||
@property
|
||||
def is_organization(self):
|
||||
return self._is_organization
|
||||
@@ -31,6 +28,18 @@ class UserConfig:
|
||||
def entity_name(self):
|
||||
return self._entity_name
|
||||
|
||||
@property
|
||||
def user_id(self):
|
||||
return self._user_id
|
||||
|
||||
def __parse_config(self, filtered_config):
|
||||
self._is_organization = filtered_config['is_organization']
|
||||
self._entity_name = filtered_config['entity_name']
|
||||
|
||||
def __extract_uuid(self, db_user_id):
|
||||
# Format: development_cartodb_user_<UUID>
|
||||
return db_user_id.split('_')[-1]
|
||||
|
||||
class GeocoderConfig:
|
||||
|
||||
GEOCODER_CONFIG_KEYS = ['street_geocoder_provider', 'google_maps_private_key',
|
||||
@@ -70,6 +79,10 @@ class GeocoderConfig:
|
||||
self._nokia_monthly_quota = filtered_config[self.NOKIA_QUOTA_KEY]
|
||||
self._nokia_soft_geocoder_limit = filtered_config[self.NOKIA_SOFT_LIMIT_KEY]
|
||||
|
||||
@property
|
||||
def service_type(self):
|
||||
return self._geocoder_type
|
||||
|
||||
@property
|
||||
def nokia_geocoder(self):
|
||||
return self._geocoder_type == self.NOKIA_GEOCODER
|
||||
|
||||
@@ -1,27 +1,31 @@
|
||||
import user_service
|
||||
import config_helper
|
||||
from datetime import date
|
||||
|
||||
class QuotaService:
|
||||
""" Class to manage all the quota operation for the Geocoder SQL API Extension """
|
||||
|
||||
def __init__(self, user_id, transaction_id, redis_connection):
|
||||
self._user_service = user_service.UserService(user_id, redis_connection)
|
||||
self.transaction_id = transaction_id
|
||||
def __init__(self, user_config, geocoder_config, redis_connection):
|
||||
self._user_config = user_config
|
||||
self._geocoder_config = geocoder_config
|
||||
self._user_service = user_service.UserService(self._user_config,
|
||||
self._geocoder_config.service_type, redis_connection)
|
||||
|
||||
def check_user_quota(self):
|
||||
""" Check if the current user quota surpasses the current quota """
|
||||
# TODO We need to add the hard/soft limit flag for the geocoder
|
||||
user_quota = self.user_service.user_quota()
|
||||
today = date.today()
|
||||
current_used = self.user_service.used_quota_month(today.year, today.month)
|
||||
soft_geocoder_limit = self.user_service.soft_geocoder_limit()
|
||||
# We don't have quota check for google geocoder
|
||||
if self._geocoder_config.google_geocoder:
|
||||
return True
|
||||
|
||||
return True if soft_geocoder_limit or (current_used + 1) < user_quota else False
|
||||
user_quota = self._geocoder_config.nokia_monthly_quota
|
||||
today = date.today()
|
||||
service_type = self._geocoder_config.service_type
|
||||
current_used = self._user_service.used_quota(service_type, today.year, today.month)
|
||||
soft_geocoder_limit = self._geocoder_config.nokia_soft_limit
|
||||
|
||||
print "User quota: {0} --- current_used: {1} --- limit: {2}".format(user_quota, current_used, soft_geocoder_limit)
|
||||
|
||||
return True if soft_geocoder_limit or current_used <= user_quota else False
|
||||
|
||||
def increment_geocoder_use(self, amount=1):
|
||||
today = date.today()
|
||||
self.user_service.increment_geocoder_use(today.year, today.month, self.transaction_id)
|
||||
|
||||
@property
|
||||
def user_service(self):
|
||||
return self._user_service
|
||||
self._user_service.increment_service_use(self._geocoder_config.service_type)
|
||||
@@ -12,39 +12,53 @@ class UserService:
|
||||
REDIS_CONNECTION_PORT = "redis_port"
|
||||
REDIS_CONNECTION_DB = "redis_db"
|
||||
|
||||
def __init__(self, user_id, redis_connection):
|
||||
self.user_id = user_id
|
||||
def __init__(self, user_config, service_type, redis_connection):
|
||||
self.user_config = user_config
|
||||
self.service_type = service_type
|
||||
self._redis_connection = redis_connection
|
||||
|
||||
def user_quota(self):
|
||||
# Check for exceptions or redis timeout
|
||||
user_quota = self._redis_connection.hget(self.__get_user_redis_key(), self.GEOCODING_QUOTA_KEY)
|
||||
return int(user_quota) if user_quota and int(user_quota) >= 0 else 0
|
||||
|
||||
def soft_geocoder_limit(self):
|
||||
""" Check what kind of limit the user has """
|
||||
soft_limit = self._redis_connection.hget(self.__get_user_redis_key(), self.GEOCODING_SOFT_LIMIT_KEY)
|
||||
return True if soft_limit == '1' else False
|
||||
|
||||
def used_quota_month(self, year, month):
|
||||
def used_quota(self, service_type, year, month, day=None):
|
||||
""" Recover the used quota for the user in the current month """
|
||||
# Check for exceptions or redis timeout
|
||||
current_used = 0
|
||||
for _, value in self._redis_connection.hscan_iter(self.__get_month_redis_key(year,month)):
|
||||
current_used += int(value)
|
||||
return current_used
|
||||
redis_key_data = self.__get_redis_key(service_type, year, month, day)
|
||||
current_use = self._redis_connection.hget(redis_key_data['redis_name'], redis_key_data['redis_key'])
|
||||
return int(current_use) if current_use else 0
|
||||
|
||||
def increment_geocoder_use(self, year, month, key, amount=1):
|
||||
# TODO Manage exceptions or timeout
|
||||
self._redis_connection.hincrby(self.__get_month_redis_key(year, month),key,amount)
|
||||
def increment_service_use(self, service_type, date=date.today(), amount=1):
|
||||
""" Increment the services uses in monthly and daily basis"""
|
||||
self.__increment_monthly_uses(date, service_type, amount)
|
||||
self.__increment_daily_uses(date, service_type, amount)
|
||||
|
||||
@property
|
||||
def redis_connection(self):
|
||||
return self._redis_connection
|
||||
# Private functions
|
||||
|
||||
def __get_month_redis_key(self, year, month):
|
||||
today = date.today()
|
||||
return "geocoder:{0}:{1}{2}".format(self.user_id, year, month)
|
||||
def __increment_monthly_uses(self, date, service_type, amount):
|
||||
redis_key_data = self.__get_redis_key(service_type, date.year, date.month)
|
||||
self._redis_connection.hincrby(redis_key_data['redis_name'],redis_key_data['redis_key'],amount)
|
||||
|
||||
def __get_user_redis_key(self):
|
||||
return "geocoder:{0}".format(self.user_id)
|
||||
def __increment_daily_uses(self, date, service_type, amount):
|
||||
redis_key_data = self.__get_redis_key(service_type, date.year, date.month, date.day)
|
||||
self._redis_connection.hincrby(redis_key_data['redis_name'],redis_key_data['redis_key'],amount)
|
||||
|
||||
def __get_redis_key(self, service_type, year, month, day=None):
|
||||
redis_name = self.__parse_redis_name(service_type,day)
|
||||
redis_key = self.__parse_redis_key(year,month,day)
|
||||
|
||||
return {'redis_name': redis_name, 'redis_key': redis_key}
|
||||
|
||||
def __parse_redis_name(self,service_type, day=None):
|
||||
prefix = "org" if self.user_config.is_organization else "user"
|
||||
dated_key = "used_quota_day" if day else "used_quota_month"
|
||||
redis_name = "{0}:{1}:{2}:{3}".format(
|
||||
prefix, self.user_config.entity_name, service_type, dated_key
|
||||
)
|
||||
if self.user_config.is_organization and day:
|
||||
redis_name = "{0}:{1}".format(redis_name, self.user_config.user_id)
|
||||
|
||||
return redis_name
|
||||
|
||||
def __parse_redis_key(self,year,month,day=None):
|
||||
if day:
|
||||
redis_key = "{0}_{1}_{2}".format(year,month,day)
|
||||
else:
|
||||
redis_key = "{0}_{1}".format(year,month)
|
||||
|
||||
return redis_key
|
||||
|
||||
Reference in New Issue
Block a user