Module licenseware.report_builder.report_builder

Expand source code
from typing import List
from flask import Request
from licenseware.common.constants.envs import envs
from licenseware.registry_service import register_report
from licenseware.report_components.build_match_expression import condition_switcher
from licenseware.report_components import BaseReportComponent
from licenseware.report_snapshot import ReportSnapshot
from licenseware.utils.logger import log


class ReportBuilder:
    """
    
    :name - report name
    :report_id - report id (will be used to construct path/route)
    :description - report data description
    :report_components - instantiated class objects from report_components
    :registrable - If True report will be registered to registry service
    :report_path - the endpoint/route on which this report is found
    :preview_image - the image name from resources folder. If not provided it will look for an image with the name `report_id.png`
    :preview_image_dark - the dark theme image name from resources folder. If not provided it will look for an image with the name `report_id_dark.png`
    :connected_apps - related apps which are needed to build this report
    :flags - use flags dataclass from licenseware.commun.constants
    

    """

    def __init__(
            self,
            name: str,
            report_id: str,
            description: str,
            report_components: list,
            registrable: bool = True,
            report_path: str = None,
            preview_image: str = None,
            preview_image_dark: str = None,
            connected_apps: list = [],
            flags: list = [],
            filters: list = []

    ):

        if envs.DEPLOYMENT_SUFFIX is not None:
            name = name + envs.DEPLOYMENT_SUFFIX
            report_id = report_id + envs.DEPLOYMENT_SUFFIX

        self.report_id = report_id
        self.name = name
        self.description = description
        self.components: List[BaseReportComponent] = report_components
        self.report_path = report_path or '/' + report_id
        self.register_report_path = self.report_path + '/register'
        self.registrable = registrable
        self.connected_apps = connected_apps
        self.app_id = envs.APP_ID
        self.flags = flags
        self.url = envs.REPORT_URL + self.report_path
        self.preview_image_path = self.report_path + '/preview_image'
        self.preview_image_dark_path = self.report_path + '/preview_image_dark'
        self.preview_image_url = envs.REPORT_URL + self.preview_image_path
        self.preview_image_dark_url = envs.REPORT_URL + self.preview_image_dark_path
        self.preview_image = preview_image
        self.preview_image_dark = preview_image_dark

        # Needed to overwrite report_components and filters
        self.report_components = []
        self.filters = filters
        self.register_components()

        self.reportvars = vars(self)

    def return_json_payload(self):
        payload = {
            "app_id": self.app_id,
            "report_id": self.report_id,
            "name": self.name,
            "description": self.description,
            "flags": self.flags,
            "report_components": self.report_components,
            "filters": self.filters,
            "url": self.url,
            "preview_image_url": self.preview_image_url,
            "preview_image_dark_url": self.preview_image_dark_url,
            "connected_apps": self.connected_apps
        }
        return payload, 200

    def get_report_snapshot(self, flask_request: Request):

        rs = ReportSnapshot(self, flask_request)

        return rs.get_report_data()

    def register_report(self):
        return register_report(**self.reportvars)

    def register_components(self):

        for order, component in enumerate(self.components):
            for registered_component in self.report_components:
                if registered_component['component_id'] == component.component_id:
                    raise Exception(f"Component id '{component.component_id}' was already declared")

            metadata = component.get_registration_payload()

            metadata['order'] = metadata['order'] or order + 1
            metadata['url'] = self.url + metadata.pop('path')
            metadata['type'] = metadata.pop('component_type')

            # Gathering filters from all components may cause memory overload
            # Not sure if we need to extend raport filters with all component filters
            # If we do so then in the list there should be no duplicates
            # if metadata["filters"]:
            #     self.filters.extend(metadata["filters"])

            self.report_components.append(metadata)

    def register_filters(self, filters: list):
        self.filters.extend(filters)

    @classmethod  # same func as in base_report_component
    def build_filter(cls, column: str, allowed_filters: list, visible_name: str, validate: bool = True):
        """
            Will return a dictionary similar to the one bellow:
            
            {
                "column": "version.edition",
                "allowed_filters": [
                    "equals", "contains", "in_list"
                ],
                "visible_name": "Product Edition"
            }
            
            The dictionary build will be used to filter mongo 
            
        """

        if validate:

            if " " in column:
                raise ValueError("Parameter `column` can't contain spaces and must be all lowercase like `device_name`")

            for f in allowed_filters:
                if f not in condition_switcher.keys():
                    raise ValueError(f"Filter {f} not in {condition_switcher.keys()}")

        return dict(
            column=column,
            allowed_filters=allowed_filters,
            visible_name=visible_name
        )

Classes

class ReportBuilder (name: str, report_id: str, description: str, report_components: list, registrable: bool = True, report_path: str = None, preview_image: str = None, preview_image_dark: str = None, connected_apps: list = [], flags: list = [], filters: list = [])

:name - report name :report_id - report id (will be used to construct path/route) :description - report data description :report_components - instantiated class objects from report_components :registrable - If True report will be registered to registry service :report_path - the endpoint/route on which this report is found :preview_image - the image name from resources folder. If not provided it will look for an image with the name report_id.png :preview_image_dark - the dark theme image name from resources folder. If not provided it will look for an image with the name report_id_dark.png :connected_apps - related apps which are needed to build this report :flags - use flags dataclass from licenseware.commun.constants

Expand source code
class ReportBuilder:
    """
    
    :name - report name
    :report_id - report id (will be used to construct path/route)
    :description - report data description
    :report_components - instantiated class objects from report_components
    :registrable - If True report will be registered to registry service
    :report_path - the endpoint/route on which this report is found
    :preview_image - the image name from resources folder. If not provided it will look for an image with the name `report_id.png`
    :preview_image_dark - the dark theme image name from resources folder. If not provided it will look for an image with the name `report_id_dark.png`
    :connected_apps - related apps which are needed to build this report
    :flags - use flags dataclass from licenseware.commun.constants
    

    """

    def __init__(
            self,
            name: str,
            report_id: str,
            description: str,
            report_components: list,
            registrable: bool = True,
            report_path: str = None,
            preview_image: str = None,
            preview_image_dark: str = None,
            connected_apps: list = [],
            flags: list = [],
            filters: list = []

    ):

        if envs.DEPLOYMENT_SUFFIX is not None:
            name = name + envs.DEPLOYMENT_SUFFIX
            report_id = report_id + envs.DEPLOYMENT_SUFFIX

        self.report_id = report_id
        self.name = name
        self.description = description
        self.components: List[BaseReportComponent] = report_components
        self.report_path = report_path or '/' + report_id
        self.register_report_path = self.report_path + '/register'
        self.registrable = registrable
        self.connected_apps = connected_apps
        self.app_id = envs.APP_ID
        self.flags = flags
        self.url = envs.REPORT_URL + self.report_path
        self.preview_image_path = self.report_path + '/preview_image'
        self.preview_image_dark_path = self.report_path + '/preview_image_dark'
        self.preview_image_url = envs.REPORT_URL + self.preview_image_path
        self.preview_image_dark_url = envs.REPORT_URL + self.preview_image_dark_path
        self.preview_image = preview_image
        self.preview_image_dark = preview_image_dark

        # Needed to overwrite report_components and filters
        self.report_components = []
        self.filters = filters
        self.register_components()

        self.reportvars = vars(self)

    def return_json_payload(self):
        payload = {
            "app_id": self.app_id,
            "report_id": self.report_id,
            "name": self.name,
            "description": self.description,
            "flags": self.flags,
            "report_components": self.report_components,
            "filters": self.filters,
            "url": self.url,
            "preview_image_url": self.preview_image_url,
            "preview_image_dark_url": self.preview_image_dark_url,
            "connected_apps": self.connected_apps
        }
        return payload, 200

    def get_report_snapshot(self, flask_request: Request):

        rs = ReportSnapshot(self, flask_request)

        return rs.get_report_data()

    def register_report(self):
        return register_report(**self.reportvars)

    def register_components(self):

        for order, component in enumerate(self.components):
            for registered_component in self.report_components:
                if registered_component['component_id'] == component.component_id:
                    raise Exception(f"Component id '{component.component_id}' was already declared")

            metadata = component.get_registration_payload()

            metadata['order'] = metadata['order'] or order + 1
            metadata['url'] = self.url + metadata.pop('path')
            metadata['type'] = metadata.pop('component_type')

            # Gathering filters from all components may cause memory overload
            # Not sure if we need to extend raport filters with all component filters
            # If we do so then in the list there should be no duplicates
            # if metadata["filters"]:
            #     self.filters.extend(metadata["filters"])

            self.report_components.append(metadata)

    def register_filters(self, filters: list):
        self.filters.extend(filters)

    @classmethod  # same func as in base_report_component
    def build_filter(cls, column: str, allowed_filters: list, visible_name: str, validate: bool = True):
        """
            Will return a dictionary similar to the one bellow:
            
            {
                "column": "version.edition",
                "allowed_filters": [
                    "equals", "contains", "in_list"
                ],
                "visible_name": "Product Edition"
            }
            
            The dictionary build will be used to filter mongo 
            
        """

        if validate:

            if " " in column:
                raise ValueError("Parameter `column` can't contain spaces and must be all lowercase like `device_name`")

            for f in allowed_filters:
                if f not in condition_switcher.keys():
                    raise ValueError(f"Filter {f} not in {condition_switcher.keys()}")

        return dict(
            column=column,
            allowed_filters=allowed_filters,
            visible_name=visible_name
        )

Static methods

def build_filter(column: str, allowed_filters: list, visible_name: str, validate: bool = True)

Will return a dictionary similar to the one bellow:

{ "column": "version.edition", "allowed_filters": [ "equals", "contains", "in_list" ], "visible_name": "Product Edition" }

The dictionary build will be used to filter mongo

Expand source code
@classmethod  # same func as in base_report_component
def build_filter(cls, column: str, allowed_filters: list, visible_name: str, validate: bool = True):
    """
        Will return a dictionary similar to the one bellow:
        
        {
            "column": "version.edition",
            "allowed_filters": [
                "equals", "contains", "in_list"
            ],
            "visible_name": "Product Edition"
        }
        
        The dictionary build will be used to filter mongo 
        
    """

    if validate:

        if " " in column:
            raise ValueError("Parameter `column` can't contain spaces and must be all lowercase like `device_name`")

        for f in allowed_filters:
            if f not in condition_switcher.keys():
                raise ValueError(f"Filter {f} not in {condition_switcher.keys()}")

    return dict(
        column=column,
        allowed_filters=allowed_filters,
        visible_name=visible_name
    )

Methods

def get_report_snapshot(self, flask_request: flask.wrappers.Request)
Expand source code
def get_report_snapshot(self, flask_request: Request):

    rs = ReportSnapshot(self, flask_request)

    return rs.get_report_data()
def register_components(self)
Expand source code
def register_components(self):

    for order, component in enumerate(self.components):
        for registered_component in self.report_components:
            if registered_component['component_id'] == component.component_id:
                raise Exception(f"Component id '{component.component_id}' was already declared")

        metadata = component.get_registration_payload()

        metadata['order'] = metadata['order'] or order + 1
        metadata['url'] = self.url + metadata.pop('path')
        metadata['type'] = metadata.pop('component_type')

        # Gathering filters from all components may cause memory overload
        # Not sure if we need to extend raport filters with all component filters
        # If we do so then in the list there should be no duplicates
        # if metadata["filters"]:
        #     self.filters.extend(metadata["filters"])

        self.report_components.append(metadata)
def register_filters(self, filters: list)
Expand source code
def register_filters(self, filters: list):
    self.filters.extend(filters)
def register_report(self)
Expand source code
def register_report(self):
    return register_report(**self.reportvars)
def return_json_payload(self)
Expand source code
def return_json_payload(self):
    payload = {
        "app_id": self.app_id,
        "report_id": self.report_id,
        "name": self.name,
        "description": self.description,
        "flags": self.flags,
        "report_components": self.report_components,
        "filters": self.filters,
        "url": self.url,
        "preview_image_url": self.preview_image_url,
        "preview_image_dark_url": self.preview_image_dark_url,
        "connected_apps": self.connected_apps
    }
    return payload, 200