diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 24adbe162..7450e537b 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -9,3 +9,6 @@ updates: directory: "/" # Location of package manifests schedule: interval: "daily" + ignore: + - dependency-name: "boto3" + update-types: ["version-update:semver-patch"] diff --git a/pyproject.toml b/pyproject.toml index 232f8557e..c336a1c2b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,9 +5,9 @@ description = "Add your description here" readme = "README.md" requires-python = "==3.13.*" dependencies = [ - "boto3==1.38.9", + "boto3==1.40.52", "ciso8601==2.3.2", - "django==5.2.2", + "django==5.2.8", "django-ace-overlay", "django-bitfield==2.2.0", "django-bootstrap-icons==0.9.0", @@ -27,7 +27,7 @@ dependencies = [ "djangorestframework==3.16.0", "djangorestframework-jsonapi==7.1.0", "docker==7.1.0", - "drf-nested-routers==0.94.1", + "drf-nested-routers==0.95.0", "fleep==1.0.1", "gevent==25.4.2", "google-cloud-storage==3.1.0", @@ -54,7 +54,7 @@ dev = [ "django-dynamic-fixture==4.0.1", "libsass==0.23.0", "parameterized==0.9.0", - "pre-commit==4.2.0", + "pre-commit==4.3.0", "pyinstrument==5.0.1", "pyopenssl==25.0.0", "python-dotenv==1.0.1", diff --git a/studies/templates/studies/experiment_runner/base.html b/studies/templates/studies/experiment_runner/base.html index bb32cbd33..9b4530cc6 100644 --- a/studies/templates/studies/experiment_runner/base.html +++ b/studies/templates/studies/experiment_runner/base.html @@ -48,7 +48,7 @@

{% block header %} {% endblock header %} -
+ {% csrf_token %} {% block form %} {% endblock form %} diff --git a/uv.lock b/uv.lock index 773401718..a29d4f541 100644 --- a/uv.lock +++ b/uv.lock @@ -47,30 +47,30 @@ wheels = [ [[package]] name = "boto3" -version = "1.38.9" +version = "1.40.52" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, { name = "jmespath" }, { name = "s3transfer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/16/fa/3907a6f574172d34ec1d8f27d02cef82f1a218cc438bfb89c24c68f11b8f/boto3-1.38.9.tar.gz", hash = "sha256:71f6d43f5bc156cc904f8dde9a2801adb222b81724fb9129f8ff6e7b9331e853", size = 111778, upload-time = "2025-05-05T19:31:36.188Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a0/5a/8ba08c979926326d961e2384d994d789a2eda3ed281bb6cb333b36e92310/boto3-1.40.52.tar.gz", hash = "sha256:96ee720b52be647d8ef5ba92fccfce6b65d6321769430fe6edd10d57ec43c25b", size = 111530, upload-time = "2025-10-14T20:32:12.226Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a5/b7/132e5950668ca9c5c53ee6b7658b80446db78df8c923f96c4d73d694ed59/boto3-1.38.9-py3-none-any.whl", hash = "sha256:a9f8642e84589e7787da0d5d146a14d1eb9e3a4029893c88d1b4e11654cf8014", size = 139900, upload-time = "2025-05-05T19:31:32.956Z" }, + { url = "https://files.pythonhosted.org/packages/0f/d2/879e9787c5263aefc5c88f0dd97cdea29ac01c480dd53c2421de77a493f7/boto3-1.40.52-py3-none-any.whl", hash = "sha256:ecc8c99d3cc96716cdfba62d9c9c6ce0eb98d02494a66690bcc2ec181c1ced67", size = 139345, upload-time = "2025-10-14T20:32:10.801Z" }, ] [[package]] name = "botocore" -version = "1.38.19" +version = "1.40.52" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jmespath" }, { name = "python-dateutil" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7f/78/c1b2fa6a267018062a66470e6e779366b4e64ab1178de8870ccc3a393cac/botocore-1.38.19.tar.gz", hash = "sha256:796b948c05017eb33385b798990cd91ed4af0e881eb9eb1ee6e17666be02abc9", size = 13913334, upload-time = "2025-05-19T19:31:07.026Z" } +sdist = { url = "https://files.pythonhosted.org/packages/83/74/3449d77c002d82586786b91dff6dd2e6fd52c5cdc1793d1ac7ea690ea52c/botocore-1.40.52.tar.gz", hash = "sha256:b65d970ca4ccd869639332083da17c3a933bcf495120dcc4f5c7723cb3f6216c", size = 14427680, upload-time = "2025-10-14T20:32:03.065Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ae/4d/168137542d007a2beb7df8147edce6c5ab1155dd13e8533e74e3ac8ec030/botocore-1.38.19-py3-none-any.whl", hash = "sha256:f937a20e75889215a99280ea0fdd4e1716ffede23e4f9af7bc9c64af9bc63e61", size = 13573222, upload-time = "2025-05-19T19:31:01.52Z" }, + { url = "https://files.pythonhosted.org/packages/05/ad/559dc4097fe1368e5f3abb5d8ca496f9c609e4e452498bca11134fde1462/botocore-1.40.52-py3-none-any.whl", hash = "sha256:838697a06c7713df8d39f088105334b4eadcc3d65c7a260bf1a1bd8bf616ce4a", size = 14098823, upload-time = "2025-10-14T20:32:00.094Z" }, ] [[package]] @@ -320,16 +320,16 @@ wheels = [ [[package]] name = "django" -version = "5.2.2" +version = "5.2.7" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "asgiref" }, { name = "sqlparse" }, { name = "tzdata", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/39/17/4567ee12bb84114c544d5c4a792e7226db517ac78f552111e9dc62d1de14/django-5.2.2.tar.gz", hash = "sha256:85852e517f84435e9b13421379cd6c43ef5b48a9c8b391d29a26f7900967e952", size = 10827542, upload-time = "2025-06-04T13:52:40.879Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b1/96/bd84e2bb997994de8bcda47ae4560991084e86536541d7214393880f01a8/django-5.2.7.tar.gz", hash = "sha256:e0f6f12e2551b1716a95a63a1366ca91bbcd7be059862c1b18f989b1da356cdd", size = 10865812, upload-time = "2025-10-01T14:22:12.081Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/5c/5d00acab6c062b154e5a0f092938ae5a0c698dbc4362b68e23200960f32c/django-5.2.2-py3-none-any.whl", hash = "sha256:997ef2162d04ead6869551b22cde4e06da1f94cf595f4af3f3d3afeae1f3f6fe", size = 8302562, upload-time = "2025-06-04T13:52:33.14Z" }, + { url = "https://files.pythonhosted.org/packages/8f/ef/81f3372b5dd35d8d354321155d1a38894b2b766f576d0abffac4d8ae78d9/django-5.2.7-py3-none-any.whl", hash = "sha256:59a13a6515f787dec9d97a0438cd2efac78c8aca1c80025244b0fe507fe0754b", size = 8307145, upload-time = "2025-10-01T14:22:49.476Z" }, ] [[package]] @@ -586,15 +586,15 @@ wheels = [ [[package]] name = "drf-nested-routers" -version = "0.94.1" +version = "0.95.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "django" }, { name = "djangorestframework" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1e/24/9e6a070dc491a416c93e4ec41950c7ea66d6a63b8db8d8abc0c128355978/drf-nested-routers-0.94.1.tar.gz", hash = "sha256:2b846385ed95c9f17bf4242db3b264ac826b5af00dda6c737d3fe7cc7bf2c7db", size = 18347, upload-time = "2024-05-10T22:36:55.553Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ff/b2/070908ccd41bd6f025f5507d7f6e50009abe8be48393cc697d159b539f0b/drf_nested_routers-0.95.0.tar.gz", hash = "sha256:815978f802e578fd7035c74040c104909cbe97615de89a275d77e928f4029891", size = 23318, upload-time = "2025-09-09T02:01:58.201Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/a2/313a95268ffae9773a59aeb15c3f6932d4c905616d4797b371e6257fc8f9/drf_nested_routers-0.94.1-py2.py3-none-any.whl", hash = "sha256:3a8ec45a025c0f39188ec1ec415244beb875a6f4db87911a1f5a606d09b68c9f", size = 36260, upload-time = "2024-05-10T22:36:53.092Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/69d951a6e8031389f5feade38531432325019e1047b23d5c6036a86c5e8f/drf_nested_routers-0.95.0-py2.py3-none-any.whl", hash = "sha256:dd489c33d667aaa81383ffaa8c74781d2b353d8f0795716ae37fc59ee297b7c4", size = 36407, upload-time = "2025-09-09T02:01:56.999Z" }, ] [[package]] @@ -893,9 +893,9 @@ dev = [ [package.metadata] requires-dist = [ - { name = "boto3", specifier = "==1.38.9" }, + { name = "boto3", specifier = "==1.40.52" }, { name = "ciso8601", specifier = "==2.3.2" }, - { name = "django", specifier = "==5.2.2" }, + { name = "django", specifier = "==5.2.7" }, { name = "django-ace-overlay", git = "https://github.com/lookit/django-ace-overlay.git?rev=master" }, { name = "django-bitfield", specifier = "==2.2.0" }, { name = "django-bootstrap-icons", specifier = "==0.9.0" }, @@ -915,7 +915,7 @@ requires-dist = [ { name = "djangorestframework", specifier = "==3.16.0" }, { name = "djangorestframework-jsonapi", specifier = "==7.1.0" }, { name = "docker", specifier = "==7.1.0" }, - { name = "drf-nested-routers", specifier = "==0.94.1" }, + { name = "drf-nested-routers", specifier = "==0.95.0" }, { name = "fleep", specifier = "==1.0.1" }, { name = "gevent", specifier = "==25.4.2" }, { name = "google-cloud-storage", specifier = "==3.1.0" }, @@ -942,7 +942,7 @@ dev = [ { name = "django-dynamic-fixture", specifier = "==4.0.1" }, { name = "libsass", specifier = "==0.23.0" }, { name = "parameterized", specifier = "==0.9.0" }, - { name = "pre-commit", specifier = "==4.2.0" }, + { name = "pre-commit", specifier = "==4.3.0" }, { name = "pyinstrument", specifier = "==5.0.1" }, { name = "pyopenssl", specifier = "==25.0.0" }, { name = "python-dotenv", specifier = "==1.0.1" }, @@ -1046,7 +1046,7 @@ wheels = [ [[package]] name = "pre-commit" -version = "4.2.0" +version = "4.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cfgv" }, @@ -1055,9 +1055,9 @@ dependencies = [ { name = "pyyaml" }, { name = "virtualenv" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/08/39/679ca9b26c7bb2999ff122d50faa301e49af82ca9c066ec061cfbc0c6784/pre_commit-4.2.0.tar.gz", hash = "sha256:601283b9757afd87d40c4c4a9b2b5de9637a8ea02eaff7adc2d0fb4e04841146", size = 193424, upload-time = "2025-03-18T21:35:20.987Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ff/29/7cf5bbc236333876e4b41f56e06857a87937ce4bf91e117a6991a2dbb02a/pre_commit-4.3.0.tar.gz", hash = "sha256:499fe450cc9d42e9d58e606262795ecb64dd05438943c62b66f6a8673da30b16", size = 193792, upload-time = "2025-08-09T18:56:14.651Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/74/a88bf1b1efeae488a0c0b7bdf71429c313722d1fc0f377537fbe554e6180/pre_commit-4.2.0-py2.py3-none-any.whl", hash = "sha256:a009ca7205f1eb497d10b845e52c838a98b6cdd2102a6c8e4540e94ee75c58bd", size = 220707, upload-time = "2025-03-18T21:35:19.343Z" }, + { url = "https://files.pythonhosted.org/packages/5b/a5/987a405322d78a73b66e39e4a90e4ef156fd7141bf71df987e50717c321b/pre_commit-4.3.0-py2.py3-none-any.whl", hash = "sha256:2b0747ad7e6e967169136edffee14c16e148a778a54e4f967921aa1ebf2308d8", size = 220965, upload-time = "2025-08-09T18:56:13.192Z" }, ] [[package]] @@ -1375,14 +1375,14 @@ wheels = [ [[package]] name = "s3transfer" -version = "0.12.0" +version = "0.14.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fc/9e/73b14aed38ee1f62cd30ab93cd0072dec7fb01f3033d116875ae3e7b8b44/s3transfer-0.12.0.tar.gz", hash = "sha256:8ac58bc1989a3fdb7c7f3ee0918a66b160d038a147c7b5db1500930a607e9a1c", size = 149178, upload-time = "2025-04-22T21:08:09.787Z" } +sdist = { url = "https://files.pythonhosted.org/packages/62/74/8d69dcb7a9efe8baa2046891735e5dfe433ad558ae23d9e3c14c633d1d58/s3transfer-0.14.0.tar.gz", hash = "sha256:eff12264e7c8b4985074ccce27a3b38a485bb7f7422cc8046fee9be4983e4125", size = 151547, upload-time = "2025-09-09T19:23:31.089Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/89/64/d2b49620039b82688aeebd510bd62ff4cdcdb86cbf650cc72ae42c5254a3/s3transfer-0.12.0-py3-none-any.whl", hash = "sha256:35b314d7d82865756edab59f7baebc6b477189e6ab4c53050e28c1de4d9cce18", size = 84773, upload-time = "2025-04-22T21:08:08.265Z" }, + { url = "https://files.pythonhosted.org/packages/48/f0/ae7ca09223a81a1d890b2557186ea015f6e0502e9b8cb8e1813f1d8cfa4e/s3transfer-0.14.0-py3-none-any.whl", hash = "sha256:ea3b790c7077558ed1f02a3072fb3cb992bbbd253392f4b6e9e8976941c7d456", size = 85712, upload-time = "2025-09-09T19:23:30.041Z" }, ] [[package]] diff --git a/web/static/js/efp-runner.js b/web/static/js/efp-runner.js index 84426184e..192d37583 100644 --- a/web/static/js/efp-runner.js +++ b/web/static/js/efp-runner.js @@ -120,7 +120,7 @@ function updateCommitUpdateInfo(event) { } function updateLastPlayerSha() { - const form = document.forms[0]; + const form = document.querySelector('form#experiment_runner_form'); if (!form.last_known_player_sha.value) { const playerRepoUrl = document.querySelector('#id_player_repo_url').value; @@ -162,4 +162,4 @@ updateLastPlayerSha(); document.querySelector('#id_use_generator').addEventListener("click", updateProtocolDisplay); document.querySelector('#update-button').addEventListener("click", updateCommitUpdateInfo); document.querySelector('#id_last_known_player_sha').addEventListener('keyup', updateCommitDescription); -document.querySelector('form').addEventListener('submit', validateGenerator); +document.querySelector('form#experiment_runner_form').addEventListener('submit', validateGenerator); diff --git a/web/static/js/external-runner.js b/web/static/js/external-runner.js index 54e5b8df0..426b66a91 100644 --- a/web/static/js/external-runner.js +++ b/web/static/js/external-runner.js @@ -1,7 +1,9 @@ +const form = document.querySelector('form#experiment_runner_form'); + function toggleScheduling() { - const scheduled = document.forms[0].scheduled; - const scheduling = document.querySelector('#id_scheduling'); - const checked_scheduling = document.querySelector('input[name="scheduling"]:checked') + const scheduled = form.querySelector('#id_scheduled'); + const scheduling = form.querySelector('#id_scheduling'); + const checked_scheduling = form.querySelector('input[name="scheduling"]:checked'); if (scheduled.value === "Scheduled") { scheduling.parentNode.classList.remove('d-none'); } else { @@ -11,9 +13,9 @@ function toggleScheduling() { } function toggleOtherScheduling() { - const scheduled = document.forms[0].scheduled; - const scheduling = document.forms[0].scheduling; - const otherScheduling = document.querySelector('#id_other_scheduling') + const scheduled = form.querySelector('#id_scheduled'); + const scheduling = form.querySelector('#id_scheduling'); + const otherScheduling = form.querySelector('#id_other_scheduling'); if (scheduling.value === 'Other' && scheduled.value === "Scheduled") { otherScheduling.parentNode.classList.remove('d-none'); } else { @@ -23,9 +25,8 @@ function toggleOtherScheduling() { } function toggleOtherStudyPlatform() { - const studyPlatform = document.forms[0].study_platform; - const otherStudyPlatform = document.forms[0].other_study_platform; - + const studyPlatform = form.study_platform; + const otherStudyPlatform = form.other_study_platform; if (studyPlatform.value === 'Other') { otherStudyPlatform.parentNode.classList.remove('d-none') } else { @@ -41,13 +42,12 @@ toggleScheduling(); toggleOtherScheduling(); toggleOtherStudyPlatform(); - /*** * Event listeners */ -document.querySelector('#id_scheduled').addEventListener('click', () => { +form.querySelector('#id_scheduled').addEventListener('click', () => { toggleScheduling(); toggleOtherScheduling(); }); -document.querySelector('#id_scheduling').addEventListener('change', toggleOtherScheduling); -document.querySelector('#id_study_platform').addEventListener('change', toggleOtherStudyPlatform); +form.querySelector('#id_scheduling').addEventListener('change', toggleOtherScheduling); +form.querySelector('#id_study_platform').addEventListener('change', toggleOtherStudyPlatform); diff --git a/web/static/js/jspsych-runner.js b/web/static/js/jspsych-runner.js index b47cbb944..2c85fb89e 100644 --- a/web/static/js/jspsych-runner.js +++ b/web/static/js/jspsych-runner.js @@ -6,4 +6,4 @@ function validateExperiment(event) { /** * Event Listeners */ -document.querySelector('form').addEventListener('submit', validateExperiment); +document.querySelector('form#experiment_runner_form').addEventListener('submit', validateExperiment); diff --git a/web/static/js/resources.js b/web/static/js/resources.js index 1e7aeffde..e92f8f838 100644 --- a/web/static/js/resources.js +++ b/web/static/js/resources.js @@ -551,6 +551,10 @@ const labsData = { { "url": "https://peabody.vanderbilt.edu/departments/psych/research/research_labs/educational_cognitive_neuroscience_lab/index.php", "name": "Vanderbilt Educational Cognitive Neuroscience Lab" + }, + { + "url": "https://theccdlab.com/", + "name": "Vanderbilt University Computational Cognitive Development Lab" } ], "Texas": [ diff --git a/web/static/js/studies-list.js b/web/static/js/studies-list.js index 34f928fcc..fd0c61d35 100644 --- a/web/static/js/studies-list.js +++ b/web/static/js/studies-list.js @@ -1,4 +1,4 @@ -const $form = $('form'); +const $form = $('form#studies_list_form'); const $hideStudiesCheckbox = $form.find('input:checkbox[name=hide_studies_we_have_done]') const $checkboxes = $form.find('input:checkbox') const $dropdownSelected = $form.find('select option:selected') diff --git a/web/static/js/study-create.js b/web/static/js/study-create.js index 2e31dbc96..cc6562328 100644 --- a/web/static/js/study-create.js +++ b/web/static/js/study-create.js @@ -8,7 +8,7 @@ })(); $(document).ready(function() { - $('form').submit(function() { + $('form#study-details-form').submit(function() { $('#create-study-button').prop("disabled", "disabled"); }); }); diff --git a/web/static/js/study-detail.js b/web/static/js/study-detail.js index 5c04472cb..95f941b68 100644 --- a/web/static/js/study-detail.js +++ b/web/static/js/study-detail.js @@ -128,9 +128,10 @@ new Clipboard('.copy-link-button'); // NOSONAR $('#private-study-link, #study-preview-link').attr('readonly', 'readonly'); - -$('form').submit(function () { - $('#changeStatusButton').prop("disabled", "disabled"); +// disable the study state dropdown and submit/save button to prevent another status change while the page reloads +$('form#studyStateModalForm').submit(function () { + $('#changeStudyState').prop("disabled", "disabled"); + $('form#studyStateModalForm button').prop("disabled", "disabled"); }); $(function () { diff --git a/web/templates/web/jspsych-study-detail.html b/web/templates/web/jspsych-study-detail.html index 40015df3f..d165f2054 100644 --- a/web/templates/web/jspsych-study-detail.html +++ b/web/templates/web/jspsych-study-detail.html @@ -15,6 +15,9 @@ + @@ -24,6 +27,12 @@ + + @@ -45,11 +54,11 @@ - - {% csrf_token %}