Adding a simple endpoint that describes what scripts are currently available, along with a brief description.

This commit is contained in:
Dan Funk 2020-03-03 15:30:42 -05:00
parent 7194d7d374
commit 94f828dfd6
8 changed files with 80 additions and 25 deletions

View File

@ -680,7 +680,21 @@ paths:
type: string
format: binary
example: '<?xml version="1.0" encoding="UTF-8"?><bpmn:definitions></bpmn:definitions>'
/list_scripts:
get:
operationId: crc.api.tools.list_scripts
summary: Returns an list of scripts, along with their descriptions
tags:
- Configurator Tools
responses:
'201':
description: The list of scripts
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Script"
components:
schemas:
User:
@ -969,3 +983,12 @@ components:
message:
type: string
example: "You do not have permission to view the requested study."
Script:
properties:
name:
type: string
format: string
example: "random_fact"
description:
type: string
example: "Returns a random fact about a topic. Provide an argument of either 'cat', 'norris', or 'buzzword'"

View File

@ -1,18 +1,14 @@
import io
import json
import uuid
from io import BytesIO
import connexion
import jinja2
from docxtpl import DocxTemplate
from flask import send_file
from jinja2 import Template, UndefinedError
from crc.api.common import ApiError, ApiErrorSchema
from crc.api.common import ApiError
from crc.scripts.complete_template import CompleteTemplate
from crc.services.file_service import FileService
from crc.scripts.script import Script
import crc.scripts
def render_markdown(data, template):
"""
@ -48,3 +44,17 @@ def render_docx(data):
raise ApiError(code="invalid", message=str(e))
except Exception as e:
raise ApiError(code="invalid", message=str(e))
def list_scripts():
"""Provides a list of scripts that can be called by a script task."""
scripts = Script.get_all_subclasses()
script_meta = []
for script_class in scripts:
script_meta.append(
{
"name": script_class.__name__,
"description": script_class().get_description()
})
return script_meta

View File

@ -1,9 +0,0 @@
import requests
class IRBDocAPI:
"""Just your basic class that can pull in data from a few api endpoints and do a basic task."""
def do_task(self, task_data):
print('*** IRB_Doc_API > do_task ***')
print('task_data', task_data)

View File

@ -17,11 +17,8 @@ from crc.services.workflow_processor import WorkflowProcessor
class CompleteTemplate(Script):
def get_description(self):
return
"""Completes a word template, using the data available in the current task. Heavy on the
error messages, because there is so much that can go wrong here, and we want to provide
as much feedback as possible. Some of this might move up to a higher level object or be
passed into all tasks as we complete more work."""
return """Takes one argument, which is the name of a MS Word docx file to use as a template.
All data currently collected up to this Task will be available for use in the template."""
def do_task(self, task, study_id, *args, **kwargs):
"""Entry point, mostly worried about wiring it all up."""

View File

@ -5,7 +5,8 @@ from crc.scripts.script import Script
class FactService(Script):
def get_description(self):
return """Just your basic class that can pull in data from a few api endpoints and do a basic task."""
return """Just your basic class that can pull in data from a few api endpoints and
do a basic task."""
def get_cat(self):
response = requests.get('https://cat-fact.herokuapp.com/facts/random')

View File

@ -1,3 +1,7 @@
import importlib
import os
import pkgutil
from crc.api.common import ApiError
@ -13,3 +17,25 @@ class Script:
raise ApiError("invalid_script",
"This is an internal error. The script you are trying to execute " +
"does not properly implement the do_task function.")
@staticmethod
def get_all_subclasses():
return Script._get_all_subclasses(Script)
@staticmethod
def _get_all_subclasses(cls):
# hackish mess to make sure we have all the modules loaded for the scripts
pkg_dir = os.path.dirname(__file__)
for (module_loader, name, ispkg) in pkgutil.iter_modules([pkg_dir]):
importlib.import_module('.' + name, __package__)
"""Returns a list of all classes that extend this class."""
all_subclasses = []
for subclass in cls.__subclasses__():
all_subclasses.append(subclass)
all_subclasses.extend(Script._get_all_subclasses(subclass))
return all_subclasses

View File

@ -13,8 +13,7 @@ class StudyInfo(Script):
type_options = ['info', 'investigators', 'required_docs', 'details']
def get_description(self):
return """
StudyInfo [TYPE] is one of 'info', 'investigators','required_docs', 'details'
return """StudyInfo [TYPE], where TYPE is one of 'info', 'investigators','required_docs', or 'details'
Adds details about the current study to the Task Data. The type of information required should be
provided as an argument. Basic returns the basic information such as the title. Investigators provides
detailed information about each investigator in th study. Details provides a large number

View File

@ -32,3 +32,11 @@ class TestStudyApi(BaseTest):
data=file_data, follow_redirects=True,
content_type='multipart/form-data')
self.assert_success(rv)
def test_list_scripts(self):
rv = self.app.get('/v1.0/list_scripts')
self.assert_success(rv)
scripts = json.loads(rv.get_data(as_text=True))
self.assertTrue(len(scripts) > 1)
self.assertIsNotNone(scripts[0]['name'])
self.assertIsNotNone(scripts[0]['description'])