diff --git a/crc/api.yml b/crc/api.yml index 0bf8bd6f..213e8d15 100644 --- a/crc/api.yml +++ b/crc/api.yml @@ -703,18 +703,18 @@ paths: description: The string to search for in the Value column of the lookup table. schema: type: string + - name: value + in: query + required: false + description: An alternative to query, this accepts the specific value or id selected in a dropdown list or auto-complete, and will return the one matching record. Useful for getting additional details about an item selected in a dropdown. + schema: + type: string - name: limit in: query required: false description: The total number of records to return, defaults to 10. schema: type: integer - - name: id - in: query - required: false - description: Rather than supplying a query, you can specify a speicific id to get data back on a lookup field. - schema: - type: string get: operationId: crc.api.workflow.lookup diff --git a/crc/api/workflow.py b/crc/api/workflow.py index cee2f4cf..dc86ac9e 100644 --- a/crc/api/workflow.py +++ b/crc/api/workflow.py @@ -198,7 +198,7 @@ def delete_workflow_spec_category(cat_id): session.commit() -def lookup(workflow_id, field_id, query=None, limit=10, id=None): +def lookup(workflow_id, field_id, query=None, value=None, limit=10): """ given a field in a task, attempts to find the lookup table or function associated with that field and runs a full-text query against it to locate the values and @@ -206,7 +206,7 @@ def lookup(workflow_id, field_id, query=None, limit=10, id=None): Tries to be fast, but first runs will be very slow. """ workflow = session.query(WorkflowModel).filter(WorkflowModel.id == workflow_id).first() - lookup_data = LookupService.lookup(workflow, field_id, query, limit, id) + lookup_data = LookupService.lookup(workflow, field_id, query, value, limit) return LookupDataSchema(many=True).dump(lookup_data) diff --git a/crc/models/file.py b/crc/models/file.py index ccfbdc56..5eb50d4e 100644 --- a/crc/models/file.py +++ b/crc/models/file.py @@ -182,6 +182,7 @@ class LookupDataSchema(SQLAlchemyAutoSchema): load_instance = True include_relationships = False include_fk = False # Includes foreign keys + exclude = ['id'] # Do not include the id field, it should never be used via the API. class SimpleFileSchema(ma.Schema): diff --git a/crc/services/lookup_service.py b/crc/services/lookup_service.py index 876fda80..97c9824b 100644 --- a/crc/services/lookup_service.py +++ b/crc/services/lookup_service.py @@ -63,14 +63,14 @@ class LookupService(object): return lookup_model @staticmethod - def lookup(workflow, field_id, query, limit, id = None): + def lookup(workflow, field_id, query, value, limit): lookup_model = LookupService.__get_lookup_model(workflow, field_id) if lookup_model.is_ldap: return LookupService._run_ldap_query(query, limit) else: - return LookupService._run_lookup_query(lookup_model, query, limit, id) + return LookupService._run_lookup_query(lookup_model, query, value, limit) @@ -157,10 +157,10 @@ class LookupService(object): return lookup_model @staticmethod - def _run_lookup_query(lookup_file_model, query, limit, lookup_id): + def _run_lookup_query(lookup_file_model, query, value, limit): db_query = LookupDataModel.query.filter(LookupDataModel.lookup_file_model == lookup_file_model) - if lookup_id is not None: # Then just find the model with that id. - db_query = db_query.filter(LookupDataModel.id == lookup_id) + if value is not None: # Then just find the model with that value + db_query = db_query.filter(LookupDataModel.value == value) else: # Build a full text query that takes all the terms provided and executes each term as a prefix query, and # OR's those queries together. The order of the results is handled as a standard "Like" on the original diff --git a/tests/test_tasks_api.py b/tests/test_tasks_api.py index 11be07fd..236defdc 100644 --- a/tests/test_tasks_api.py +++ b/tests/test_tasks_api.py @@ -357,15 +357,36 @@ class TestTasksApi(BaseTest): self.assert_success(rv) results = json.loads(rv.get_data(as_text=True)) self.assertEqual(5, len(results)) - rv = self.app.get('/v1.0/workflow/%i/lookup/%s?id=%i' % - (workflow.id, field_id, results[0]['id']), # All records with a word that starts with 'c' + rv = self.app.get('/v1.0/workflow/%i/lookup/%s?value=%s' % + (workflow.id, field_id, results[0]['value']), # All records with a word that starts with 'c' headers=self.logged_in_headers(), content_type="application/json") results = json.loads(rv.get_data(as_text=True)) self.assertEqual(1, len(results)) self.assertIsInstance(results[0]['data'], dict) + self.assertNotIn('id', results[0], "Don't include the internal id, that can be very confusing, and should not be used.") - + def test_lookup_endpoint_also_works_for_enum(self): + # Naming here get's a little confusing. fields can be marked as enum or autocomplete. + # In the event of an auto-complete it's a type-ahead search field, for an enum the + # the key/values from the spreadsheet are added directly to the form and it shows up as + # a dropdown. This tests the case of wanting to get additional data when a user selects + # something from a drodown. + self.load_example_data() + workflow = self.create_workflow('enum_options_from_file') + # get the first form in the two form workflow. + workflow = self.get_workflow_api(workflow) + task = workflow.next_task + field_id = task.form['fields'][0]['id'] + option_id = task.form['fields'][0]['options'][0]['id'] + rv = self.app.get('/v1.0/workflow/%i/lookup/%s?value=%s' % + (workflow.id, field_id, option_id), # All records with a word that starts with 'c' + headers=self.logged_in_headers(), + content_type="application/json") + self.assert_success(rv) + results = json.loads(rv.get_data(as_text=True)) + self.assertEqual(1, len(results)) + self.assertIsInstance(results[0]['data'], dict) def test_lookup_endpoint_for_task_ldap_field_lookup(self): self.load_example_data()