def tag_asset(tag_id, asset_id, asset_type, organization_id, commit=True): """ Tag the asset with the given asset_type ("device" or "gateway") and asset_id (device_id or gateway_id) with the tag with tag_id and organization_id. """ if not is_from_organization(tag_id, organization_id): raise Error.Forbidden("Trying to use a tag from other organization.") if is_tagged(tag_id, asset_id, asset_type): return if asset_type == "device": if not DeviceRepository.is_from_organization(asset_id, organization_id): raise Error.Forbidden( "Trying to tag a device from other organization") asset_tag = DeviceToTag(tag_id=tag_id, device_id=asset_id) db.session.add(asset_tag) elif asset_type == "gateway": if not GatewayRepository.is_from_organization(asset_id, organization_id): raise Error.Forbidden( "Trying to tag a gateway from other organization") asset_tag = GatewayToTag(tag_id=tag_id, gateway_id=asset_id) db.session.add(asset_tag) else: raise Error.BadRequest(f"Invalid asset_type: {asset_type}") if commit: db.session.commit()
def untag_asset(tag_id, asset_id, asset_type, organization_id, commit=True): """ Remove the tag with the tag_id and organization_id from the asset with the given asset_type ("device" or "gateway") and asset_id (device_id or gateway_id). """ if not is_from_organization(tag_id, organization_id): raise Error.Forbidden( "Trying to delete a tag from other organization.") if asset_type == "device": if not DeviceRepository.is_from_organization(asset_id, organization_id): raise Error.Forbidden( "Trying to untag a device from other organization") asset_tag = db.session.query(DeviceToTag).\ filter(DeviceToTag.tag_id==tag_id, DeviceToTag.device_id==asset_id).first() if asset_tag: db.session.delete(asset_tag) elif asset_type == "gateway": if not GatewayRepository.is_from_organization(asset_id, organization_id): raise Error.Forbidden( "Trying to untag a gateway from other organization") asset_tag = db.session.query(GatewayToTag).\ filter(GatewayToTag.tag_id==tag_id, GatewayToTag.gateway_id==asset_id).first() if asset_tag: db.session.delete(asset_tag) else: raise Error.BadRequest(f"Invalid asset_type: {asset_type}") if commit: db.session.commit()
def list_asset_tags(asset_id, asset_type, organization_id): if asset_type == "device": if not DeviceRepository.is_from_organization(asset_id, organization_id): raise Error.Forbidden( "Trying to list tags from a device from other organization") return db.session.query(Tag).\ join(DeviceToTag).\ filter(DeviceToTag.device_id == asset_id).all() elif asset_type == "gateway": if not GatewayRepository.is_from_organization(asset_id, organization_id): raise Error.Forbidden( "Trying to list tags from a gateway from other organization") return db.session.query(Tag).\ join(GatewayToTag).\ filter(GatewayToTag.gateway_id == asset_id).all() else: raise Error.BadRequest(f"Invalid asset_type: {asset_type}")
def handle_alert_events(ch, method, properties, body): event = None try: event = json.loads(body) except Exception: LOG.error("Couldn't deserialize event") if not event: return alert_id = event.get('alert_id') organization_id = event.get('organization_id') data_collector_id = event.get('data_collector_id') event_type = event.get('event_type') alert_type_code = event.get('alert_type') phones = [] emails = [] if event_type == 'NEW': alert_type = AlertType.find_one(alert_type_code) users = User.find_all_user_by_organization_id(organization_id) users = list( filter( lambda x: (x.blocked == False and x.deleted == False and x. active == True), users)) emit_alert_event({'alert_id': alert_id}, organization_id) try: alert = Alert.find_one(alert_id) device = None gateway = None if alert and alert.device_id: device = AssetRepository.get_with(alert.device_id, "device") if alert and alert.gateway_id: gateway = AssetRepository.get_with(alert.gateway_id, "gateway") except Exception as e: LOG.error( f"Error {e} on alert assets search {alert}. Ignoring device/gateway related preferences" ) device = None gateway = None for user in users: alert_settings = NotificationAlertSettings.find_one(user.id) dc_settings = NotificationDataCollectorSettings.find_one( user_id=user.id, data_collector_id=data_collector_id) preferences = NotificationPreferences.find_one(user.id) # Check whether the alert assets are important for the user or not try: asset_importance = NotificationAssetImportance.get_with( user.id) is_important_for_user = False if asset_importance and device is not None: is_important_for_user = getattr( asset_importance, device.importance.value.lower()) elif asset_importance: is_important_for_user = getattr( asset_importance, gateway.importance.value.lower()) except Exception as e: LOG.error( f"Error {e} on NotificationAssetImportance search for user {user.id}. Ignoring asset_importance preference" ) is_important_for_user = True # Check whether the alert assets contain all the tags in user notification preferences or not try: asset_tags = NotificationAssetTag.find_all_with( user_id=user.id) tag_id_list = [asset_tag.tag_id for asset_tag in asset_tags] if device: has_all_tags = DeviceRepository.has_all_tags( device.id, tag_id_list) elif gateway: has_all_tags = GatewayRepository.has_all_tags( gateway.id, tag_id_list) except Exception as e: LOG.error( f"Error {e} on handling NotificationAssetTag preferences for user {user.id}. Ignoring this preference" ) has_all_tags = True if alert_settings and getattr( alert_settings, alert_type.risk.lower() ) and is_important_for_user and has_all_tags and dc_settings and dc_settings.enabled: data = NotificationData.find_one(user.id) notification = Notification(type='NEW_ALERT', alert_id=alert_id, user_id=user.id, created_at=datetime.now()) notification.save() if data and data.ws_sid and preferences and preferences.push: emit_notification_event(notification.to_dict(), data.ws_sid) if preferences: if preferences.sms: if user.phone and not user.phone in phones: phones.append(user.phone) additional = NotificationAdditionalTelephoneNumber.find( user_id=user.id) for item in additional: if item.active and not item.phone in phones: phones.append(item.phone) if preferences.email: if user.email and not user.email in emails: emails.append(user.email) additional = NotificationAdditionalEmail.find( user_id=user.id) for item in additional: if item.active and not item.email in emails: emails.append(item.email) # Send a SMS message to the specified phone number for phone in phones: if config.SEND_SMS: sns.publish( PhoneNumber=phone, Message= f'New notification from {config.BRAND_NAME}. There\'s a new alert: {alert_type.name}. You can check this accessing to {config.BRAND_URL}', ) if len(emails) > 0: with app.app_context(): msg = MIMEMultipart('alternative') msg['Subject'] = f"New {config.BRAND_NAME} Notification" msg['From'] = email.utils.formataddr( (config.SMTP_SENDER_NAME, config.SMTP_SENDER)) part = MIMEText( render_template('notification.html', brand_name=config.BRAND_NAME, full_url=config.BRAND_URL, alert_type=alert_type.name), 'html') msg.attach(part) server = smtplib.SMTP(config.SMTP_HOST, config.SMTP_PORT) #server.set_debuglevel(1) server.ehlo() server.starttls() #stmplib docs recommend calling ehlo() before & after starttls() server.ehlo() server.login(config.SMTP_USERNAME, config.SMTP_PASSWORD) for email_user in emails: try: msg['To'] = email_user server.sendmail(config.SMTP_SENDER, email_user, msg.as_string()) except Exception as exc: server.close() print(exc) server.close()
def count_per_importance(organization_id, vendors=None, gateway_ids=None, data_collector_ids=None, tag_ids=None, asset_type=None, importances=None): """ Count the number of assets per importance. Parameters: - organization_id: which organization. - vendors[]: for filtering, lists only assets that have ANY one of these vendors. - gateway_ids[]: for filtering, list only the assets connected to ANY one of these gateways. - data_collector_ids[]: for filtering, list only the assest related to ANY of these data collectors. - tag_ids[]: for filtering, list only the assest that have ALL these tags. - asset_type: for filtering, list only this type of asset ("device" or "gateway"). - importances: for filtering, list only the assets that have ANY of these importances Returns: - A list of dicts, where each dict has three fields: id, name, count. """ # Build two queries, one for devices and one for gateways dev_query = db.session.query(Device.importance, func.count(distinct(Device.id))).\ join(GatewayToDevice).\ group_by(Device.importance).\ filter(Device.organization_id==organization_id).\ filter(Device.pending_first_connection==False) gtw_query = db.session.query(Gateway.importance, func.count(distinct(Gateway.id))).\ group_by(Gateway.importance).\ filter(Gateway.organization_id==organization_id) # If filter arguments were given, add the respective where clauses to the queries if None in vendors: dev_query = dev_query.filter( or_(Device.vendor.in_(vendors), Device.vendor.is_(None))) gtw_query = gtw_query.filter( or_(Gateway.vendor.in_(vendors), Gateway.vendor.is_(None))) elif vendors: dev_query = dev_query.filter(Device.vendor.in_(vendors)) gtw_query = gtw_query.filter(Gateway.vendor.in_(vendors)) if gateway_ids: dev_query = dev_query.filter( GatewayToDevice.gateway_id.in_(gateway_ids)) gtw_query = gtw_query.filter(Gateway.id.in_(gateway_ids)) if data_collector_ids: dev_query = dev_query.filter( Device.data_collector_id.in_(data_collector_ids)) gtw_query = gtw_query.filter( Gateway.data_collector_id.in_(data_collector_ids)) if tag_ids: dev_query = dev_query.filter( Device.id.in_(DeviceRepository.query_ids_with(tag_ids=tag_ids))) gtw_query = gtw_query.filter( Gateway.id.in_(GatewayRepository.query_ids_with(tag_ids=tag_ids))) if importances: dev_query = dev_query.filter(Device.importance.in_(importances)) gtw_query = gtw_query.filter(Gateway.importance.in_(importances)) # Execute the queries, filtering by asset type if asset_type is None: all_counts = dev_query.all() + gtw_query.all() elif asset_type == "device": all_counts = dev_query.all() elif asset_type == "gateway": all_counts = gtw_query.all() else: raise Error.BadRequest( f"Invalid asset_type: {asset_type}. Valid values are \'device\' or \'gateway\'" ) counts = defaultdict(lambda: {'name': None, 'count': 0}) for entry in all_counts: counts[entry[0].value]['name'] = entry[0].value counts[entry[0].value]['count'] += entry[1] return [{ 'id': k, 'name': v['name'], 'count': v['count'] } for k, v in counts.items()]
def count_per_tag(organization_id, vendors=None, gateway_ids=None, data_collector_ids=None, tag_ids=None, asset_type=None, importances=None): """ Count the number of assets per tag. Parameters: - organization_id: which organization. - vendors[]: for filtering, lists only assets that have ANY one of these vendors. - gateway_ids[]: for filtering, list only the assets connected to ANY one of these gateways. - data_collector_ids[]: for filtering, list only the assest related to ANY of these data collectors. - tag_ids[]: for filtering, list only the assest that have ALL these tags. - asset_type: for filtering, list only this type of asset ("device" or "gateway"). - importances: for filtering, list only the assets that have ANY of these importances Returns: - List of dicts, where each dict has the tag id and name and the count of assets. """ # Base queries, one for devices and one for gateways dev_query = db.session.query(Tag.id, Tag.name, Tag.color, func.count(distinct(Device.id))).\ select_from(Device).\ join(DeviceToTag).join(Tag).\ group_by(Tag.id, Tag.name, Tag.color).\ filter(Device.organization_id == organization_id).\ filter(Device.pending_first_connection==False) gtw_query = db.session.query(Tag.id, Tag.name, Tag.color, func.count(distinct(Gateway.id))).\ select_from(Gateway).\ join(GatewayToTag).join(Tag).\ group_by(Tag.id, Tag.name, Tag.color).\ filter(Gateway.organization_id==organization_id) # If filtering parameters are given, add the respective where clauses to the queries if None in vendors: dev_query = dev_query.filter( or_(Device.vendor.in_(vendors), Device.vendor.is_(None))) gtw_query = gtw_query.filter( or_(Gateway.vendor.in_(vendors), Gateway.vendor.is_(None))) elif vendors: dev_query = dev_query.filter(Device.vendor.in_(vendors)) gtw_query = gtw_query.filter(Gateway.vendor.in_(vendors)) if gateway_ids: dev_query = dev_query.join(GatewayToDevice, Device.id == GatewayToDevice.device_id)\ .filter(GatewayToDevice.gateway_id.in_(gateway_ids)) gtw_query = gtw_query.filter(Gateway.id.in_(gateway_ids)) if data_collector_ids: dev_query = dev_query.filter( Device.data_collector_id.in_(data_collector_ids)) gtw_query = gtw_query.filter( Gateway.data_collector_id.in_(data_collector_ids)) if tag_ids: dev_query = dev_query.filter( Device.id.in_(DeviceRepository.query_ids_with(tag_ids=tag_ids))) gtw_query = gtw_query.filter( Gateway.id.in_(GatewayRepository.query_ids_with(tag_ids=tag_ids))) if importances: dev_query = dev_query.filter(Device.importance.in_(importances)) gtw_query = gtw_query.filter(Gateway.importance.in_(importances)) # Execute the queries, filtering by asset type if asset_type is None: all_counts = dev_query.all() + gtw_query.all() elif asset_type == "device": all_counts = dev_query.all() elif asset_type == "gateway": all_counts = gtw_query.all() else: raise Exception("Invalid asset type parameter") # Join the results of the queries counts = defaultdict(lambda: {'name': None, 'color': None, 'count': 0}) for e in all_counts: counts[e[0]]['name'] = e[1] counts[e[0]]['color'] = e[2] counts[e[0]]['count'] += e[3] return counts
def count_per_gateway(organization_id, vendors=None, gateway_ids=None, data_collector_ids=None, tag_ids=None, asset_type=None, importances=None): """ Count the number of assets per gateway. Parameters: - organization_id: which organization. - vendors[]: for filtering, lists only assets that have ANY one of these vendors. - gateway_ids[]: for filtering, list only the assets connected to ANY one of these gateways. - data_collector_ids[]: for filtering, list only the assest related to ANY of these data collectors. - tag_ids[]: for filtering, list only the assest that have ALL these tags. - asset_type: for filtering, list only this type of asset ("device" or "gateway"). - importances: for filtering, list only the assets that have ANY of these importances Returns: - List of dicts, where each dict has the gateway id and name and the count of assets. """ # Query to count the number of devices per gateway dev_query = db.session.query(Gateway.id, Gateway.gw_hex_id, func.count(distinct(Device.id)).label("count")).\ select_from(Gateway).\ join(GatewayToDevice).\ join(Device).\ group_by(Gateway.id, Gateway.gw_hex_id).\ filter(Gateway.organization_id==organization_id).\ filter(Device.pending_first_connection==False) # The number of gateway grouped by gateway is simply 1 gtw_query = db.session.query(Gateway.id, Gateway.gw_hex_id, expression.literal_column("1").label("count")).\ filter(Gateway.organization_id==organization_id) # If the arguments are given, filter adding the respective where clause if None in vendors: dev_query = dev_query.filter( or_(Device.vendor.in_(vendors), Device.vendor.is_(None))) gtw_query = gtw_query.filter( or_(Gateway.vendor.in_(vendors), Gateway.vendor.is_(None))) elif vendors: dev_query = dev_query.filter(Device.vendor.in_(vendors)) gtw_query = gtw_query.filter(Gateway.vendor.in_(vendors)) if gateway_ids: dev_query = dev_query.filter(Gateway.id.in_(gateway_ids)) gtw_query = gtw_query.filter(Gateway.id.in_(gateway_ids)) if data_collector_ids: dev_query = dev_query.filter( Gateway.data_collector_id.in_(data_collector_ids)) gtw_query = gtw_query.filter( Gateway.data_collector_id.in_(data_collector_ids)) if tag_ids: dev_query = dev_query.filter( Device.id.in_(DeviceRepository.query_ids_with(tag_ids=tag_ids))) gtw_query = gtw_query.filter( Gateway.id.in_(GatewayRepository.query_ids_with(tag_ids=tag_ids))) if importances: dev_query = dev_query.filter(Device.importance.in_(importances)) gtw_query = gtw_query.filter(Gateway.importance.in_(importances)) # Execute the queries, filtering by asset type if asset_type is None: all_counts = dev_query.all() + gtw_query.all() elif asset_type == "device": all_counts = dev_query.all() elif asset_type == "gateway": all_counts = gtw_query.all() else: raise Error.BadRequest("Invalid device type parameter") counts = defaultdict(lambda: {'name': None, 'count': 0}) for e in all_counts: counts[e[0]]['name'] = e[1] counts[e[0]]['count'] += e[2] return [{ 'id': k, 'name': v['name'], 'count': v['count'] } for k, v in counts.items()]
def list_all(organization_id, page=None, size=None, vendors=None, gateway_ids=None, data_collector_ids=None, tag_ids=None, asset_type=None, importances=None): """ List assets of an organization. Parameters: - organization_id: which organization. - page: for pagination. - size: for pagination. - vendors[]: for filtering, lists only assets that have ANY one of these vendors. - gateway_ids[]: for filtering, list only the assets connected to ANY one of these gateways. - data_collector_ids[]: for filtering, list only the assest related to ANY of these data collectors. - tag_ids[]: for filtering, list only the assest that have ALL these tags. - asset_type: for filtering, list only this type of asset ("device" or "gateway"). - importances: for filtering, list only the assets that have ANY of these importances Returns: - A dict with the list of assets. """ # Build two queries, one for devices and one for gateways dev_query = db.session.query( distinct(Device.id).label('id'), Device.dev_eui.label('hex_id'), expression.literal_column('\'Device\'').label('type'), Device.join_eui.label('join_eui'), Device.name, cast(expression.null(), Float).label('location_latitude'), cast(expression.null(), Float).label('location_longitude'), Device.app_name, DataCollector.name.label('data_collector'), Device.vendor, Device.importance, Device.connected, Device.first_activity, Device.last_activity ).select_from(Device).\ join(DataCollector).\ join(GatewayToDevice).\ filter(Device.organization_id==organization_id).\ filter(Device.pending_first_connection==False) gtw_query = db.session.query( distinct(Gateway.id).label('id'), Gateway.gw_hex_id.label('hex_id'), expression.literal_column('\'Gateway\'').label('type'), expression.null().label('join_eui'), Gateway.name, Gateway.location_latitude, Gateway.location_longitude, expression.null().label('app_name'), DataCollector.name.label('data_collector'), Gateway.vendor, Gateway.importance, Gateway.connected, Gateway.first_activity, Gateway.last_activity ).select_from(Gateway).\ join(DataCollector).\ filter(Gateway.organization_id == organization_id) # If filter parameters were given, add the respective where clauses to the queries if None in vendors: dev_query = dev_query.filter( or_(Device.vendor.in_(vendors), Device.vendor.is_(None))) gtw_query = gtw_query.filter( or_(Gateway.vendor.in_(vendors), Gateway.vendor.is_(None))) elif vendors: dev_query = dev_query.filter(Device.vendor.in_(vendors)) gtw_query = gtw_query.filter(Gateway.vendor.in_(vendors)) if gateway_ids: dev_query = dev_query.filter( GatewayToDevice.gateway_id.in_(gateway_ids)) gtw_query = gtw_query.filter(Gateway.id.in_(gateway_ids)) if data_collector_ids: dev_query = dev_query.filter( Device.data_collector_id.in_(data_collector_ids)) gtw_query = gtw_query.filter( Gateway.data_collector_id.in_(data_collector_ids)) if tag_ids: dev_query = dev_query.filter( Device.id.in_(DeviceRepository.query_ids_with(tag_ids=tag_ids))) gtw_query = gtw_query.filter( Gateway.id.in_(GatewayRepository.query_ids_with(tag_ids=tag_ids))) if importances: dev_query = dev_query.filter(Device.importance.in_(importances)) gtw_query = gtw_query.filter(Gateway.importance.in_(importances)) # Filter by device type if the parameter was given, else, make a union with queries. if asset_type is None: asset_query = dev_query.union(gtw_query) elif asset_type == "device": asset_query = dev_query elif asset_type == "gateway": asset_query = gtw_query else: raise Error.BadRequest("Invalid device type parameter") asset_query = asset_query.order_by(text('type desc, id')) if page and size: return asset_query.paginate(page=page, per_page=size, error_out=False) else: return asset_query.all()
def search(organization_id, page=None, size=None, page_ids=None, size_ids=None, search_param="", asset_type=None, asset_status=None, data_collector_ids=None, gateway_ids=None, tag_ids=None, importances=None): """ Get assets and devices filtered by string search param that found in multiple fields of the asset. Also you can pass other params for filtering - keep this params for future filters features. Args: organization_id (integer): Filter by assets belongs to this organization id page (integer, optional): [description]. Defaults to 1. size (integer, optional): [description]. Defaults to 3. page_ids (integer, optional): [description]. Defaults to 1. size_ids (integer, optional): [description]. Defaults to 20. search_param (string, optional): A string used for find coincidence in vendor, hexid, datasource join eui and app name. Defaults to "". asset_type (string, optional): Filter assets for only show devices or gateways. Defaults to None. asset_status (string, optional): Filter assets by 'connected' or 'disconnected'. Defaults to None. data_collector_ids (integer, optional): Filter assets belongs to data collector ids. Defaults to None. gateway_ids (integer, optional): Filter devices connected to gateways ids or filter by specific gateway ids . Defaults to None. tag_ids (integer, optional): Filter assets that has this tags ids. Defaults to None. importances (string, optional): A string for filter by importance. Defaults to None. Returns: [dict]: return a dict with keys: "devices": a list of devices that coincide with the search criteria, "device_ids": a list of ids of devices that coincide with the search critera, "gateways": a list of gateways that coincide with the search criteria, "device_ids": a list of ids of gateways that coincide with the search critera, } """ # Build two queries, one for devices and one for gateways dev_query = db.session.query( distinct(Device.id).label('id'), Device.dev_eui.label('hex_id'), expression.literal_column('\'Device\'').label('type'), Device.join_eui.label('join_eui'), Device.name, cast(expression.null(), Float).label('location_latitude'), cast(expression.null(), Float).label('location_longitude'), Device.app_name, DataCollector.name.label('data_collector'), Device.vendor, #Device.importance, Device.connected, #Device.first_activity, #Device.last_activity ).select_from(Device).\ join(DataCollector).\ join(GatewayToDevice).\ filter(Device.organization_id==organization_id).\ filter(Device.pending_first_connection==False) dev_query_ids = db.session.query(distinct(Device.id).label('id')).select_from(Device).\ join(DataCollector).\ join(GatewayToDevice).\ filter(Device.organization_id==organization_id).\ filter(Device.pending_first_connection==False) gtw_query = db.session.query( distinct(Gateway.id).label('id'), Gateway.gw_hex_id.label('hex_id'), expression.literal_column('\'Gateway\'').label('type'), expression.null().label('join_eui'), Gateway.name, Gateway.location_latitude, Gateway.location_longitude, expression.null().label('app_name'), DataCollector.name.label('data_collector'), Gateway.vendor, #Gateway.importance, Gateway.connected, #Gateway.first_activity, #Gateway.last_activity ).select_from(Gateway).\ join(DataCollector).\ filter(Gateway.organization_id == organization_id) if gateway_ids: dev_query = dev_query.filter( GatewayToDevice.gateway_id.in_(gateway_ids)) gtw_query = gtw_query.filter(Gateway.id.in_(gateway_ids)) if data_collector_ids: dev_query = dev_query.filter( Device.data_collector_id.in_(data_collector_ids)) gtw_query = gtw_query.filter( Gateway.data_collector_id.in_(data_collector_ids)) if tag_ids: dev_query = dev_query.filter( Device.id.in_(DeviceRepository.query_ids_with(tag_ids=tag_ids))) gtw_query = gtw_query.filter( Gateway.id.in_(GatewayRepository.query_ids_with(tag_ids=tag_ids))) #if importances: # dev_query = dev_query.filter(Device.importance.in_(importances)) # gtw_query = gtw_query.filter(Gateway.importance.in_(importances)) # Filter by device type if the parameter was given, else, make a union with queries. # if asset_type is None: # asset_query = dev_query.union(gtw_query) # elif asset_type == "device": # asset_query = dev_query # elif asset_type == "gateway": # asset_query = gtw_query # else: # raise Error.BadRequest("Invalid device type parameter") if asset_status == 'connected': dev_query = dev_query.filter(Device.connected) gtw_query = gtw_query.filter(Gateway.connected) elif asset_status == 'disconnected': dev_query = dev_query.filter(not_(Device.connected)) gtw_query = gtw_query.filter(not_(Gateway.connected)) elif asset_status is not None: raise Error.BadRequest("Invalid asset status parameter") #asset_query = asset_query.order_by(text('type desc, id')) gtw_query_ids = db.session.query(distinct(Gateway.id).label('id')).select_from(Gateway).\ join(DataCollector).\ filter(Gateway.organization_id == organization_id) # If filter parameters were given, add the respective where clauses to the queries if search_param: search_param_device_condition = or_(\ Device.vendor.ilike(f'%{search_param}%'),\ Device.dev_eui.ilike(f'%{search_param}%'),\ Device.name.ilike(f'%{search_param}%'),\ Device.join_eui.ilike(f'%{search_param}%'),\ Device.app_name.ilike(f'%{search_param}%'),\ DataCollector.name.ilike(f'%{search_param}%') ) dev_query = dev_query.filter(search_param_device_condition) dev_query_ids = dev_query_ids.filter(search_param_device_condition) search_param_gateway_condition = or_( Gateway.vendor.ilike(f'%{search_param}%'),\ Gateway.gw_hex_id.ilike(f'%{search_param}%'),\ Gateway.name.ilike(f'%{search_param}%'),\ DataCollector.name.ilike(f'%{search_param}%') ) gtw_query = gtw_query.filter(search_param_gateway_condition) gtw_query_ids = gtw_query_ids.filter(search_param_gateway_condition) if page and size: return { "devices": dev_query.paginate(page=page, per_page=size, error_out=False), "device_ids": dev_query_ids.paginate(page=page_ids, per_page=size_ids, error_out=False), "gateways": gtw_query.paginate(page=page, per_page=size, error_out=False), "gateway_ids": gtw_query_ids.paginate(page=page_ids, per_page=size_ids, error_out=False), } else: return { "devices": [], "device_ids": [], "gateways": [], "gateways_ids": [] }