Module licenseware.quota.quota

Expand source code
import sys
import datetime
import dateutil.parser as dateparser
from typing import Tuple
from dataclasses import dataclass

from marshmallow import Schema

from licenseware import mongodata
from licenseware.common.constants import envs, states
from licenseware.common.serializers import QuotaSchema
from licenseware.tenants.info import get_tenants_list, get_user_profile
from licenseware.utils.logger import log
from licenseware.decorators.failsafe_decorator import failsafe


@dataclass
class quota_plan:
    UNLIMITED: str = "UNLIMITED"
    FREE: str = "FREE"


def get_quota_reset_date(current_date: datetime.datetime = datetime.datetime.utcnow()):
    quota_reset_date = current_date + datetime.timedelta(days=30)
    return quota_reset_date.isoformat()


class Quota:

    def __init__(
            self,
            tenant_id: str,
            auth_token: str,
            uploader_id: str,
            units: int,
            schema: Schema = None,
            collection: str = None,
    ):

        self.units = units
        self.tenant_id = tenant_id if not envs.DESKTOP_ENVIRONMENT else envs.DESKTOP_TENANT_ID
        self.auth_token = auth_token
        self.uploader_id = uploader_id
        self.schema = schema or QuotaSchema
        self.collection = collection or envs.MONGO_COLLECTION_UTILIZATION_NAME

        if envs.DESKTOP_ENVIRONMENT:
            self.tenants = [envs.DESKTOP_TENANT_ID]
            self.plan_type = quota_plan.UNLIMITED
        else:
            self.tenants = get_tenants_list(self.tenant_id, self.auth_token)
            self.user_profile = get_user_profile(self.tenant_id, self.auth_token)
            self.plan_type = self.user_profile["plan_type"].upper()

        # This is used to calculate quota
        self.user_query = {
            'tenant_id': {"$in": self.tenants},
            'uploader_id': self.uploader_id
        }

        # This is used to update quota
        self.tenant_query = {
            'tenant_id': self.tenant_id,
            'uploader_id': self.uploader_id
        }

        # Making sure quota is initialized
        response, status_code = self.init_quota()
        if status_code != 200:
            # will be cached in the api make sure to add @failsafe(failcode=500) decorator
            raise Exception(response['message'])

    def get_monthly_quota(self):
        if self.plan_type == quota_plan.UNLIMITED:
            return sys.maxsize
        return self.units

    def init_quota(self) -> Tuple[dict, int]:

        results = mongodata.fetch(
            match=self.tenant_query,
            collection=self.collection
        )

        if results:
            return {'status': states.SUCCESS, 'message': 'Quota initialized'}, 200

        utilization_data = {
            "tenant_id": self.tenant_id,
            "uploader_id": self.uploader_id,
            "monthly_quota": self.get_monthly_quota(),
            "monthly_quota_consumed": 0,
            "quota_reset_date": get_quota_reset_date()
        }

        inserted_ids = mongodata.insert(
            schema=self.schema, data=utilization_data, collection=self.collection
        )

        if isinstance(inserted_ids, list) and len(inserted_ids) == 1:
            return {'status': states.SUCCESS, 'message': 'Quota initialized'}, 200

        return {'status': states.FAILED, 'message': 'Quota failed to initialize'}, 500

    def update_quota(self, units: int) -> Tuple[dict, int]:

        current_utilization = mongodata.fetch(
            match=self.tenant_query,
            collection=self.collection
        )

        new_utilization = current_utilization[0]
        new_utilization['monthly_quota_consumed'] += units
        _id = new_utilization.pop('_id')

        updated_docs = mongodata.update(
            schema=self.schema,
            match={'_id': _id},
            new_data=new_utilization,
            collection=self.collection,
            append=False
        )

        if updated_docs != 1:
            return {'status': states.FAILED, 'message': 'Quota update failed'}, 500

        return {'status': states.SUCCESS, 'message': 'Quota updated'}, 200

    @failsafe
    def reset_quota(self) -> list:
        quota_data = mongodata.fetch(self.user_query, self.collection)
        quota_reset_date = min(
            [dateparser.parse(quota['quota_reset_date'])
             for quota in quota_data]
        )
        current_date = datetime.datetime.utcnow()
        if quota_reset_date <= current_date:
            for quota in quota_data:
                quota['monthly_quota_consumed'] = 0
                quota['quota_reset_date'] = get_quota_reset_date(
                    current_date=quota_reset_date)
                quota.pop('_id')
                mongodata.update(
                    schema=self.schema,
                    match=self.user_query,
                    new_data=quota,
                    collection=self.collection,
                    append=False
                )
        return mongodata.fetch(self.user_query, self.collection)

    def check_quota(self, units: int = 0) -> Tuple[dict, int]:

        if self.plan_type == quota_plan.UNLIMITED:
            return {
                       'status': states.SUCCESS,
                       'message': 'Utilization within monthly quota'
                   }, 200

        quota_data = self.reset_quota()

        total_quota_consumed = sum(
            [quota['monthly_quota_consumed'] for quota in quota_data]
        )
        max_allowed_quota = max(
            [quota['monthly_quota'] for quota in quota_data]
        )
        quota_reset_date = min(
            [dateparser.parse(quota['quota_reset_date'])
             for quota in quota_data]
        )

        if total_quota_consumed + units <= max_allowed_quota:
            return {
                       'status': states.SUCCESS,
                       'message': 'Utilization within monthly quota',
                       'monthly_quota': max_allowed_quota,
                       'monthly_quota_consumed': total_quota_consumed,
                       'quota_reset_date': quota_reset_date.isoformat()
                   }, 200
        else:
            return {
                       'status': states.FAILED,
                       'message': 'Monthly quota exceeded',
                       'monthly_quota': max_allowed_quota,
                       'monthly_quota_consumed': total_quota_consumed,
                       'quota_reset_date': quota_reset_date.isoformat()
                   }, 402

Functions

def get_quota_reset_date(current_date: datetime.datetime = datetime.datetime(2022, 5, 10, 11, 48, 59, 389300))
Expand source code
def get_quota_reset_date(current_date: datetime.datetime = datetime.datetime.utcnow()):
    quota_reset_date = current_date + datetime.timedelta(days=30)
    return quota_reset_date.isoformat()

Classes

class Quota (tenant_id: str, auth_token: str, uploader_id: str, units: int, schema: marshmallow.schema.Schema = None, collection: str = None)
Expand source code
class Quota:

    def __init__(
            self,
            tenant_id: str,
            auth_token: str,
            uploader_id: str,
            units: int,
            schema: Schema = None,
            collection: str = None,
    ):

        self.units = units
        self.tenant_id = tenant_id if not envs.DESKTOP_ENVIRONMENT else envs.DESKTOP_TENANT_ID
        self.auth_token = auth_token
        self.uploader_id = uploader_id
        self.schema = schema or QuotaSchema
        self.collection = collection or envs.MONGO_COLLECTION_UTILIZATION_NAME

        if envs.DESKTOP_ENVIRONMENT:
            self.tenants = [envs.DESKTOP_TENANT_ID]
            self.plan_type = quota_plan.UNLIMITED
        else:
            self.tenants = get_tenants_list(self.tenant_id, self.auth_token)
            self.user_profile = get_user_profile(self.tenant_id, self.auth_token)
            self.plan_type = self.user_profile["plan_type"].upper()

        # This is used to calculate quota
        self.user_query = {
            'tenant_id': {"$in": self.tenants},
            'uploader_id': self.uploader_id
        }

        # This is used to update quota
        self.tenant_query = {
            'tenant_id': self.tenant_id,
            'uploader_id': self.uploader_id
        }

        # Making sure quota is initialized
        response, status_code = self.init_quota()
        if status_code != 200:
            # will be cached in the api make sure to add @failsafe(failcode=500) decorator
            raise Exception(response['message'])

    def get_monthly_quota(self):
        if self.plan_type == quota_plan.UNLIMITED:
            return sys.maxsize
        return self.units

    def init_quota(self) -> Tuple[dict, int]:

        results = mongodata.fetch(
            match=self.tenant_query,
            collection=self.collection
        )

        if results:
            return {'status': states.SUCCESS, 'message': 'Quota initialized'}, 200

        utilization_data = {
            "tenant_id": self.tenant_id,
            "uploader_id": self.uploader_id,
            "monthly_quota": self.get_monthly_quota(),
            "monthly_quota_consumed": 0,
            "quota_reset_date": get_quota_reset_date()
        }

        inserted_ids = mongodata.insert(
            schema=self.schema, data=utilization_data, collection=self.collection
        )

        if isinstance(inserted_ids, list) and len(inserted_ids) == 1:
            return {'status': states.SUCCESS, 'message': 'Quota initialized'}, 200

        return {'status': states.FAILED, 'message': 'Quota failed to initialize'}, 500

    def update_quota(self, units: int) -> Tuple[dict, int]:

        current_utilization = mongodata.fetch(
            match=self.tenant_query,
            collection=self.collection
        )

        new_utilization = current_utilization[0]
        new_utilization['monthly_quota_consumed'] += units
        _id = new_utilization.pop('_id')

        updated_docs = mongodata.update(
            schema=self.schema,
            match={'_id': _id},
            new_data=new_utilization,
            collection=self.collection,
            append=False
        )

        if updated_docs != 1:
            return {'status': states.FAILED, 'message': 'Quota update failed'}, 500

        return {'status': states.SUCCESS, 'message': 'Quota updated'}, 200

    @failsafe
    def reset_quota(self) -> list:
        quota_data = mongodata.fetch(self.user_query, self.collection)
        quota_reset_date = min(
            [dateparser.parse(quota['quota_reset_date'])
             for quota in quota_data]
        )
        current_date = datetime.datetime.utcnow()
        if quota_reset_date <= current_date:
            for quota in quota_data:
                quota['monthly_quota_consumed'] = 0
                quota['quota_reset_date'] = get_quota_reset_date(
                    current_date=quota_reset_date)
                quota.pop('_id')
                mongodata.update(
                    schema=self.schema,
                    match=self.user_query,
                    new_data=quota,
                    collection=self.collection,
                    append=False
                )
        return mongodata.fetch(self.user_query, self.collection)

    def check_quota(self, units: int = 0) -> Tuple[dict, int]:

        if self.plan_type == quota_plan.UNLIMITED:
            return {
                       'status': states.SUCCESS,
                       'message': 'Utilization within monthly quota'
                   }, 200

        quota_data = self.reset_quota()

        total_quota_consumed = sum(
            [quota['monthly_quota_consumed'] for quota in quota_data]
        )
        max_allowed_quota = max(
            [quota['monthly_quota'] for quota in quota_data]
        )
        quota_reset_date = min(
            [dateparser.parse(quota['quota_reset_date'])
             for quota in quota_data]
        )

        if total_quota_consumed + units <= max_allowed_quota:
            return {
                       'status': states.SUCCESS,
                       'message': 'Utilization within monthly quota',
                       'monthly_quota': max_allowed_quota,
                       'monthly_quota_consumed': total_quota_consumed,
                       'quota_reset_date': quota_reset_date.isoformat()
                   }, 200
        else:
            return {
                       'status': states.FAILED,
                       'message': 'Monthly quota exceeded',
                       'monthly_quota': max_allowed_quota,
                       'monthly_quota_consumed': total_quota_consumed,
                       'quota_reset_date': quota_reset_date.isoformat()
                   }, 402

Methods

def check_quota(self, units: int = 0) ‑> Tuple[dict, int]
Expand source code
def check_quota(self, units: int = 0) -> Tuple[dict, int]:

    if self.plan_type == quota_plan.UNLIMITED:
        return {
                   'status': states.SUCCESS,
                   'message': 'Utilization within monthly quota'
               }, 200

    quota_data = self.reset_quota()

    total_quota_consumed = sum(
        [quota['monthly_quota_consumed'] for quota in quota_data]
    )
    max_allowed_quota = max(
        [quota['monthly_quota'] for quota in quota_data]
    )
    quota_reset_date = min(
        [dateparser.parse(quota['quota_reset_date'])
         for quota in quota_data]
    )

    if total_quota_consumed + units <= max_allowed_quota:
        return {
                   'status': states.SUCCESS,
                   'message': 'Utilization within monthly quota',
                   'monthly_quota': max_allowed_quota,
                   'monthly_quota_consumed': total_quota_consumed,
                   'quota_reset_date': quota_reset_date.isoformat()
               }, 200
    else:
        return {
                   'status': states.FAILED,
                   'message': 'Monthly quota exceeded',
                   'monthly_quota': max_allowed_quota,
                   'monthly_quota_consumed': total_quota_consumed,
                   'quota_reset_date': quota_reset_date.isoformat()
               }, 402
def get_monthly_quota(self)
Expand source code
def get_monthly_quota(self):
    if self.plan_type == quota_plan.UNLIMITED:
        return sys.maxsize
    return self.units
def init_quota(self) ‑> Tuple[dict, int]
Expand source code
def init_quota(self) -> Tuple[dict, int]:

    results = mongodata.fetch(
        match=self.tenant_query,
        collection=self.collection
    )

    if results:
        return {'status': states.SUCCESS, 'message': 'Quota initialized'}, 200

    utilization_data = {
        "tenant_id": self.tenant_id,
        "uploader_id": self.uploader_id,
        "monthly_quota": self.get_monthly_quota(),
        "monthly_quota_consumed": 0,
        "quota_reset_date": get_quota_reset_date()
    }

    inserted_ids = mongodata.insert(
        schema=self.schema, data=utilization_data, collection=self.collection
    )

    if isinstance(inserted_ids, list) and len(inserted_ids) == 1:
        return {'status': states.SUCCESS, 'message': 'Quota initialized'}, 200

    return {'status': states.FAILED, 'message': 'Quota failed to initialize'}, 500
def reset_quota(self) ‑> list
Expand source code
@failsafe
def reset_quota(self) -> list:
    quota_data = mongodata.fetch(self.user_query, self.collection)
    quota_reset_date = min(
        [dateparser.parse(quota['quota_reset_date'])
         for quota in quota_data]
    )
    current_date = datetime.datetime.utcnow()
    if quota_reset_date <= current_date:
        for quota in quota_data:
            quota['monthly_quota_consumed'] = 0
            quota['quota_reset_date'] = get_quota_reset_date(
                current_date=quota_reset_date)
            quota.pop('_id')
            mongodata.update(
                schema=self.schema,
                match=self.user_query,
                new_data=quota,
                collection=self.collection,
                append=False
            )
    return mongodata.fetch(self.user_query, self.collection)
def update_quota(self, units: int) ‑> Tuple[dict, int]
Expand source code
def update_quota(self, units: int) -> Tuple[dict, int]:

    current_utilization = mongodata.fetch(
        match=self.tenant_query,
        collection=self.collection
    )

    new_utilization = current_utilization[0]
    new_utilization['monthly_quota_consumed'] += units
    _id = new_utilization.pop('_id')

    updated_docs = mongodata.update(
        schema=self.schema,
        match={'_id': _id},
        new_data=new_utilization,
        collection=self.collection,
        append=False
    )

    if updated_docs != 1:
        return {'status': states.FAILED, 'message': 'Quota update failed'}, 500

    return {'status': states.SUCCESS, 'message': 'Quota updated'}, 200
class quota_plan (UNLIMITED: str = 'UNLIMITED', FREE: str = 'FREE')

quota_plan(UNLIMITED: str = 'UNLIMITED', FREE: str = 'FREE')

Expand source code
class quota_plan:
    UNLIMITED: str = "UNLIMITED"
    FREE: str = "FREE"

Class variables

var FREE : str
var UNLIMITED : str