diff --git a/glpi/glpi.py b/glpi/glpi.py index 9e67b45..190bbdb 100644 --- a/glpi/glpi.py +++ b/glpi/glpi.py @@ -397,7 +397,7 @@ def search_options(self, item_name): return response.json() - def search_engine(self, search_query): + def search_engine(self, search_query, params): """ Search an item by URI. Use GLPI search engine passing parameter by URI. @@ -405,7 +405,7 @@ def search_engine(self, search_query): operations. """ new_uri = "%s/%s" % (self.uri, search_query) - response = self.request('GET', new_uri, accept_json=True) + response = self.request('GET', new_uri, params=params, accept_json=True) return response.json() @@ -672,7 +672,7 @@ def search(self, item_name, criteria): else: return {"message_error": "Unable to find a valid criteria."} - def search_engine(self, item_name, criteria): + def search_engine(self, item_name, params): """ Call GLPI's search engine syntax. @@ -690,6 +690,17 @@ def search_engine(self, item_name, criteria): GLPIs APIRest JSON formated with result of search in key 'data'. """ + def field_to_int(field, field_map): + # if int given, use it directly + if isinstance(field, int) or field.isdigit(): + return int(field) + # if name given, try to map to an int + elif field in field_map: + return field_map[field] + else: + raise GlpiInvalidArgument( + 'Cannot map field name "' + field + '" to a field id.') + # Receive the possible field ids for type item_name # -> to avoid wrong lookups, use uid of fields, but strip item type: # example: {"1": {"uid": "Computer.name"}} gets {"name": 1} @@ -702,64 +713,64 @@ def search_engine(self, item_name, criteria): flags=re.IGNORECASE) field_map[field_name] = int(field_id) - uri_query = "%s?" % item_name - - for idx, c in enumerate(criteria['criteria']): - # build field argument - if idx == 0: - uri = "" - else: - uri = "&" - if 'field' in c and c['field'] is not None: - field_name = "" - # if int given, use it directly - if isinstance(c['field'], int) or c['field'].isdigit(): - field_name = int(c['field']) - # if name given, try to map to an int - elif c['field'] in field_map: - field_name = field_map[c['field']] + def build_params_from_criteria(criteria, prefix): + for idx, c in enumerate(criteria): + if 'criteria' in c: + for param in build_params_from_criteria( + c['criteria'], + '%s[%d][criteria]' % (prefix, idx), + ): + yield param + elif 'field' in c and c['field'] is not None: + yield ( + "%s[%d][field]" % (prefix, idx), + field_to_int(c['field'], field_map), + ) else: raise GlpiInvalidArgument( - 'Cannot map field name "' + c['field'] + '" to ' + - 'a field id for '+str(idx+1)+'. criterion '+str(c)) - uri = uri + "criteria[%d][field]=%d" % (idx, field_name) - else: - raise GlpiInvalidArgument( - 'Missing "field" parameter for ' + str(idx+1) + - 'the criteria: ' + str(c)) + 'Missing "field" parameter for ' + str(idx+1) + + 'the criteria: ' + str(c)) + + # build value argument + yield ( + "%s[%d][value]" % (prefix, idx), + c.get('value', ''), + ) + + # build searchtype argument + # -> optional! defaults to "contains" on the server if empty + yield ( + "%s[%d][searchtype]" % (prefix, idx), + c.get('searchtype', ''), + ) + + if 'link' in c: + yield ( + "%s[%d][link]" % (prefix, idx), + c['link'], + ) + elif idx > 0: + # link is optional for 1st criterion according to docs... + # -> error if not present but more than one criterion + raise GlpiInvalidArgument( + 'Missing link type for '+str(idx+1)+'. criterion '+str(c)) - # build value argument - if 'value' not in c or c['value'] is None: - uri = uri + "&criteria[%d][value]=" % (idx) - else: - uri = uri + "&criteria[%d][value]=%s" % (idx, c['value']) + params.update(build_params_from_criteria(params['criteria'], 'criteria')) - # build searchtype argument - # -> optional! defaults to "contains" on the server if empty - if 'searchtype' in c and c['searchtype'] is not None: - uri = (uri + "&criteria[%d][searchtype]=%s".format(idx, - c['searchtype'])) - else: - uri = uri + "&criteria[%d][searchtype]=" % (idx) + del params['criteria'] - # link is optional for 1st criterion according to docs... - # -> error if not present but more than one criterion - if 'link' not in c and idx > 0: - raise GlpiInvalidArgument( - 'Missing link type for '+str(idx+1)+'. criterion '+str(c)) - elif 'link' in c: - uri = uri + "&criteria[%d][link]=%s" % (idx, c['link']) + if 'forcedisplay' in params: + for idx, field in enumerate(params['forcedisplay']): + params['forcedisplay[%d]' % idx] = field_to_int(field, field_map) - # add this criterion to the query - uri_query = uri_query + uri + del params['forcedisplay'] try: if not self.api_has_session(): self.init_api() self.update_uri('search') - # TODO: is this call correct? shouldn't this be search_engine()? - return self.api_rest.search_options(uri_query) + return self.api_rest.search_engine(item_name, params) except GlpiException as e: return {'{}'.format(e)}