def var(var: str): try: if '.' in var: return _extract_attr(scope=Config.vars, attr_path=var) else: return Config.vars[var] except (KeyError, TypeError): raise InvalidVarException(var=var)
def l10n(*, locale: str, term: str): if locale not in Config.l10n.keys(): raise InvalidLocaleException(locale=locale) try: if '.' in term: return _extract_attr(scope=Config.l10n[locale], attr_path=term) else: return Config.l10n[locale][term] except (KeyError, TypeError): raise InvalidLocaleTermException(locale=locale, term=term)
class File(BaseModule): '''`File` module provides functionality for `File Upload Workflow`.''' collection = 'files' attrs = { 'user': ATTR.ID(desc='`_id` of `User` doc file belongs to.'), 'file': ATTR.FILE(desc='File object.'), 'create_time': ATTR.DATETIME( desc='Python `datetime` ISO format of the doc creation.' ), } methods = { 'read': METHOD(permissions=[PERM(privilege='__sys')]), 'create': METHOD( permissions=[PERM(privilege='create')], post_method=True, ), 'delete': METHOD(permissions=[PERM(privilege='__sys')]), } async def on_read(self, results, skip_events, env, query, doc, payload): for i in range(len(results['docs'])): results['docs'][i]['file']['lastModified'] = int( results['docs'][i]['file']['lastModified'] ) return (results, skip_events, env, query, doc, payload) async def pre_create(self, skip_events, env, query, doc, payload): if Config.file_upload_limit != -1 and len(doc['file']) > Config.file_upload_limit: raise self.exception( status=400, msg=f'File size is beyond allowed limit.', args={ 'code': 'INVALID_SIZE', 'attr': doc['__attr'].decode('utf-8'), 'name': doc['name'].decode('utf-8'), }, ) if (module := doc['__module'].decode('utf-8')) not in Config.modules.keys(): raise self.exception( status=400, msg=f'Invalid module \'{module}\'', args={'code': 'INVALID_MODULE'}, ) try: attr_type = _extract_attr( scope=Registry.module(module).attrs, attr_path='$__' + (attr := doc['__attr'].decode('utf-8')), )
async def _extend_doc( *, env: NAWAH_ENV, doc: NAWAH_DOC, attr: Optional[NAWAH_DOC], extn_id: ObjectId, extn: EXTN, extn_models: Dict[str, Optional[BaseModel]] = {}, ) -> Optional[BaseModel]: # [DOC] Check if extn module is dynamic value if extn.module.startswith('$__'): extn_module = Config.modules[_extract_attr(scope={ 'doc': doc, 'attr': attr }, attr_path=extn.module)] else: extn_module = Config.modules[extn.module] # [DOC] Check if extn attr set to fetch all or specific attrs if type(extn.attrs) == str and extn.attrs.startswith( '$__'): # type: ignore extn.attrs = cast(str, extn.attrs) extn_attrs = _extract_attr(scope={ 'doc': doc, 'attr': attr }, attr_path=extn.attrs) if extn_attrs[0] == '*': extn_attrs = { attr: extn_module.attrs[attr] for attr in extn_module.attrs.keys() } elif extn.attrs[0] == '*': extn_attrs = { attr: extn_module.attrs[attr] for attr in extn_module.attrs.keys() } else: extn_attrs = {attr: extn_module.attrs[attr] for attr in extn.attrs} # [DOC] Implicitly add _id key to extn attrs so that we don't delete it in process extn_attrs['_id'] = 'id' # [DOC] Set skip events skip_events = [Event.PERM] # [DOC] Check if extn instruction is explicitly requires second-dimension extn. if extn.force == False: skip_events.append(Event.EXTN) elif type(extn.force) == str and extn.force.startswith( '$__'): # type: ignore extn.force = cast(str, extn.force) if not _extract_attr(scope={ 'doc': doc, 'attr': attr }, attr_path=extn.force): skip_events.append(Event.EXTN) # [DOC] Read doc if not in extn_models if str(extn_id) not in extn_models.keys(): extn_results = await extn_module.methods['read']( skip_events=skip_events + (extn.skip_events or []), env=env, query=[{ '_id': extn_id }] + (extn.query or []), # type: ignore ) if extn_results['args']['count']: extn_models[str(extn_id)] = extn_results['args']['docs'][0] else: extn_models[str(extn_id)] = None # [DOC] Set attr to extn_models doc extn_doc = copy.deepcopy(extn_models[str(extn_id)]) # [DOC] delete all unneeded keys from the resulted doc if extn_doc: extn_doc = BaseModel({ attr: extn_doc[attr] for attr in extn_attrs.keys() if attr in extn_doc }) return extn_doc
def test_extract_attr_list_item(attr_obj): attr_val = _extract_attr(scope=attr_obj, attr_path='$__list_item1:1') assert attr_val == 'list_child2'
def test_extract_attr_nested_obj_dict_item(attr_obj): attr_val = _extract_attr(scope=attr_obj, attr_path='$__nested_obj.dict.list:0') assert attr_val == 'item1'
def test_extract_attr_nested_obj_list_item(attr_obj): attr_val = _extract_attr(scope=attr_obj, attr_path='nested_obj.list:1.item2') assert attr_val == 'val2'
def test_extract_attr_item(attr_obj): attr_val = _extract_attr(scope=attr_obj, attr_path='item2') assert attr_val == 'val2'
def test_extract_attr_nested_list_item(attr_obj): attr_val = _extract_attr(scope=attr_obj, attr_path='nested_list:1:0') assert attr_val == 'child_child_item21'
def test_extract_attr_nested_dict_item(attr_obj): attr_val = _extract_attr( scope=attr_obj, attr_path='$__nested_dict.child_dict.child_child_item1') assert attr_val == 'child_child_val1'
def test_extract_attr_dict_item(attr_obj): attr_val = _extract_attr(scope=attr_obj, attr_path='dict_item1.dict_child2') assert attr_val == 'child_val2'
async def _parse_permission_args( skip_events: List[Event], env: NAWAH_ENV, query: Union[NAWAH_QUERY, Query], doc: NAWAH_DOC, permission_args: Any, ): user = env['session'].user args_iter: Iterable if type(permission_args) == list: args_iter = range(len(permission_args)) elif type(permission_args) == dict: args_iter = list(permission_args.keys()) for j in args_iter: if type(permission_args[j]) == ATTR: try: permission_args[j] = await validate_attr( mode='create', attr_name=j, attr_type=permission_args[j], attr_val=doc[j], skip_events=[], env=env, query=query, doc=doc, scope=doc, ) except InvalidAttrException as e: raise e except: # [DOC] There is a chance doc[j] is invalid, so try to get the type in try..except try: raise InvalidAttrException( attr_name=j, attr_type=permission_args[j], val_type=type(doc[j]), ) except: raise InvalidAttrException( attr_name=j, attr_type=permission_args[j], val_type=None, ) elif type(permission_args[j]) == dict: # [DOC] Check opers for oper in [ '$gt', '$lt', '$gte', '$lte', '$bet', '$ne', '$regex', '$all', '$in', '$nin', ]: if oper in permission_args[j].keys(): if oper == '$bet': permission_args[j][ '$bet'] = await _parse_permission_args( skip_events=skip_events, env=env, query=query, doc=doc, permission_args=permission_args[j]['$bet'], ) else: permission_args[j][ oper] = await _parse_permission_args( skip_events=skip_events, env=env, query=query, doc=doc, permission_args={ oper: permission_args[j][oper] }, ) permission_args[j][oper] = permission_args[j][oper][ oper] # [DOC] Continue the iteration continue # [DOC] Child args, parse permission_args[j] = await _parse_permission_args( skip_events=skip_events, env=env, query=query, doc=doc, permission_args=permission_args[j], ) elif type(permission_args[j]) == list: permission_args[j] = await _parse_permission_args( skip_events=skip_events, env=env, query=query, doc=doc, permission_args=permission_args[j], ) elif type(permission_args[j]) == str: # [DOC] Check for variables if permission_args[j] == '$__user': permission_args[j] = user._id elif permission_args[j].startswith('$__user.'): try: permission_args[j] = _extract_attr( scope=user, attr_path=permission_args[j].replace( '$__user.', '$__'), ) except Exception as e: # [TODO] Log exception # [DOC] For values that are expected to have a list value, return empty list if type(permission_args) == dict and j in ['$in', '$nin']: permission_args[j] = [None] else: permission_args[j] = None elif permission_args[j] == '$__access': permission_args[j] = { '$__user': user._id, '$__groups': user.groups } elif permission_args[j] == '$__datetime': permission_args[j] = datetime.datetime.utcnow().isoformat() elif permission_args[j] == '$__date': permission_args[j] = datetime.date.today().isoformat() elif permission_args[j] == '$__time': permission_args[j] = datetime.datetime.now().time().isoformat() return permission_args