def get_by_template(req, template_id): """ Return a list of devices that have a particular template associated to it :param req: The received HTTP request, as created by Flask. :param template_id: The template to be considered :raises HTTPRequestError: If no authorization token was provided (no tenant was informed) :raises HTTPRequestError: If this device or template could not be found in database. :return A list of devices that are associated to the selected template. :rtype JSON """ tenant = init_tenant_context(req, db) page_number, per_page = get_pagination(req) page = (db.session.query(Device).join(DeviceTemplateMap).filter_by( template_id=template_id).paginate(page=page_number, per_page=per_page, error_out=False)) devices = [] for d in page.items: devices.append(serialize_full_device(d, tenant)) result = { 'pagination': { 'page': page.page, 'total': page.pages, 'has_next': page.has_next, 'next_page': page.next_num }, 'devices': devices } return result
def flask_get_templates(): try: # retrieve the authorization token token = retrieve_auth_token(request) # retrieve pagination page_number, per_page = get_pagination(request) params = { 'page_number': page_number, 'per_page': per_page, 'sortBy': request.args.get('sortBy', None), 'attr': request.args.getlist('attr'), 'attr_type': request.args.getlist('attr_type'), 'label': request.args.get('label', None), 'attrs_format': request.args.get('attr_format', 'both') } result = TemplateHandler.get_templates(params, token) for templates in result.get('templates'): LOGGER.info(f" Getting template with id {templates.get('id')}") return make_response(jsonify(result), 200) except ValidationError as e: results = {'message': 'failed to parse attr', 'errors': e} LOGGER.error(f" {e}") return make_response(jsonify(results), 500) except HTTPRequestError as e: LOGGER.error(f" {e}") if isinstance(e.message, dict): return make_response(jsonify(e.message), e.error_code) return format_response(e.error_code, e.message)
def get_templates(req): """ Fetches known templates, potentially limited by a given value. Ordering might be user-configurable too. :param req: The received HTTP request, as created by Flask. :return A JSON containing pagination information and the template list :rtype JSON :raises HTTPRequestError: If no authorization token was provided (no tenant was informed) """ init_tenant_context(req, db) page_number, per_page = get_pagination(req) pagination = {'page': page_number, 'per_page': per_page, 'error_out': False} parsed_query = [] query = req.args.getlist('attr') for attr in query: parsed = re.search('^(.+){1}=(.+){1}$', attr) parsed_query.append(text("attrs.label = '{}'".format(parsed.group(1)))) parsed_query.append(text("attrs.static_value = '{}'".format(parsed.group(2)))) target_label = req.args.get('label', None) if target_label: parsed_query.append(text("templates.label like '%{}%'".format(target_label))) SORT_CRITERION = { 'label': DeviceTemplate.label, None: DeviceTemplate.id } sortBy = SORT_CRITERION.get(req.args.get('sortBy', None), DeviceTemplate.id) if parsed_query: LOGGER.debug(f" Filtering template by {parsed_query}") page = db.session.query(DeviceTemplate) \ .join(DeviceAttr, isouter=True) \ .filter(*parsed_query) \ .order_by(sortBy) \ .paginate(**pagination) else: LOGGER.debug(f" Querying templates sorted by {sortBy}") page = db.session.query(DeviceTemplate).order_by(sortBy).paginate(**pagination) templates = [] for template in page.items: templates.append(attr_format(req, template_schema.dump(template))) result = { 'pagination': { 'page': page.page, 'total': page.pages, 'has_next': page.has_next, 'next_page': page.next_num }, 'templates': templates } return result
def test_get_pagination(self): args = {'page_size': 10,'page_num': 1} req = {'headers': {'authorization': generate_token()},'args': args,'body': ''} page, per_page = get_pagination(Request(req)) self.assertEqual(page, 1) self.assertEqual(per_page, 10) with self.assertRaises(HTTPRequestError): args = {'page_size': 10,'page_num': 0} req = {'headers': {'authorization': generate_token()},'args': args,'body': ''} page, per_page = get_pagination(Request(req)) with self.assertRaises(HTTPRequestError): args = {'page_size': 0,'page_num': 2} req = {'headers': {'authorization': generate_token()},'args': args,'body': ''} page, per_page = get_pagination(Request(req))
def flask_get_by_template(template_id): try: # retrieve the authorization token token = retrieve_auth_token(request) # retrieve pagination page_number, per_page = get_pagination(request) params = { 'page_number': page_number, 'per_page': per_page, } LOGGER.info(f' Getting devices with template id {template_id}.') result = DeviceHandler.get_by_template(token, params, template_id) return make_response(jsonify(result), 200) except HTTPRequestError as e: LOGGER.error(f' {e.message} - {e.error_code}.') if isinstance(e.message, dict): return make_response(jsonify(e.message), e.error_code) return format_response(e.error_code, e.message)
def flask_get_devices(): """ Fetches known devices, potentially limited by a given value. Ordering might be user-configurable too. Check API description for more information about request parameters and headers. """ try: # retrieve the authorization token token = retrieve_auth_token(request) # retrieve pagination page_number, per_page = get_pagination(request) params = { 'page_number': page_number, 'per_page': per_page, 'sortBy': request.args.get('sortBy', None), 'attr': request.args.getlist('attr'), 'attr_type': request.args.getlist('attr_type'), 'label': request.args.get('label', None), 'template': request.args.get('template', None), 'idsOnly': request.args.get('idsOnly', 'false'), } result = DeviceHandler.get_devices(token, params) LOGGER.info(f' Getting latest added device(s).') return make_response(jsonify(result), 200) except HTTPRequestError as e: LOGGER.error(f' {e.message} - {e.error_code}.') if isinstance(e.message, dict): return make_response(jsonify(e.message), e.error_code) return format_response(e.error_code, e.message)
def get_templates(req): """ Fetches known templates, potentially limited by a given value. Ordering might be user-configurable too. :param req: The received HTTP request, as created by Flask. :return A JSON containing pagination information and the template list :rtype JSON :raises HTTPRequestError: If no authorization token was provided (no tenant was informed) """ LOGGER.debug(f"Retrieving templates.") LOGGER.debug(f"Initializing tenant context...") init_tenant_context(req, db) LOGGER.debug(f"... tenant context initialized.") page_number, per_page = get_pagination(req) pagination = { 'page': page_number, 'per_page': per_page, 'error_out': False } LOGGER.debug(f"Pagination configuration is {pagination}") parsed_query = [] query = req.args.getlist('attr') for attr in query: LOGGER.debug(f"Analyzing query parameter: {attr}...") parsed = re.search('^(.+){1}=(.+){1}$', attr) parsed_query.append(DeviceAttr.label == parsed.group(1)) parsed_query.append(DeviceAttr.static_value == parsed.group(2)) LOGGER.debug("... query parameter was added to filter list.") query = req.args.getlist('attr_type') for attr_type_item in query: parsed_query.append(DeviceAttr.value_type == attr_type_item) target_label = req.args.get('label', None) if target_label: LOGGER.debug(f"Adding label filter to query...") parsed_query.append( DeviceTemplate.label.like("%{}%".format(target_label))) LOGGER.debug(f"... filter was added to query.") SORT_CRITERION = {'label': DeviceTemplate.label, None: None} sortBy = SORT_CRITERION.get(req.args.get('sortBy', None), None) LOGGER.debug(f"Sortby filter is {sortBy}") if parsed_query: LOGGER.debug(f" Filtering template by {parsed_query}") # Always sort by DeviceTemplate.id page = db.session.query(DeviceTemplate) \ .join(DeviceAttr, isouter=True) \ .filter(*parsed_query) \ .order_by(DeviceTemplate.id) if sortBy: page = page.order_by(sortBy) page = page.distinct(DeviceTemplate.id) LOGGER.debug(f"Current query: {type(page)}") page = paginate(page, **pagination) else: LOGGER.debug(f" Querying templates sorted by {sortBy}") page = db.session.query(DeviceTemplate).order_by(sortBy).paginate( **pagination) templates = [] for template in page.items: formatted_template = attr_format(req, template_schema.dump(template)) LOGGER.debug(f"Adding resulting template to response...") LOGGER.debug(f"Template is: {formatted_template['label']}") templates.append(formatted_template) LOGGER.debug(f"... template was added to response.") result = { 'pagination': { 'page': page.page, 'total': page.pages, 'has_next': page.has_next, 'next_page': page.next_num }, 'templates': templates } LOGGER.debug(f"Full response is {result}") return result
def get_devices(req, sensitive_data=False): """ Fetches known devices, potentially limited by a given value. Ordering might be user-configurable too. :param req: The received HTTP request, as created by Flask. :param sensitive_data: Informs if sensitive data like keys should be returned :return A JSON containing pagination information and the device list :rtype JSON :raises HTTPRequestError: If no authorization token was provided (no tenant was informed) """ if req.args.get('idsOnly', 'false').lower() in ['true', '1', '']: return DeviceHandler.list_ids(req) tenant = init_tenant_context(req, db) page_number, per_page = get_pagination(req) pagination = {'page': page_number, 'per_page': per_page, 'error_out': False} SORT_CRITERION = { 'label': Device.label, None: Device.id } sortBy = SORT_CRITERION.get(req.args.get('sortBy', None), Device.id) attr_filter = [] query = req.args.getlist('attr') for attr in query: parsed = re.search('^(.+){1}=(.+){1}$', attr) attr = [] attr.append("attrs.label = '{}'".format(parsed.group(1))) # static value must be the override, if any attr.append("coalesce(overrides.static_value, attrs.static_value) = '{}'".format(parsed.group(2))) attr_filter.append(and_(*attr)) label_filter = [] target_label = req.args.get('label', None) if target_label: label_filter.append("devices.label like '%{}%'".format(target_label)) template_filter = [] target_template = req.args.get('template', None) if target_template: template_filter.append("device_template.template_id = {}".format(target_template)) if template_filter or label_filter or attr_filter: # find all devices that contain matching attributes (may contain devices that # do not match all required attributes) subquery = db.session.query(func.count(Device.id).label('count'), Device.id) \ .join(DeviceTemplateMap, isouter=True) \ .join(DeviceTemplate) \ .join(DeviceAttr, isouter=True) \ .join(DeviceOverride, (Device.id == DeviceOverride.did) & (DeviceAttr.id == DeviceOverride.aid), isouter=True) \ .filter(or_(*attr_filter)) \ .filter(*label_filter) \ .filter(*template_filter) \ .group_by(Device.id) \ .subquery() # devices must match all supplied filters if (len(attr_filter)): LOGGER.debug(f" Filtering devices by {attr_filter}") page = db.session.query(Device) \ .join(DeviceTemplateMap) \ .join(subquery, subquery.c.id == Device.id) \ .filter(subquery.c.count == len(attr_filter)) \ .filter(*label_filter) \ .filter(*template_filter) \ .order_by(sortBy) \ .paginate(**pagination) else: # only filter by label LOGGER.debug(f" Filtering devices by label") page = db.session.query(Device) \ .join(DeviceTemplateMap) \ .join(subquery, subquery.c.id == Device.id) \ .filter(*label_filter) \ .filter(*template_filter) \ .order_by(sortBy) \ .paginate(**pagination) else: LOGGER.debug(f" Querying devices sorted by {sortBy}") page = db.session.query(Device).order_by(sortBy).paginate(**pagination) status_info = StatusMonitor.get_status(tenant) devices = [] for d in page.items: devices.append(serialize_full_device(d, tenant, sensitive_data, status_info)) result = { 'pagination': { 'page': page.page, 'total': page.pages, 'has_next': page.has_next, 'next_page': page.next_num }, 'devices': devices } return result
def get_devices(req, sensitive_data=False): """ Fetches known devices, potentially limited by a given value. Ordering might be user-configurable too. :param req: The received HTTP request, as created by Flask. :param sensitive_data: Informs if sensitive data like keys should be returned :return A JSON containing pagination information and the device list :rtype JSON :raises HTTPRequestError: If no authorization token was provided (no tenant was informed) """ tenant = init_tenant_context(req, db) page_number, per_page = get_pagination(req) pagination = { 'page': page_number, 'per_page': per_page, 'error_out': False } SORT_CRITERION = {'label': Device.label, None: Device.id} sortBy = SORT_CRITERION.get(req.args.get('sortBy', None)) attr_filter = [] query = req.args.getlist('attr') for attr_label_item in query: parsed = re.search('^(.+){1}=(.+){1}$', attr_label_item) attr_label = [] attr_label.append(DeviceAttr.label == parsed.group(1)) # static value must be the override, if any attr_label.append( text( "coalesce(overrides.static_value, attrs.static_value)=:static_value " ).bindparams(static_value=parsed.group(2))) attr_filter.append(and_(*attr_label)) query = req.args.getlist('attr_type') for attr_type_item in query: attr_filter.append(DeviceAttr.value_type == attr_type_item) label_filter = [] target_label = req.args.get('label', None) if target_label: label_filter.append(Device.label.like("%{}%".format(target_label))) template_filter = [] target_template = req.args.get('template', None) if target_template: template_filter.append( DeviceTemplateMap.template_id == target_template) if (attr_filter): #filter by attr LOGGER.debug(f" Filtering devices by {attr_filter}") page = db.session.query(Device) \ .join(DeviceTemplateMap, isouter=True) page = page.join(DeviceTemplate) \ .join(DeviceAttr, isouter=True) \ .join(DeviceOverride, (Device.id == DeviceOverride.did) & (DeviceAttr.id == DeviceOverride.aid), isouter=True) page = page.filter(*label_filter) \ .filter(*template_filter) \ .filter(*attr_filter) \ .order_by(sortBy) \ .paginate(**pagination) elif label_filter or template_filter: # only filter by label or/and template if label_filter: LOGGER.debug(f"Filtering devices by label: {target_label}") if template_filter: LOGGER.debug( f"Filtering devices with template: {target_template}") page = db.session.query(Device) \ .join(DeviceTemplateMap, isouter=True) if sensitive_data: #aditional joins for sensitive data page = page.join(DeviceTemplate) \ .join(DeviceAttr, isouter=True) \ .join(DeviceOverride, (Device.id == DeviceOverride.did) & (DeviceAttr.id == DeviceOverride.aid), isouter=True) page = page.filter(*label_filter) \ .filter(*template_filter) \ .order_by(sortBy) \ .paginate(**pagination) else: LOGGER.debug(f" Querying devices sorted by device id") page = db.session.query(Device).order_by(sortBy).paginate( **pagination) devices = [] if req.args.get('idsOnly', 'false').lower() in ['true', '1', '']: return DeviceHandler.get_only_ids(page) for d in page.items: devices.append(serialize_full_device(d, tenant, sensitive_data)) result = { 'pagination': { 'page': page.page, 'total': page.pages, 'has_next': page.has_next, 'next_page': page.next_num }, 'devices': devices } return result