def __init__( self, *, host: str = BASE_URL, clientId: str = None, clientSecret: str = None, customerToken: str = None, flag: str = 'mgmt', ): self.host = host[:-1] if host.endswith('/') else host self.clientId = clientId self.clientSecret = clientSecret self.ssoCustomerToken = customerToken self.flag = flag self.session = requests.Session() if self.flag not in ('mgmt', 'sso'): raise e.KnowiException( f'invalid flag=`{flag}`. supported flag inputs are (`mgmt` or `sso`)' ) if self.flag == 'mgmt': if not all([clientId, clientSecret]): raise e.KnowiException( f'client id/secret needed to use management api with flag=`{flag}`' ) else: self.auth() if self.flag == 'sso' and not customerToken: raise e.KnowiException( f'sso customer token needed to use single sign on api with flag=`{flag}`' )
def _validateContentFilters(contentFilter: List[dict] = None): """ validate passed arguments in constructing a user or customer content filter :param contentFilter: parsing contentFilters as arrays of dict i.e. [{"fieldName": "Zip Code", "values": ["11787"], "operator": "="}] :return: """ OPERATOR_NAME = [ 'equals', 'not equals', 'greater than', 'greater than or equals', 'less than', 'less than or equals', 'contains', 'does not contain' ] OPERATOR_VALUE = ['=', '!=', '>', '>=', '<', '<=', 'like', 'not like'] CONTENT_FILTER_FIELDS = ['fieldName', 'values', 'operator'] if contentFilter and isinstance(contentFilter, list): for i in contentFilter: if all(elem in list(i) for elem in CONTENT_FILTER_FIELDS): filterValue = i['values'] if not isinstance(i['values'], list): i['values'] = [str(filterValue)] if i.get('operator') not in chain(OPERATOR_NAME, OPERATOR_VALUE): raise e.KnowiException( f"invalid `operator` value in contentFilter= `{i['operator']}` " ) else: raise e.KnowiException( f"missing/invalid contentFilter parameter. must have {CONTENT_FILTER_FIELDS}" ) return contentFilter
def api_call(self, apiMethod: str, httpVerb: str, *, files: dict = None, data: dict = None, params: dict = None, json: dict = None): """Create a request and execute the API call to Knowi. :param apiMethod: The target Knowi API method. :param httpVerb: HTTP Verb. e.g. 'GET' :param files: :param data: The body to attach to the request. If a dictionary is provided, form-encoding will take place. e.g. {'key1': 'value1', 'key2': 'value2'} :param params: The URL parameters to append to the URL. e.g. {'key1': 'value1', 'key2': 'value2'} :param json: JSON for the body to attach to the request (if files or data is not specified). e.g. {'key1': 'value1', 'key2': 'value2'} :return: """ if apiMethod.startswith("/sso/") and self.flag != "sso": raise e.KnowiException( f'invalid method=`{apiMethod}` with flag=`{self.flag}`, use flag `sso`' ) if not apiMethod.startswith('/sso') and self.flag == 'sso': raise e.KnowiException( f'invalid method=`{apiMethod}` with flag=`{self.flag}` use flag `mgmt`' ) apiUrl = self._get_url(apiMethod) if data: data = cleanNullTerms(data) elif json: json = cleanNullTerms(json) requestArgs = { "data": data, "files": files, "params": params, "json": json } return self._request(httpVerb=httpVerb, apiUrl=apiUrl, requestArgs=requestArgs)
def wrapper(*args, **kwargs): props = kwargs['queryProperty']['properties'] if props.get('categories'): if not isinstance(props['categories'], list): kwargs['queryProperty']['properties']['categories'] = [ props['categories'] ] if props.get("direct"): if not isinstance("direct", bool): raise e.KnowiException( f"invalid `direct` type, should be a bool: (`True`, `False`)" ) if props.get("jsonPayload") and props.get("urlParams"): raise e.KnowiException( f"invalid attributes. Can't use both `jsonPayload` and `urlParams`" ) return func(*args, **kwargs)
def wrapper(*args, **kwargs): if kwargs.get('shareProperty') or kwargs.get('userGroups'): shareProperties = kwargs.get('shareProperty') or kwargs.get( 'userGroups') for i in shareProperties: if 'type' not in i: raise e.KnowiException( 'missing attribute `type` in shareProperty') i['type'] = i['type'].capitalize() # sharing to users if i["type"] == 'Users': if not all(key in i for key in ['access_level', 'name']): raise e.KnowiException( f"invalid/missing user property key. must include: {SHARE_TO_USERS}" ) if i['access_level'] not in ACCESS_LEVEL: raise e.KnowiException( f'invalid/missing property. access_level must be 1 or 2' ) # sharing to group elif i['type'] == 'Groups': if not all(key in i for key in ['access_level', 'id']): raise e.KnowiException( f"invalid/missing group property. must include: {SHARE_TO_GROUPS}" ) if i['access_level'] not in ACCESS_LEVEL: raise ValueError( f'missing/invalid property. access_level must be 1 or 2' ) else: raise ValueError( f"Invalid share `type`. allowed values: (`users`, `groups`)" ) return func(*args, **kwargs)
def wrapper(*args, **kwargs): if 'datasource' not in kwargs: raise e.KnowiException('missing parameter "datasource"') if kwargs.get('datasource') not in SUPPORTED_DATASOURCES: raise e.KnowiException( f" invalid/unsupported datasource={kwargs['datasource']}") if kwargs.get('datasource') == 'restapi': if 'url' not in kwargs: raise e.KnowiException( f'Missing restapi host url={kwargs["url"]}') if kwargs['privateDatasource']: if not kwargs.get('privateConnector'): raise e.KnowiException( 'privateConnector is needed with a privateDatasource') if kwargs.get('tunnel'): if 'tunnelAddress' not in kwargs: raise e.KnowiException('tunnelAddress is needed with tunnel') return func(*args, **kwargs)
def wrapper(*args, **kwargs): if kwargs.get('timezone'): userTz = kwargs.get('timezone') if not isinstance(userTz, str): raise TypeError( f"Got {type(userTz)}, expected type is string, {userTz}") if userTz not in pytz.all_timezones: raise ValueError( f"Invalid timezone `{userTz}`! \n" f"For reference, see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones" ) if kwargs.get('twoFA'): twoFA = kwargs.get('twoFA') phone = kwargs.get('phone') if not isinstance(kwargs.get('twoFA'), bool): raise TypeError( f"`twoFA` type must be bool. Got {type(twoFA)}.") if not phone: raise ValueError( f"`phone` is needed with twoFactorAuth= {twoFA}") if kwargs.get('phone'): kwargs['phone'] = str(kwargs.get('phone')) if kwargs.get('userInviteJson'): userProps = kwargs.get('userInviteJson') addGroups = userProps.get('userGroups', []) for i in addGroups: if not all(s in ['access_level', 'id'] for s in list(i)): raise ValueError( f'missing/invalid userGroups property: {i}') if kwargs.get('contentFilters') or kwargs.get('contentFilter'): userFilter = kwargs.get('contentFilter') or kwargs.get( 'contentFilters') _validateContentFilters(userFilter) # editing existing user groups if kwargs.get('groups'): userGroups = kwargs.get("groups") if not isinstance(userGroups, List): raise TypeError(f"groups must be a array of dicts") for i in userGroups: if not all(key in i for key in ['access_level', 'id']): raise e.KnowiException( 'missing/invalid properties. Required keys are `access_level` `id`' ) if i['access_level'] not in ACCESS_LEVEL: raise e.KnowiException( f'access_level must be `1` or `2`, got {i["access_level"]}' ) if kwargs.get('autoShareTo'): autoShare = kwargs.get('autoShareTo') if isinstance(autoShare, dict): autoShare = [autoShare] else: raise TypeError('`autoShareTo` must be dict of array of dict ') for i in autoShare: if not all(key in i for key in ['id']): raise e.KnowiException('missing `id` field') return func(*args, **kwargs)