Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parse URL query parameters to prepopulate subparser and script parameters #395

Merged
merged 3 commits into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions docs/wooey_ui.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,27 @@ to parse this information), updates to the script version will result in a new
version being created. If a command line library doesn't support versioning
or the version has not been updated in a script, the Script Iteration counter
will be incremented.

Using URL parameters to pre-populate script parameters
------------------------------------------------------

Wooey supports pre-populating script parameters via URL parameters. This is
useful for providing a link to a script with some parameters already set. The
following rules apply.

* URL parameters are specified as :code:`?parameter=value`
* Multiple parameters may be specified by separating them with :code:`&`.
For example, :code:`?parameter1=value1&parameter2=value2`.
* Parameters are specified by the name used in the script, **but in snake case**.
Lioscro marked this conversation as resolved.
Show resolved Hide resolved
For example, a parameter named :code:`--my-parameter` would be specified as
:code:`?my_parameter=value`.
* If a parameter is a flag, passing any value will set the flag. For example,
:code:`?my_flag=1` or :code:`?my_flag=true` will set the flag.
* If a parameter accepts multiple values (:code:`nargs`), the values are specified
by passing the parameter multiple times. For example, :code:`?my_parameter=1&my_parameter=2`
will set the parameter to have two values filled out: :code:`1` and :code:`2`.
If a parameter does not support multiple values and multiple values are passed,
the last value will be used.
* If the script has subparsers, the :code:`__subparser` parameter is used to specify
the subparser to use. For example, :code:`?__subparser=mysubparser` will select the
subparser named :code:`mysubparser`.
7 changes: 5 additions & 2 deletions wooey/templates/wooey/scripts/script_view.html
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ <h3 id="wooey-script-title">
<ul class="dropdown-menu">
{% for parser_info, parser_groups in form.parsers.items %}
{% with parser_pk=parser_info.0 parser_name=parser_info.1 %}
<li class="{% if forloop.first %}active{% endif %}"><a data-toggle="tab" data-parser-pk="{{ parser_pk }}" href="#parsergroup-{{ parser_pk }}">{% if not parser_name %}{% trans "Main Parser Parameters" %}{% else %}{{ parser_name|title }}{% endif %}</a></li>
<li class="{% if forloop.first %}active{% endif %}"><a data-toggle="tab" data-parser-pk="{{ parser_pk }}" data-parser-name="{{ parser_name }}" href="#parsergroup-{{ parser_pk }}">{% if not parser_name %}{% trans "Main Parser Parameters" %}{% else %}{{ parser_name|title }}{% endif %}</a></li>
{% if forloop.first %}
<li role="separator" class="divider"></li>
{% endif %}
Expand Down Expand Up @@ -263,7 +263,10 @@ <h3 id="wooey-script-title">
selectWooeyParser($('div[id^=parsergroup-]'))
}

var $initial_parser = $("a[data-parser-pk=" + $wooey_parser.val() + "]");
// Set initial subparser if present in url params.
const urlParams = new URLSearchParams(window.location.search);
const subparser = urlParams.get('__subparser');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a reason the param has __?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's because it is somewhat of an internal keyword that specifically controls the subparser to use, not to be confused with other URL parameters that are treated as positional or keyword arguments.

var $initial_parser = $("a[data-parser-name=" + subparser + "]");
if ($initial_parser.length) {
$initial_parser.click();
}
Expand Down
6 changes: 6 additions & 0 deletions wooey/tests/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ def tearDown(self):

class ScriptFactoryMixin(ScriptTearDown, object):
def setUp(self):
self.command_order_script_path = os.path.join(
config.WOOEY_TEST_SCRIPTS, "command_order.py"
)
self.command_order_script = factories.generate_script(
self.command_order_script_path
)
self.translate_script_path = os.path.join(
config.WOOEY_TEST_SCRIPTS, "translate.py"
)
Expand Down
108 changes: 108 additions & 0 deletions wooey/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,114 @@ def test_form_groups(self):
d = load_JSON_dict(response.content)
self.assertTrue(d["valid"], d)

def test_url_parameters_positional(self):
script_version = self.command_order_script
url = reverse("wooey:wooey_script", kwargs={"slug": script_version.script.slug})
request = self.factory.get(
url,
data={
"link": "abc",
},
)
request.user = AnonymousUser()
response = self.script_view_func(
request,
pk=script_version.script.pk,
)
self.assertEqual(response.status_code, 200)

context = response.resolve_context(response.context_data)
parser = list(context["form"]["parsers"].keys())[0]
self.assertEqual(
context["form"]["parsers"][parser][0]["form"]
.fields[f"{parser[0]}-link"]
.initial,
"abc",
)

def test_url_parameters_optional(self):
script_version = self.translate_script
url = reverse("wooey:wooey_script", kwargs={"slug": script_version.script.slug})
request = self.factory.get(
url,
data={
"sequence": "abc",
},
)
request.user = AnonymousUser()
response = self.script_view_func(
request,
pk=script_version.script.pk,
)
self.assertEqual(response.status_code, 200)

context = response.resolve_context(response.context_data)
parser = list(context["form"]["parsers"].keys())[0]
self.assertEqual(
context["form"]["parsers"][parser][0]["form"]
.fields[f"{parser[0]}-sequence"]
.initial,
"abc",
)

def test_url_parameters_multi_choice(self):
script_version = self.choice_script
url = reverse("wooey:wooey_script", kwargs={"slug": script_version.script.slug})
request = self.factory.get(
url,
data={
"one_choice": "0",
"two_choices": ["0", "1"],
},
)
request.user = AnonymousUser()
response = self.script_view_func(
request,
pk=script_version.script.pk,
)
self.assertEqual(response.status_code, 200)

context = response.resolve_context(response.context_data)
parser = list(context["form"]["parsers"].keys())[0]
self.assertEqual(
context["form"]["parsers"][parser][1]["form"]
.fields[f"{parser[0]}-one_choice"]
.initial,
"0",
)
self.assertEqual(
context["form"]["parsers"][parser][1]["form"]
.fields[f"{parser[0]}-two_choices"]
.initial,
["0", "1"],
)

def test_url_parameters_subparser(self):
script_version = self.subparser_script
url = reverse("wooey:wooey_script", kwargs={"slug": script_version.script.slug})
request = self.factory.get(url, data={"test_arg": "3.3", "sp1": "2"})
request.user = AnonymousUser()
response = self.script_view_func(
request,
pk=script_version.script.pk,
)
self.assertEqual(response.status_code, 200)

context = response.resolve_context(response.context_data)
main_parser, subparser1, subparser2 = list(context["form"]["parsers"].keys())
self.assertEqual(
context["form"]["parsers"][main_parser][0]["form"]
.fields[f"{main_parser[0]}-test_arg"]
.initial,
"3.3",
)
self.assertEqual(
context["form"]["parsers"][subparser1][0]["form"]
.fields[f"{subparser1[0]}-sp1"]
.initial,
"2",
)

def test_job_view_permissions(self):
# Make sure users cannot see jobs from other users
job = factories.generate_job(self.translate_script)
Expand Down
11 changes: 11 additions & 0 deletions wooey/views/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,17 @@ def get_context_data(self, **kwargs):
"script_version", "script_iteration"
).last()

# Set parameter initial values by parsing the URL parameters
# and matching them to the script parameters.
for param in script_version.get_parameters():
if param.script_param in self.request.GET:
value = (
self.request.GET.getlist(param.script_param)
if param.multiple_choice
else self.request.GET.get(param.script_param)
)
initial[param.form_slug] = value

context["form"] = utils.get_form_groups(
script_version=script_version,
initial_dict=initial,
Expand Down
Loading