From 57f23f5198a364eefc27f1cf2ad7adf929355099 Mon Sep 17 00:00:00 2001 From: Lars Eggert Date: Thu, 10 Aug 2023 17:49:15 +0300 Subject: [PATCH] chore: feat/dark-mode <- main (#6103) * chore: Remove unused "rendertest" stuff (#6015) * fix: restore ability to create status change documents (#5963) * fix: restore ability to create status change documents Fixes #5962 * chore: address review comment * fix: Provide human-friendly status in submission status API response (#6011) Co-authored-by: nectostr * fix: Make name/email lookups case-insensitive (#5972) (#6007) * fix: Make name/email lookups case-insensitive (#5972) Use icontains so that looking up name or email is case insensitive Added a test Fixes: 5972 * fix: Use __iexact not __icontains * fix: Clarify no-action-needed (#5918) (#6020) When a draft is submitted for manual processing, clarify that no action is needed; the Secretariat has the next steps. Fixes: #5918 * fix: Fix menu hover issue (#6019) * fix: Fix menu hover issue Fixes #5702 * Fix leftmenu hover issue * fix: Server error from api_get_session_materials() (#6025) Fixes #5877 * fix: Clarify Questionnaire label (#4688) (#6017) When filtering nominees, `Questionnaire` implies `Accepted == yes` so fix the dropdown test tosay that. Fixes: #4688 * chore: Merge from @martinthomson's rfc-txt-html (#6023) * fix:no history entry when changing RFC Editor note for doc (#6021) * fix:no history entry when changing RFC Editor note for doc * fix:no history entry when changing RFC Editor note for doc --------- Co-authored-by: Priyanka Narkar * fix: avoid deprecation warning on view_list() for objs without CommunityList Fixes #5942 * fix: return 404 for non-existing revisions (#6014) * fix: return 404 for non-existing revisions Links to non-existing revisions to docs should return 404 * fix: change rfc/rev and search behaviour * refactor: fix tab level * fix: return 404 for rfc revision for bibtex * fix: provide date for revisions in bibtex output (#6029) * fix: provide date for revisions in bibtex output * refactor: change walrus to if's * fix: specify particular revision for events * fix: review refactoring issue fixes #5447 * fix: Remove automatically suggested document for document that is already has review request (fixes #3211) (#5425) * Added check that if there is already review request for the document in question, ignore the automatic suggestion for that document. Fixes #3211. * fix: dont block on open requests for a previous version. Add tests --------- Co-authored-by: Nicolas Giard Co-authored-by: Robert Sparks * feat: IAB statements (#5940) * feat: support iab and iesg statements. Import iab statements. (#5895) * feat: infrastructure for statements doctype * chore: basic test framework * feat: basic statement document view * feat: show replaced statements * chore: black * fix: state help for statements * fix: cleanout non-relevant email expansions * feat: import iab statements, provide group statements tab * fix: guard against running import twice * feat: build redirect csv for iab statements * fix: set document state on import * feat: show published date on main doc view * feat: handle pdf statements * feat: create new and update statements * chore: copyright block updates * chore: remove flakes * chore: black * feat: add edit/new buttons for the secretariat * fix: address PR #5895 review comments * fix: pin pydantic until inflect catches up (#5901) (#5902) * chore: re-un-pin pydantic * feat: include submitter in email about submitted slides (#6033) * feat: include submitter in email about submitted slides fixes #6031 * chore: remove unintended whitespace change * chore(dev): update .vscode/settings.json with new taskExplorer settings * fix: Add editorial stream to proceedings (#6027) * fix: Add editorial stream to proceedings Fixes #5717 * fix: Move editorial stream after the irtf in proceedings * fix: Add editorial stream to meeting materials (#6047) Fixes #6042 * fix: Shows requested reviews for doc fixes (#6022) * Fix: Shows requested reviews for doc * Changed template includes to only give required variables to them. * feat: allow openId to choose an unactive email if there are none active (#6041) * feat: allow openId to choose an unactive email if there are no active ones * chore: correct typo * chore: rename unactive to inactive * fix: Make review table more responsive (#6053) * fix: Improve layout of review table * Progress * Progress * Final changes * Fix tests * Remove fluff * Undo commits * ci: add --validate-html-harder to tests * ci: add --validate-html-harder to build.yml workflow * fix: Set colspan to actual number of columns (#6069) * fix: Clean up view_feedback_pending (#6070) - Remove "Unclassified" column header, which caused misalignment in the table body. - Show the message author - previously displayed as `(None)`. * docs: Update LICENSE year * fix: Remove IESG state edit button when state is 'dead' (#6051) (#6065) * fix: Correctly order "last call requested" column in the IESG dashboard (#6079) * ci: update dev sandbox init script to start memcached * feat: Reclassify nomcom feedback (#6002) * fix: Clean up view_feedback_pending - Remove "Unclassified" column header, which caused misalignment in the table body. - Show the message author - previously displayed as `(None)`. * feat: Reclassify nomcom feedback (#4669) - There's a new `Chair/Advisor Tasks` menu item `Reclassify feedback`. - I overloaded `view_feedback*` URLs with a `?reclassify` parameter. - This adds a checkbox to each feedback message, and a `Reclassify` button at the bottom of each feedback page. - "Reclassifying" basically de-classifies the feedback, and punts it back to the "Pending emails" view for reclassification. - If a feedback has been applied to multiple nominees, declassifying it from one nominee removes it from all. * fix: Remove unused local variables * fix: Fix some missing and mis-nested html * test: Add tests for reclassifying feedback * refactor: Substantial redesign of feedback reclassification - Break out reclassify_feedback* as their own URLs and views, and revert changes to view_feedback*.html. - Replace checkboxes with a Reclassify button on each message. * fix: Remember to clear the feedback associations when reclassifying * feat: Add an 'Overcome by events' feedback type * refactor: When invoking reclassification from a view-feedback page, load the corresponding reclassify-feedback page * fix: De-conflict migration with 0004_statements Also change the coding style to match, and add a reverse migration. * fix: Fix a test case to account for new feedback type * fix: 842e730 broke the Back button * refactor: Reclassify feedback directly instead of putting it back in the work queue * fix: Adjust tests to new workflow * refactor: Further refine reclassification to avoid redirects * refactor: Impose a FeedbackTypeName ordering Also add FeedbackTypeName.legend field, rather than synthesizing it every time we classify or reclassify feedback. In the reclassification forms, only show the relevant feedback types. * refactor: Merge reclassify_feedback_* back into view_feedback_* This means the "Reclassify" button is always present, but eliminates some complexity. * refactor: Add filter(used=True) on FeedbackTypeName querysets * refactor: Add the new FeedbackTypeName to the reclassification success message * fix: Secure reclassification against rogue nomcom members * fix: Print decoded key and fully clean up test nomcom (#6094) * fix: Delete Person records when deleting a test nomcom * fix: Decode test nomcom private key before printing * test: Use correct time zone for test_statement_doc_view (#6064) * chore(deps): update all npm dependencies for playwright (#6061) Co-authored-by: depfu[bot] <23717796+depfu[bot]@users.noreply.github.com> * chore(deps): update all npm dependencies for dev/diff (#6062) Co-authored-by: depfu[bot] <23717796+depfu[bot]@users.noreply.github.com> * chore(deps): update all npm dependencies for dev/coverage-action (#6063) Co-authored-by: depfu[bot] <23717796+depfu[bot]@users.noreply.github.com> * fix: Hash cache key for default memcached cache (#6089) * feat: Show docs that an AD hasn't balloted on that need ballots to progress (#6075) * fix(doc): Unify help texts for document states (#6060) * Fix IESG State help text link (only) * Intermediate checkpoint * Correct URL filtering of state descriptions * Unify help texts for document states * Remove redundant load static from template --------- Co-authored-by: Robert Sparks * ci: fix sandbox start.sh memcached user * fix: refactor how settings handles cache definitions (#6099) * fix: refactor how settings handles cache definitions * chore: more english-speaker readable expression * fix: Cast cache key to str before calling encode (#6100) --------- Co-authored-by: Robert Sparks Co-authored-by: Liubov Kurafeeva Co-authored-by: nectostr Co-authored-by: Rich Salz Co-authored-by: PriyankaN Co-authored-by: Priyanka Narkar Co-authored-by: Ali Co-authored-by: Roman Beltiukov Co-authored-by: Tero Kivinen Co-authored-by: Nicolas Giard Co-authored-by: Kesara Rathnayake Co-authored-by: Jennifer Richards Co-authored-by: Paul Selkirk Co-authored-by: depfu[bot] <23717796+depfu[bot]@users.noreply.github.com> Co-authored-by: Jim Fenton --- .github/workflows/build.yml | 4 +- .github/workflows/ci-run-tests.yml | 2 +- .vscode/settings.json | 115 +- LICENSE | 4 +- dev/coverage-action/package-lock.json | 1535 ++++++----------- dev/coverage-action/package.json | 4 +- dev/deploy-to-container/start.sh | 3 + dev/diff/package-lock.json | 14 +- dev/diff/package.json | 2 +- docker/configs/settings_local.py | 2 +- ietf/api/tests.py | 9 + ietf/community/views.py | 2 +- ietf/doc/factories.py | 32 +- .../commands/import_iab_statements.py | 320 ++++ .../migrations/0005_alter_docevent_type.py | 86 + ietf/doc/migrations/0006_statements.py | 43 + ietf/doc/models.py | 12 +- ietf/doc/tests.py | 21 + ietf/doc/tests_draft.py | 20 +- ietf/doc/tests_statement.py | 359 ++++ ietf/doc/tests_status_change.py | 26 +- ietf/doc/urls.py | 6 +- ietf/doc/urls_statement.py | 10 + ietf/doc/views_ballot.py | 2 +- ietf/doc/views_doc.py | 55 +- ietf/doc/views_help.py | 9 +- ietf/doc/views_review.py | 5 +- ietf/doc/views_search.py | 52 +- ietf/doc/views_statement.py | 274 +++ ietf/doc/views_status_change.py | 4 +- ietf/group/tests_info.py | 6 - ietf/group/tests_review.py | 17 +- ietf/group/urls.py | 4 +- ietf/group/utils.py | 4 +- ietf/group/views.py | 44 +- ietf/ietfauth/utils.py | 2 +- .../migrations/0002_slidesubmitter.py | 31 + ietf/mailtrigger/utils.py | 4 +- ietf/meeting/tests_views.py | 40 + ietf/meeting/views.py | 22 +- ietf/name/fixtures/names.json | 96 +- ietf/name/migrations/0004_statements.py | 21 + .../0005_feedbacktypename_schema.py | 20 + .../migrations/0006_feedbacktypename_data.py | 36 + ietf/name/models.py | 1 + ietf/nomcom/forms.py | 2 +- .../management/commands/create_test_nomcom.py | 8 +- ietf/nomcom/tests.py | 91 +- ietf/nomcom/views.py | 107 +- ietf/person/models.py | 8 + ietf/person/tests.py | 8 + ietf/person/views.py | 4 +- ietf/review/policies.py | 20 +- ietf/review/tests_policies.py | 14 +- ietf/review/utils.py | 9 +- ietf/settings.py | 161 +- ietf/static/css/document_html_txt.scss | 4 +- ietf/static/css/ietf.scss | 28 + ietf/static/js/ietf.js | 15 - ietf/static/js/upload_statement.js | 29 + ietf/submit/tests.py | 4 +- ietf/submit/views.py | 1 + ietf/templates/base/menu.html | 1 - ietf/templates/doc/document_draft.html | 16 +- ietf/templates/doc/document_info.html | 5 +- ietf/templates/doc/document_statement.html | 134 ++ ietf/templates/doc/drafts_for_ad.html | 29 +- .../doc/review_assignment_summary.html | 7 +- .../templates/doc/review_request_summary.html | 9 + ietf/templates/doc/search/status_columns.html | 4 +- ietf/templates/doc/state_help.html | 5 +- .../doc/statement/new_statement.html | 18 + .../doc/statement/statement_template.md | 1 + .../doc/statement/upload_content.html | 23 + .../doc/status_change/last_call.html | 25 +- .../group/group_about_rendertest.html | 54 - ietf/templates/group/reviewer_overview.html | 143 +- ietf/templates/group/statements.html | 40 + ietf/templates/ietfauth/review_overview.html | 6 +- ietf/templates/meeting/materials.html | 36 + ietf/templates/meeting/proceedings.html | 32 +- ietf/templates/meeting/requests.html | 2 +- .../nomcom/reclassify_feedback_item.html | 103 ++ .../nomcom/view_feedback_nominee.html | 21 +- .../nomcom/view_feedback_pending.html | 15 +- .../templates/nomcom/view_feedback_topic.html | 21 +- .../nomcom/view_feedback_unrelated.html | 21 +- ietf/templates/review/unavailable_table.html | 51 +- ietf/templates/submit/manual_post_request.txt | 2 + package.json | 1 + playwright/package-lock.json | 1515 ++++++---------- playwright/package.json | 6 +- 92 files changed, 3726 insertions(+), 2513 deletions(-) create mode 100644 ietf/doc/management/commands/import_iab_statements.py create mode 100644 ietf/doc/migrations/0005_alter_docevent_type.py create mode 100644 ietf/doc/migrations/0006_statements.py create mode 100644 ietf/doc/tests_statement.py create mode 100644 ietf/doc/urls_statement.py create mode 100644 ietf/doc/views_statement.py create mode 100644 ietf/mailtrigger/migrations/0002_slidesubmitter.py create mode 100644 ietf/name/migrations/0004_statements.py create mode 100644 ietf/name/migrations/0005_feedbacktypename_schema.py create mode 100644 ietf/name/migrations/0006_feedbacktypename_data.py create mode 100644 ietf/static/js/upload_statement.js create mode 100644 ietf/templates/doc/document_statement.html create mode 100644 ietf/templates/doc/review_request_summary.html create mode 100644 ietf/templates/doc/statement/new_statement.html create mode 100644 ietf/templates/doc/statement/statement_template.md create mode 100644 ietf/templates/doc/statement/upload_content.html delete mode 100644 ietf/templates/group/group_about_rendertest.html create mode 100644 ietf/templates/group/statements.html create mode 100644 ietf/templates/nomcom/reclassify_feedback_item.html diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f4e1bac3c5..8e0cc2acff 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -137,9 +137,9 @@ jobs: echo "Running tests..." if [[ "x${{ github.event.inputs.ignoreLowerCoverage }}" == "xtrue" ]]; then echo "Lower coverage failures will be ignored." - ./ietf/manage.py test --settings=settings_postgrestest --ignore-lower-coverage + ./ietf/manage.py test --validate-html-harder --settings=settings_postgrestest --ignore-lower-coverage else - ./ietf/manage.py test --settings=settings_postgrestest + ./ietf/manage.py test --validate-html-harder --settings=settings_postgrestest fi coverage xml diff --git a/.github/workflows/ci-run-tests.yml b/.github/workflows/ci-run-tests.yml index e8e9fe324b..a2f2e3d952 100644 --- a/.github/workflows/ci-run-tests.yml +++ b/.github/workflows/ci-run-tests.yml @@ -45,7 +45,7 @@ jobs: exit 1 fi echo "Running tests..." - ./ietf/manage.py test --settings=settings_postgrestest + ./ietf/manage.py test --validate-html-harder --settings=settings_postgrestest coverage xml - name: Upload Coverage Results to Codecov diff --git a/.vscode/settings.json b/.vscode/settings.json index 3324e6cb76..b0ceba5c9d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,59 +1,60 @@ { - "taskExplorer.exclude": [ - "**/.vscode-test/**", - "**/bin/**", - "**/build/**", - "**/CompiledOutput/**", - "**/dist/**", - "**/doc/**", - "**/ext/**", - "**/out/**", - "**/output/**", - "**/packages/**", - "**/release/**", - "**/releases/**", - "**/samples/**", - "**/sdks/**", - "**/static/**", - "**/target/**", - "**/test/**", - "**/third_party/**", - "**/vendor/**", - "**/work/**", - "/workspace/bootstrap/nuget/MyGet.ps1" - ], - "taskExplorer.enableAnt": false, - "taskExplorer.enableAppPublisher": false, - "taskExplorer.enablePipenv": false, - "taskExplorer.enableBash": false, - "taskExplorer.enableBatch": false, - "taskExplorer.enableGradle": false, - "taskExplorer.enableGrunt": false, - "taskExplorer.enableGulp": false, - "taskExplorer.enablePerl": false, - "taskExplorer.enableMake": false, - "taskExplorer.enableMaven": false, - "taskExplorer.enableNsis": false, - "taskExplorer.enableNpm": false, - "taskExplorer.enablePowershell": false, - "taskExplorer.enablePython": false, - "taskExplorer.enableRuby": false, - "taskExplorer.enableTsc": false, - "taskExplorer.enableWorkspace": true, - "taskExplorer.enableExplorerView": false, - "taskExplorer.enableSideBar": true, - "search.exclude": { - "**/.yarn": true, - "**/.pnp.*": true - }, - "eslint.nodePath": ".yarn/sdks", - "eslint.validate": [ - "javascript", - "javascriptreact", - "vue" - ], - "python.linting.pylintArgs": ["--load-plugins", "pylint_django"], - "python.testing.pytestEnabled": false, - "python.testing.unittestEnabled": false, - "python.linting.enabled": true + "taskExplorer.exclude": [ + "**/.vscode-test/**", + "**/bin/**", + "**/build/**", + "**/CompiledOutput/**", + "**/dist/**", + "**/doc/**", + "**/ext/**", + "**/out/**", + "**/output/**", + "**/packages/**", + "**/release/**", + "**/releases/**", + "**/samples/**", + "**/sdks/**", + "**/static/**", + "**/target/**", + "**/test/**", + "**/third_party/**", + "**/vendor/**", + "**/work/**", + "/workspace/bootstrap/nuget/MyGet.ps1" + ], + "taskExplorer.enabledTasks": { + "ant": false, + "bash": false, + "batch": false, + "composer": false, + "gradle": false, + "grunt": false, + "gulp": false, + "make": false, + "maven": false, + "npm": false, + "perl": false, + "pipenv": false, + "powershell": false, + "python": false, + "ruby": false, + "tsc": false + }, + "taskExplorer.enableExplorerView": false, + "taskExplorer.enableSideBar": true, + "taskExplorer.showLastTasks": false, + "search.exclude": { + "**/.yarn": true, + "**/.pnp.*": true + }, + "eslint.nodePath": ".yarn/sdks", + "eslint.validate": [ + "javascript", + "javascriptreact", + "vue" + ], + "python.linting.pylintArgs": ["--load-plugins", "pylint_django"], + "python.testing.pytestEnabled": false, + "python.testing.unittestEnabled": false, + "python.linting.enabled": true } diff --git a/LICENSE b/LICENSE index aaed0ef57d..c180fa3f9f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2008-2022, The IETF Trust +Copyright (c) 2008-2023, The IETF Trust All rights reserved. Redistribution and use in source and binary forms, with or without @@ -26,4 +26,4 @@ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/dev/coverage-action/package-lock.json b/dev/coverage-action/package-lock.json index 62922b3422..01bd770348 100644 --- a/dev/coverage-action/package-lock.json +++ b/dev/coverage-action/package-lock.json @@ -17,12 +17,21 @@ "luxon": "3.3.0" }, "devDependencies": { - "eslint": "8.43.0", + "eslint": "8.45.0", "eslint-config-standard": "17.1.0", "eslint-plugin-import": "2.27.5", "eslint-plugin-node": "11.1.0", "eslint-plugin-promise": "6.1.1", - "npm-check-updates": "16.10.13" + "npm-check-updates": "16.10.16" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, "node_modules/@actions/core": { @@ -88,14 +97,14 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.1.tgz", + "integrity": "sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.2", + "espree": "^9.6.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -111,20 +120,14 @@ } }, "node_modules/@eslint/js": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.43.0.tgz", - "integrity": "sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==", + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", + "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@gar/promisify": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "dev": true - }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", @@ -292,14 +295,13 @@ } }, "node_modules/@npmcli/git": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.0.3.tgz", - "integrity": "sha512-8cXNkDIbnXPVbhXMmQ7/bklCAjtmPaXfI9aEM4iH+xSuEHINLMHhlfESvVwdqmHJRJkR48vNJTSUvoF6GRPSFA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.1.0.tgz", + "integrity": "sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ==", "dev": true, "dependencies": { "@npmcli/promise-spawn": "^6.0.0", "lru-cache": "^7.4.4", - "mkdirp": "^1.0.4", "npm-pick-manifest": "^8.0.0", "proc-log": "^3.0.0", "promise-inflight": "^1.0.1", @@ -321,9 +323,9 @@ } }, "node_modules/@npmcli/git/node_modules/which": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.0.tgz", - "integrity": "sha512-nla//68K9NU6yRiwDY/Q8aU6siKlSs64aEC7+IV56QoAuyQT2ovsJcgGYGyqMOmI/CGN1BOR6mM5EN0FBO+zyQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", "dev": true, "dependencies": { "isexe": "^2.0.0" @@ -351,20 +353,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/@npmcli/move-file": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", - "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "dev": true, - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/@npmcli/node-gyp": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", @@ -387,9 +375,9 @@ } }, "node_modules/@npmcli/promise-spawn/node_modules/which": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.0.tgz", - "integrity": "sha512-nla//68K9NU6yRiwDY/Q8aU6siKlSs64aEC7+IV56QoAuyQT2ovsJcgGYGyqMOmI/CGN1BOR6mM5EN0FBO+zyQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", "dev": true, "dependencies": { "isexe": "^2.0.0" @@ -402,9 +390,9 @@ } }, "node_modules/@npmcli/run-script": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-6.0.0.tgz", - "integrity": "sha512-ql+AbRur1TeOdl1FY+RAwGW9fcr4ZwiVKabdvm93mujGREVuVLbdkXRJDrkTXSdCjaxYydr1wlA2v67jxWG5BQ==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-6.0.2.tgz", + "integrity": "sha512-NCcr1uQo1k5U+SYlnIrbAh3cxy+OQT1VtqiAbxdymSlptbzBb62AjH2xXgjNCoP073hoa1CfCAcwoZ8k96C4nA==", "dev": true, "dependencies": { "@npmcli/node-gyp": "^3.0.0", @@ -418,9 +406,9 @@ } }, "node_modules/@npmcli/run-script/node_modules/which": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.0.tgz", - "integrity": "sha512-nla//68K9NU6yRiwDY/Q8aU6siKlSs64aEC7+IV56QoAuyQT2ovsJcgGYGyqMOmI/CGN1BOR6mM5EN0FBO+zyQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", "dev": true, "dependencies": { "isexe": "^2.0.0" @@ -584,15 +572,40 @@ "node": ">=12" } }, + "node_modules/@sigstore/bundle": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-1.0.0.tgz", + "integrity": "sha512-yLvrWDOh6uMOUlFCTJIZEnwOT9Xte7NPXUqVexEKGSF5XtBAuSg5du0kn3dRR0p47a4ah10Y0mNt8+uyeQXrBQ==", + "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.2.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/@sigstore/protobuf-specs": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.1.0.tgz", - "integrity": "sha512-a31EnjuIDSX8IXBUib3cYLDRlPMU36AWX4xS8ysLaNu4ZzUesDiPt83pgrW2X1YLMe5L2HbDyaKK5BrL4cNKaQ==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.0.tgz", + "integrity": "sha512-8ZhZKAVfXjIspDWwm3D3Kvj0ddbJ0HqDZ/pOs5cx88HpT8mVsotFrg7H1UMnXOuDHz6Zykwxn4mxG3QLuN+RUg==", "dev": true, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/@sigstore/tuf": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-1.0.3.tgz", + "integrity": "sha512-2bRovzs0nJZFlCN3rXirE4gwxCn97JNjMmwpecqlbgV9WcxX7WRuIrgzx/X7Ib7MYRbyUTpBYE0s2x6AmZXnlg==", + "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.2.0", + "tuf-js": "^1.1.7" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/@sindresorhus/is": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.3.0.tgz", @@ -626,13 +639,23 @@ "node": ">= 10" } }, - "node_modules/@tufjs/models": { + "node_modules/@tufjs/canonical-json": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-1.0.0.tgz", - "integrity": "sha512-RRMu4uMxWnZlxaIBxahSb2IssFZiu188sndesZflWOe1cA/qUqtemSIoBWbuVKPvvdktapImWNnKpBcc+VrCQw==", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-1.0.0.tgz", + "integrity": "sha512-QTnf++uxunWvG2z3UFNzAoQPHxnSXOwtaI3iJ+AohhV+5vONuArPjJE7aPXPVXfXJsqrVbZBu9b81AJoSd09IQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-1.0.4.tgz", + "integrity": "sha512-qaGV9ltJP0EO25YfFUPhxRVK0evXFIAGicsVXuRim4Ed9cjPxYhNnNJ49SFmbeLgtxpslIkX317IgpfcHPVj/A==", "dev": true, "dependencies": { - "minimatch": "^6.1.0" + "@tufjs/canonical-json": "1.0.0", + "minimatch": "^9.0.0" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -648,15 +671,15 @@ } }, "node_modules/@tufjs/models/node_modules/minimatch": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-6.2.0.tgz", - "integrity": "sha512-sauLxniAmvnhhRjFwPNnJKaPFYyddAgbYdeUpHULtCT/GhzdCx/MDNy+Y40lBxTQUrMzDE8e0S43Z5uqfO0REg==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -680,9 +703,9 @@ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1041,21 +1064,20 @@ } }, "node_modules/cacache": { - "version": "17.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.0.4.tgz", - "integrity": "sha512-Z/nL3gU+zTUjz5pCA5vVjYM8pmaw2kxM7JEiE0fv3w77Wj+sFbi70CrBruUWH0uNcEdvLDixFpgA2JM4F4DBjA==", + "version": "17.1.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.1.3.tgz", + "integrity": "sha512-jAdjGxmPxZh0IipMdR7fK/4sDSrHMLUV0+GvVUsjwyGNKHsh79kW/otg+GkbXwl6Uzvy9wsvHOX4nUoWldeZMg==", "dev": true, "dependencies": { "@npmcli/fs": "^3.1.0", "fs-minipass": "^3.0.0", - "glob": "^8.0.1", + "glob": "^10.2.2", "lru-cache": "^7.7.1", - "minipass": "^4.0.0", + "minipass": "^5.0.0", "minipass-collect": "^1.0.2", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", "ssri": "^10.0.0", "tar": "^6.1.11", "unique-filename": "^3.0.0" @@ -1074,31 +1096,34 @@ } }, "node_modules/cacache/node_modules/fs-minipass": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.1.tgz", - "integrity": "sha512-MhaJDcFRTuLidHrIttu0RDGyyXs/IYHVmlcxfLAEFIWjc1vdLAkdwT7Ace2u7DbitWC0toKMl5eJZRYNVreIMw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.2.tgz", + "integrity": "sha512-2GAfyfoaCDRrM6jaOS3UsBts8yJ55VioXdWcOL7dK9zdAuKT71+WBA4ifnNYqVjYv+4SsPxjK0JT4yIIn4cA/g==", "dev": true, "dependencies": { - "minipass": "^4.0.0" + "minipass": "^5.0.0" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/cacache/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "version": "10.3.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.3.tgz", + "integrity": "sha512-92vPiMb/iqpmEgsOoIDvTjc50wf9CCCvMzsi6W0JLPeUKE8TWP1a73PgqSrqy7iAZxaSD1YdzU7QZR5LF51MJw==", "dev": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "foreground-child": "^3.1.0", + "jackspeak": "^2.0.3", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/cjs/src/bin.js" }, "engines": { - "node": ">=12" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -1114,21 +1139,24 @@ } }, "node_modules/cacache/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/cacache/node_modules/minipass": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", - "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true, "engines": { "node": ">=8" @@ -1718,15 +1746,15 @@ } }, "node_modules/eslint": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.43.0.tgz", - "integrity": "sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==", + "version": "8.45.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.45.0.tgz", + "integrity": "sha512-pd8KSxiQpdYRfYa9Wufvdoct3ZPQQuVuU5O6scNgMuOMYuxvH0IGaYK0wUFjo4UYYQQCUndlXiMbnxopwvvTiw==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.43.0", + "@eslint/eslintrc": "^2.1.0", + "@eslint/js": "8.44.0", "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -1738,7 +1766,7 @@ "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.2.0", "eslint-visitor-keys": "^3.4.1", - "espree": "^9.5.2", + "espree": "^9.6.0", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -1748,7 +1776,6 @@ "globals": "^13.19.0", "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", @@ -1758,9 +1785,8 @@ "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" }, "bin": { @@ -2133,12 +2159,12 @@ } }, "node_modules/espree": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", - "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "dependencies": { - "acorn": "^8.8.0", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.4.1" }, @@ -2191,6 +2217,12 @@ "node": ">=0.10.0" } }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "dev": true + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2222,7 +2254,7 @@ "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, "node_modules/fast-memoize": { @@ -2852,12 +2884,12 @@ } }, "node_modules/ignore-walk": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.1.tgz", - "integrity": "sha512-/c8MxUAqpRccq+LyDOecwF+9KqajueJHh8fz7g3YqjMZt+NSfJzx05zrKiXwa2sKwFCzaiZ5qUVfRj0pmxixEA==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.3.tgz", + "integrity": "sha512-C7FfFoTA+bI10qfeydT8aZbvr91vAEU+2W5BZUlzPec47oNb07SsOfwYrtxuvOYdUApPP/Qlh4DtAO51Ekk2QA==", "dev": true, "dependencies": { - "minimatch": "^6.1.6" + "minimatch": "^9.0.0" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -2873,15 +2905,15 @@ } }, "node_modules/ignore-walk/node_modules/minimatch": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-6.2.0.tgz", - "integrity": "sha512-sauLxniAmvnhhRjFwPNnJKaPFYyddAgbYdeUpHULtCT/GhzdCx/MDNy+Y40lBxTQUrMzDE8e0S43Z5uqfO0REg==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -2930,12 +2962,6 @@ "node": ">=8" } }, - "node_modules/infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true - }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -2951,9 +2977,9 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ini": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.0.tgz", - "integrity": "sha512-HLR38RSF2iulAzc3I/sma4CoYxQP844rPYCNfzGDOHqa/YqVlwuuZgBx6M50/X8dKgzk0cm1qRg3+47mK2N+cQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", "dev": true, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -3532,100 +3558,29 @@ } }, "node_modules/make-fetch-happen": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", - "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", + "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", "dev": true, "dependencies": { "agentkeepalive": "^4.2.1", - "cacache": "^16.1.0", - "http-cache-semantics": "^4.1.0", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", "is-lambda": "^1.0.1", "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^2.0.3", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^0.6.3", "promise-retry": "^2.0.1", "socks-proxy-agent": "^7.0.0", - "ssri": "^9.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/@npmcli/fs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", - "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", - "dev": true, - "dependencies": { - "@gar/promisify": "^1.1.3", - "semver": "^7.3.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/cacache": { - "version": "16.1.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", - "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", - "dev": true, - "dependencies": { - "@npmcli/fs": "^2.1.0", - "@npmcli/move-file": "^2.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "glob": "^8.0.1", - "infer-owner": "^1.0.4", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11", - "unique-filename": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "ssri": "^10.0.0" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/make-fetch-happen/node_modules/lru-cache": { @@ -3637,52 +3592,13 @@ "node": ">=12" } }, - "node_modules/make-fetch-happen/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-fetch-happen/node_modules/ssri": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", - "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", - "dev": true, - "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/unique-filename": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", - "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", - "dev": true, - "dependencies": { - "unique-slug": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/unique-slug": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", - "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", + "node_modules/make-fetch-happen/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4" - }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=8" } }, "node_modules/merge2": { @@ -3759,22 +3675,31 @@ } }, "node_modules/minipass-fetch": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", - "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.3.tgz", + "integrity": "sha512-n5ITsTkDqYkYJZjcRWzZt9qnZKCT7nKCosJhHoj7S7zD+BP4jVbWs+odsniw5TA3E0sLomhTKOKjF86wf11PuQ==", "dev": true, "dependencies": { - "minipass": "^3.1.6", + "minipass": "^5.0.0", "minipass-sized": "^1.0.3", "minizlib": "^2.1.2" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" }, "optionalDependencies": { "encoding": "^0.1.13" } }, + "node_modules/minipass-fetch/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/minipass-flush": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", @@ -3889,15 +3814,16 @@ } }, "node_modules/node-gyp": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.3.1.tgz", - "integrity": "sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==", + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.0.tgz", + "integrity": "sha512-dMXsYP6gc9rRbejLXmTbVRYjAHw7ppswsKyMxuxJxxOHzluIO1rGp9TOQgjFJ+2MCqcOcQTOPB/8Xwhr+7s4Eg==", "dev": true, "dependencies": { "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", "glob": "^7.1.4", "graceful-fs": "^4.2.6", - "make-fetch-happen": "^10.0.3", + "make-fetch-happen": "^11.0.3", "nopt": "^6.0.0", "npmlog": "^6.0.0", "rimraf": "^3.0.2", @@ -4049,12 +3975,12 @@ } }, "node_modules/npm-check-updates": { - "version": "16.10.13", - "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-16.10.13.tgz", - "integrity": "sha512-ZsWrtHnaMkcxAaCtDFEr8i7jgM0Bz2AYsnsJlmxISgltG8ie43bWC6G9icxFKfYSLeJJtcj/Yw1Mq5f8GL2F3g==", + "version": "16.10.16", + "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-16.10.16.tgz", + "integrity": "sha512-d8mNYce/l8o5RHPE5ZUp2P1zj9poI7KWQCh5AsTIP3EhicONEhc63mLQQv4/nkCsMb3wCrikx6YOo4BOwN4+1w==", "dev": true, "dependencies": { - "chalk": "^5.2.0", + "chalk": "^5.3.0", "cli-table3": "^0.6.3", "commander": "^10.0.0", "fast-memoize": "^2.5.2", @@ -4063,25 +3989,25 @@ "get-stdin": "^8.0.0", "globby": "^11.0.4", "hosted-git-info": "^5.1.0", - "ini": "^4.0.0", + "ini": "^4.1.1", "js-yaml": "^4.1.0", "json-parse-helpfulerror": "^1.0.3", "jsonlines": "^0.1.1", "lodash": "^4.17.21", - "minimatch": "^9.0.0", + "minimatch": "^9.0.3", "p-map": "^4.0.0", - "pacote": "15.1.1", + "pacote": "15.2.0", "parse-github-url": "^1.0.2", "progress": "^2.0.3", "prompts-ncu": "^3.0.0", - "rc-config-loader": "^4.1.2", + "rc-config-loader": "^4.1.3", "remote-git-tags": "^3.0.0", - "rimraf": "^5.0.0", - "semver": "^7.4.0", + "rimraf": "^5.0.1", + "semver": "^7.5.3", "semver-utils": "^1.1.4", "source-map-support": "^0.5.21", "spawn-please": "^2.0.1", - "strip-json-comments": "^5.0.0", + "strip-json-comments": "^5.0.1", "untildify": "^4.0.0", "update-notifier": "^6.0.2" }, @@ -4103,9 +4029,9 @@ } }, "node_modules/npm-check-updates/node_modules/chalk": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", - "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -4137,9 +4063,9 @@ } }, "node_modules/npm-check-updates/node_modules/minimatch": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", - "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -4179,9 +4105,9 @@ } }, "node_modules/npm-check-updates/node_modules/strip-json-comments": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.0.tgz", - "integrity": "sha512-V1LGY4UUo0jgwC+ELQ2BNWfPa17TIuwBLg+j1AA/9RPzKINl1lhxVEu2r+ZTTO8aetIsUzE5Qj6LMSBkoGYKKw==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.1.tgz", + "integrity": "sha512-0fk9zBqO67Nq5M/m45qHCJxylV/DhBlIOVExqgOMiCCrzrhU6tCibRXNqE3jwJLftzE9SNuZtYbpzcO+i9FiKw==", "dev": true, "engines": { "node": ">=14.16" @@ -4191,9 +4117,9 @@ } }, "node_modules/npm-install-checks": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.0.0.tgz", - "integrity": "sha512-SBU9oFglRVZnfElwAtF14NivyulDqF1VKqqwNsFW9HDcbHMAPHpRSsVFgKuwFGq/hVvWZExz62Th0kvxn/XE7Q==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.1.1.tgz", + "integrity": "sha512-dH3GmQL4vsPtld59cOn8uY0iOqRmqKvV+DLGwNXV/Q7MDgD2QfOADWd/mFXcIE5LVhYYGjA3baz6W9JneqnuCw==", "dev": true, "dependencies": { "semver": "^7.1.1" @@ -4203,9 +4129,9 @@ } }, "node_modules/npm-normalize-package-bin": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.0.tgz", - "integrity": "sha512-g+DPQSkusnk7HYXr75NtzkIP4+N81i3RPsGFidF3DzHd9MT9wWngmqoeg/fnHFz5MNdtG4w03s+QnhewSLTT2Q==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", "dev": true, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -4260,9 +4186,9 @@ } }, "node_modules/npm-pick-manifest": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-8.0.1.tgz", - "integrity": "sha512-mRtvlBjTsJvfCCdmPtiu2bdlx8d/KXtF7yNXNWe7G0Z36qWA9Ny5zXsI2PfBZEv7SXgoxTmNaTzGSbbzDZChoA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-8.0.2.tgz", + "integrity": "sha512-1dKY+86/AIiq1tkKVD3l0WI+Gd3vkknVGAggsFeBkTvbhMQ1OND/LKkYv4JtXPKUJ8bOTCyLiqEg2P6QNdK+Gg==", "dev": true, "dependencies": { "npm-install-checks": "^6.0.0", @@ -4275,13 +4201,13 @@ } }, "node_modules/npm-registry-fetch": { - "version": "14.0.3", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-14.0.3.tgz", - "integrity": "sha512-YaeRbVNpnWvsGOjX2wk5s85XJ7l1qQBGAp724h8e2CZFFhMSuw9enom7K1mWVUtvXO1uUSFIAPofQK0pPN0ZcA==", + "version": "14.0.5", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-14.0.5.tgz", + "integrity": "sha512-kIDMIo4aBm6xg7jOttupWZamsZRkAqMqwqqbVXnUqstY5+tapvv6bkH/qMR76jdgV+YljEUCyWx3hRYMrJiAgA==", "dev": true, "dependencies": { "make-fetch-happen": "^11.0.0", - "minipass": "^4.0.0", + "minipass": "^5.0.0", "minipass-fetch": "^3.0.0", "minipass-json-stream": "^1.0.1", "minizlib": "^2.1.2", @@ -4292,67 +4218,15 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm-registry-fetch/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/npm-registry-fetch/node_modules/make-fetch-happen": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.0.3.tgz", - "integrity": "sha512-oPLh5m10lRNNZDjJ2kP8UpboUx2uFXVaVweVe/lWut4iHWcQEmfqSVJt2ihZsFI8HbpwyyocaXbCAWf0g1ukIA==", - "dev": true, - "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^17.0.0", - "http-cache-semantics": "^4.1.1", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^4.0.0", - "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^10.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/npm-registry-fetch/node_modules/minipass": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", - "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true, "engines": { "node": ">=8" } }, - "node_modules/npm-registry-fetch/node_modules/minipass-fetch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.1.tgz", - "integrity": "sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==", - "dev": true, - "dependencies": { - "minipass": "^4.0.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, "node_modules/npmlog": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", @@ -4434,17 +4308,17 @@ } }, "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" }, "engines": { "node": ">= 0.8.0" @@ -4523,9 +4397,9 @@ } }, "node_modules/pacote": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.1.1.tgz", - "integrity": "sha512-eeqEe77QrA6auZxNHIp+1TzHQ0HBKf5V6c8zcaYZ134EJe1lCi+fjXATkNiEEfbG+e50nu02GLvUtmZcGOYabQ==", + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.2.0.tgz", + "integrity": "sha512-rJVZeIwHTUta23sIZgEIM62WYwbmGbThdbnkt81ravBplQv+HjyroqnLRNH2+sLJHcGZmLRmhPwACqhfTcOmnA==", "dev": true, "dependencies": { "@npmcli/git": "^4.0.0", @@ -4534,7 +4408,7 @@ "@npmcli/run-script": "^6.0.0", "cacache": "^17.0.0", "fs-minipass": "^3.0.0", - "minipass": "^4.0.0", + "minipass": "^5.0.0", "npm-package-arg": "^10.0.0", "npm-packlist": "^7.0.0", "npm-pick-manifest": "^8.0.0", @@ -4543,7 +4417,7 @@ "promise-retry": "^2.0.1", "read-package-json": "^6.0.0", "read-package-json-fast": "^3.0.0", - "sigstore": "^1.0.0", + "sigstore": "^1.3.0", "ssri": "^10.0.0", "tar": "^6.1.11" }, @@ -4555,21 +4429,21 @@ } }, "node_modules/pacote/node_modules/fs-minipass": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.1.tgz", - "integrity": "sha512-MhaJDcFRTuLidHrIttu0RDGyyXs/IYHVmlcxfLAEFIWjc1vdLAkdwT7Ace2u7DbitWC0toKMl5eJZRYNVreIMw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.2.tgz", + "integrity": "sha512-2GAfyfoaCDRrM6jaOS3UsBts8yJ55VioXdWcOL7dK9zdAuKT71+WBA4ifnNYqVjYv+4SsPxjK0JT4yIIn4cA/g==", "dev": true, "dependencies": { - "minipass": "^4.0.0" + "minipass": "^5.0.0" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/pacote/node_modules/minipass": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", - "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true, "engines": { "node": ">=8" @@ -4632,13 +4506,13 @@ "dev": true }, "node_modules/path-scurry": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.9.2.tgz", - "integrity": "sha512-qSDLy2aGFPm8i4rsbHd4MNyTcrzHFsLQykrtbuGRknZZCBBVXSv2tSCDN2Cg6Rt/GFRw8GoW9y9Ecw5rIPG1sg==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", "dev": true, "dependencies": { - "lru-cache": "^9.1.1", - "minipass": "^5.0.0 || ^6.0.2" + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -4823,9 +4697,9 @@ } }, "node_modules/rc-config-loader": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.1.2.tgz", - "integrity": "sha512-qKTnVWFl9OQYKATPzdfaZIbTxcHziQl92zYSxYC6umhOqyAsoj8H8Gq/+aFjAso68sBdjTz3A7omqeAkkF1MWg==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.1.3.tgz", + "integrity": "sha512-kD7FqML7l800i6pS6pvLyIE2ncbk9Du8Q0gp/4hMPhJU6ZxApkoLcGD8ZeqgiAlfwZ6BlETq6qqe+12DUL207w==", "dev": true, "dependencies": { "debug": "^4.3.4", @@ -4862,12 +4736,12 @@ } }, "node_modules/read-package-json": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.0.tgz", - "integrity": "sha512-b/9jxWJ8EwogJPpv99ma+QwtqB7FSl3+V6UXS7Aaay8/5VwMY50oIFooY1UKXMWpfNCM6T/PoGqa5GD1g9xf9w==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.4.tgz", + "integrity": "sha512-AEtWXYfopBj2z5N5PbkAOeNHRPUg5q+Nen7QLxV8M2zJq1ym6/lCz3fYNTCXe19puu2d06jfHhrP7v/S2PtMMw==", "dev": true, "dependencies": { - "glob": "^8.0.1", + "glob": "^10.2.2", "json-parse-even-better-errors": "^3.0.0", "normalize-package-data": "^5.0.0", "npm-normalize-package-bin": "^3.0.0" @@ -4899,34 +4773,49 @@ } }, "node_modules/read-package-json/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "version": "10.3.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.3.tgz", + "integrity": "sha512-92vPiMb/iqpmEgsOoIDvTjc50wf9CCCvMzsi6W0JLPeUKE8TWP1a73PgqSrqy7iAZxaSD1YdzU7QZR5LF51MJw==", "dev": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "foreground-child": "^3.1.0", + "jackspeak": "^2.0.3", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/cjs/src/bin.js" }, "engines": { - "node": ">=12" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/read-package-json/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/read-package-json/node_modules/minipass": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.2.tgz", + "integrity": "sha512-eL79dXrE1q9dBbDCLg7xfn/vl7MS4F1gvJAgjJrQli/jbQWdUttuVawphqpffoIYfRdq78LHx6GP4bU/EQ2ATA==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" } }, "node_modules/readable-stream": { @@ -5159,9 +5048,9 @@ "optional": true }, "node_modules/semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -5239,81 +5128,21 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "node_modules/sigstore": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.1.1.tgz", - "integrity": "sha512-4hR3tPP1y59YWlaoAgAWFVZ7srTjNWOrrpkQXWu05qP0BvwFYyt3K3l848+IHo+mKhkOzGcNDf7ktASXLEPC+A==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.8.0.tgz", + "integrity": "sha512-ogU8qtQ3VFBawRJ8wjsBEX/vIFeHuGs1fm4jZtjWQwjo8pfAt7T/rh+udlAN4+QUe0IzA8qRSc/YZ7dHP6kh+w==", "dev": true, "dependencies": { - "@sigstore/protobuf-specs": "^0.1.0", - "make-fetch-happen": "^11.0.1", - "tuf-js": "^1.0.0" + "@sigstore/bundle": "^1.0.0", + "@sigstore/protobuf-specs": "^0.2.0", + "@sigstore/tuf": "^1.0.3", + "make-fetch-happen": "^11.0.1" }, "bin": { "sigstore": "bin/sigstore.js" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/sigstore/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/sigstore/node_modules/make-fetch-happen": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.0.3.tgz", - "integrity": "sha512-oPLh5m10lRNNZDjJ2kP8UpboUx2uFXVaVweVe/lWut4iHWcQEmfqSVJt2ihZsFI8HbpwyyocaXbCAWf0g1ukIA==", - "dev": true, - "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^17.0.0", - "http-cache-semantics": "^4.1.1", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^4.0.0", - "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^10.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/sigstore/node_modules/minipass": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", - "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/sigstore/node_modules/minipass-fetch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.1.tgz", - "integrity": "sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==", - "dev": true, - "dependencies": { - "minipass": "^4.0.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/simple-concat": { @@ -5462,21 +5291,21 @@ "dev": true }, "node_modules/ssri": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.1.tgz", - "integrity": "sha512-WVy6di9DlPOeBWEjMScpNipeSX2jIZBGEn5Uuo8Q7aIuFEuDX0pw8RxcOjlD1TWP4obi24ki7m/13+nFpcbXrw==", + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.4.tgz", + "integrity": "sha512-12+IR2CB2C28MMAw0Ncqwj5QbTcs0nGIhgJzYWzDkb21vWmfNI83KS4f3Ci6GI98WreIfG7o9UXp3C0qbpA8nQ==", "dev": true, "dependencies": { - "minipass": "^4.0.0" + "minipass": "^5.0.0" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/ssri/node_modules/minipass": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", - "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true, "engines": { "node": ">=8" @@ -5689,77 +5518,17 @@ "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" }, "node_modules/tuf-js": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.1.tgz", - "integrity": "sha512-WTp382/PR96k0dI4GD5RdiRhgOU0rAC7+lnoih/5pZg3cyb3aNMqDozleEEWwyfT3+FOg7Qz9JU3n6A44tLSHw==", - "dev": true, - "dependencies": { - "@tufjs/models": "1.0.0", - "make-fetch-happen": "^11.0.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/tuf-js/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/tuf-js/node_modules/make-fetch-happen": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.0.3.tgz", - "integrity": "sha512-oPLh5m10lRNNZDjJ2kP8UpboUx2uFXVaVweVe/lWut4iHWcQEmfqSVJt2ihZsFI8HbpwyyocaXbCAWf0g1ukIA==", - "dev": true, - "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^17.0.0", - "http-cache-semantics": "^4.1.1", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^4.0.0", - "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^10.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/tuf-js/node_modules/minipass": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", - "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/tuf-js/node_modules/minipass-fetch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.1.tgz", - "integrity": "sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.7.tgz", + "integrity": "sha512-i3P9Kgw3ytjELUfpuKVDNBJvk4u5bXL6gskv572mcevPbSKCV3zt3djhmlEQ65yERjIbOSncy7U4cQJaB1CBCg==", "dev": true, "dependencies": { - "minipass": "^4.0.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" + "@tufjs/models": "1.0.4", + "debug": "^4.3.4", + "make-fetch-happen": "^11.1.1" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" } }, "node_modules/tunnel": { @@ -6107,15 +5876,6 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", @@ -6261,6 +6021,12 @@ } }, "dependencies": { + "@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true + }, "@actions/core": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.10.0.tgz", @@ -6312,14 +6078,14 @@ "dev": true }, "@eslint/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.1.tgz", + "integrity": "sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.2", + "espree": "^9.6.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -6329,15 +6095,9 @@ } }, "@eslint/js": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.43.0.tgz", - "integrity": "sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==", - "dev": true - }, - "@gar/promisify": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", + "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==", "dev": true }, "@humanwhocodes/config-array": { @@ -6463,14 +6223,13 @@ } }, "@npmcli/git": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.0.3.tgz", - "integrity": "sha512-8cXNkDIbnXPVbhXMmQ7/bklCAjtmPaXfI9aEM4iH+xSuEHINLMHhlfESvVwdqmHJRJkR48vNJTSUvoF6GRPSFA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.1.0.tgz", + "integrity": "sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ==", "dev": true, "requires": { "@npmcli/promise-spawn": "^6.0.0", "lru-cache": "^7.4.4", - "mkdirp": "^1.0.4", "npm-pick-manifest": "^8.0.0", "proc-log": "^3.0.0", "promise-inflight": "^1.0.1", @@ -6486,9 +6245,9 @@ "dev": true }, "which": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.0.tgz", - "integrity": "sha512-nla//68K9NU6yRiwDY/Q8aU6siKlSs64aEC7+IV56QoAuyQT2ovsJcgGYGyqMOmI/CGN1BOR6mM5EN0FBO+zyQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -6506,16 +6265,6 @@ "npm-normalize-package-bin": "^3.0.0" } }, - "@npmcli/move-file": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", - "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", - "dev": true, - "requires": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - } - }, "@npmcli/node-gyp": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", @@ -6532,9 +6281,9 @@ }, "dependencies": { "which": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.0.tgz", - "integrity": "sha512-nla//68K9NU6yRiwDY/Q8aU6siKlSs64aEC7+IV56QoAuyQT2ovsJcgGYGyqMOmI/CGN1BOR6mM5EN0FBO+zyQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -6543,9 +6292,9 @@ } }, "@npmcli/run-script": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-6.0.0.tgz", - "integrity": "sha512-ql+AbRur1TeOdl1FY+RAwGW9fcr4ZwiVKabdvm93mujGREVuVLbdkXRJDrkTXSdCjaxYydr1wlA2v67jxWG5BQ==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-6.0.2.tgz", + "integrity": "sha512-NCcr1uQo1k5U+SYlnIrbAh3cxy+OQT1VtqiAbxdymSlptbzBb62AjH2xXgjNCoP073hoa1CfCAcwoZ8k96C4nA==", "dev": true, "requires": { "@npmcli/node-gyp": "^3.0.0", @@ -6556,9 +6305,9 @@ }, "dependencies": { "which": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.0.tgz", - "integrity": "sha512-nla//68K9NU6yRiwDY/Q8aU6siKlSs64aEC7+IV56QoAuyQT2ovsJcgGYGyqMOmI/CGN1BOR6mM5EN0FBO+zyQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", "dev": true, "requires": { "isexe": "^2.0.0" @@ -6702,12 +6451,31 @@ "config-chain": "^1.1.11" } }, + "@sigstore/bundle": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-1.0.0.tgz", + "integrity": "sha512-yLvrWDOh6uMOUlFCTJIZEnwOT9Xte7NPXUqVexEKGSF5XtBAuSg5du0kn3dRR0p47a4ah10Y0mNt8+uyeQXrBQ==", + "dev": true, + "requires": { + "@sigstore/protobuf-specs": "^0.2.0" + } + }, "@sigstore/protobuf-specs": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.1.0.tgz", - "integrity": "sha512-a31EnjuIDSX8IXBUib3cYLDRlPMU36AWX4xS8ysLaNu4ZzUesDiPt83pgrW2X1YLMe5L2HbDyaKK5BrL4cNKaQ==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.0.tgz", + "integrity": "sha512-8ZhZKAVfXjIspDWwm3D3Kvj0ddbJ0HqDZ/pOs5cx88HpT8mVsotFrg7H1UMnXOuDHz6Zykwxn4mxG3QLuN+RUg==", "dev": true }, + "@sigstore/tuf": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-1.0.3.tgz", + "integrity": "sha512-2bRovzs0nJZFlCN3rXirE4gwxCn97JNjMmwpecqlbgV9WcxX7WRuIrgzx/X7Ib7MYRbyUTpBYE0s2x6AmZXnlg==", + "dev": true, + "requires": { + "@sigstore/protobuf-specs": "^0.2.0", + "tuf-js": "^1.1.7" + } + }, "@sindresorhus/is": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.3.0.tgz", @@ -6729,13 +6497,20 @@ "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", "dev": true }, - "@tufjs/models": { + "@tufjs/canonical-json": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-1.0.0.tgz", - "integrity": "sha512-RRMu4uMxWnZlxaIBxahSb2IssFZiu188sndesZflWOe1cA/qUqtemSIoBWbuVKPvvdktapImWNnKpBcc+VrCQw==", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-1.0.0.tgz", + "integrity": "sha512-QTnf++uxunWvG2z3UFNzAoQPHxnSXOwtaI3iJ+AohhV+5vONuArPjJE7aPXPVXfXJsqrVbZBu9b81AJoSd09IQ==", + "dev": true + }, + "@tufjs/models": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-1.0.4.tgz", + "integrity": "sha512-qaGV9ltJP0EO25YfFUPhxRVK0evXFIAGicsVXuRim4Ed9cjPxYhNnNJ49SFmbeLgtxpslIkX317IgpfcHPVj/A==", "dev": true, "requires": { - "minimatch": "^6.1.0" + "@tufjs/canonical-json": "1.0.0", + "minimatch": "^9.0.0" }, "dependencies": { "brace-expansion": { @@ -6748,9 +6523,9 @@ } }, "minimatch": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-6.2.0.tgz", - "integrity": "sha512-sauLxniAmvnhhRjFwPNnJKaPFYyddAgbYdeUpHULtCT/GhzdCx/MDNy+Y40lBxTQUrMzDE8e0S43Z5uqfO0REg==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -6776,9 +6551,9 @@ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "dev": true }, "acorn-jsx": { @@ -7037,21 +6812,20 @@ } }, "cacache": { - "version": "17.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.0.4.tgz", - "integrity": "sha512-Z/nL3gU+zTUjz5pCA5vVjYM8pmaw2kxM7JEiE0fv3w77Wj+sFbi70CrBruUWH0uNcEdvLDixFpgA2JM4F4DBjA==", + "version": "17.1.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.1.3.tgz", + "integrity": "sha512-jAdjGxmPxZh0IipMdR7fK/4sDSrHMLUV0+GvVUsjwyGNKHsh79kW/otg+GkbXwl6Uzvy9wsvHOX4nUoWldeZMg==", "dev": true, "requires": { "@npmcli/fs": "^3.1.0", "fs-minipass": "^3.0.0", - "glob": "^8.0.1", + "glob": "^10.2.2", "lru-cache": "^7.7.1", - "minipass": "^4.0.0", + "minipass": "^5.0.0", "minipass-collect": "^1.0.2", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", "ssri": "^10.0.0", "tar": "^6.1.11", "unique-filename": "^3.0.0" @@ -7067,25 +6841,25 @@ } }, "fs-minipass": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.1.tgz", - "integrity": "sha512-MhaJDcFRTuLidHrIttu0RDGyyXs/IYHVmlcxfLAEFIWjc1vdLAkdwT7Ace2u7DbitWC0toKMl5eJZRYNVreIMw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.2.tgz", + "integrity": "sha512-2GAfyfoaCDRrM6jaOS3UsBts8yJ55VioXdWcOL7dK9zdAuKT71+WBA4ifnNYqVjYv+4SsPxjK0JT4yIIn4cA/g==", "dev": true, "requires": { - "minipass": "^4.0.0" + "minipass": "^5.0.0" } }, "glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "version": "10.3.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.3.tgz", + "integrity": "sha512-92vPiMb/iqpmEgsOoIDvTjc50wf9CCCvMzsi6W0JLPeUKE8TWP1a73PgqSrqy7iAZxaSD1YdzU7QZR5LF51MJw==", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "foreground-child": "^3.1.0", + "jackspeak": "^2.0.3", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" } }, "lru-cache": { @@ -7095,18 +6869,18 @@ "dev": true }, "minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "requires": { "brace-expansion": "^2.0.1" } }, "minipass": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", - "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true } } @@ -7534,15 +7308,15 @@ "dev": true }, "eslint": { - "version": "8.43.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.43.0.tgz", - "integrity": "sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==", + "version": "8.45.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.45.0.tgz", + "integrity": "sha512-pd8KSxiQpdYRfYa9Wufvdoct3ZPQQuVuU5O6scNgMuOMYuxvH0IGaYK0wUFjo4UYYQQCUndlXiMbnxopwvvTiw==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.43.0", + "@eslint/eslintrc": "^2.1.0", + "@eslint/js": "8.44.0", "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -7554,7 +7328,7 @@ "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.2.0", "eslint-visitor-keys": "^3.4.1", - "espree": "^9.5.2", + "espree": "^9.6.0", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -7564,7 +7338,6 @@ "globals": "^13.19.0", "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", @@ -7574,9 +7347,8 @@ "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" }, "dependencies": { @@ -7828,12 +7600,12 @@ "dev": true }, "espree": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", - "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "requires": { - "acorn": "^8.8.0", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.4.1" } @@ -7868,6 +7640,12 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, + "exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "dev": true + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -7896,7 +7674,7 @@ "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, "fast-memoize": { @@ -8351,12 +8129,12 @@ "dev": true }, "ignore-walk": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.1.tgz", - "integrity": "sha512-/c8MxUAqpRccq+LyDOecwF+9KqajueJHh8fz7g3YqjMZt+NSfJzx05zrKiXwa2sKwFCzaiZ5qUVfRj0pmxixEA==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.3.tgz", + "integrity": "sha512-C7FfFoTA+bI10qfeydT8aZbvr91vAEU+2W5BZUlzPec47oNb07SsOfwYrtxuvOYdUApPP/Qlh4DtAO51Ekk2QA==", "dev": true, "requires": { - "minimatch": "^6.1.6" + "minimatch": "^9.0.0" }, "dependencies": { "brace-expansion": { @@ -8369,9 +8147,9 @@ } }, "minimatch": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-6.2.0.tgz", - "integrity": "sha512-sauLxniAmvnhhRjFwPNnJKaPFYyddAgbYdeUpHULtCT/GhzdCx/MDNy+Y40lBxTQUrMzDE8e0S43Z5uqfO0REg==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -8407,12 +8185,6 @@ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true }, - "infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true - }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -8428,9 +8200,9 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.0.tgz", - "integrity": "sha512-HLR38RSF2iulAzc3I/sma4CoYxQP844rPYCNfzGDOHqa/YqVlwuuZgBx6M50/X8dKgzk0cm1qRg3+47mK2N+cQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", "dev": true }, "internal-slot": { @@ -8838,128 +8610,39 @@ } }, "make-fetch-happen": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", - "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", + "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", "dev": true, "requires": { "agentkeepalive": "^4.2.1", - "cacache": "^16.1.0", - "http-cache-semantics": "^4.1.0", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", "is-lambda": "^1.0.1", "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^2.0.3", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^0.6.3", "promise-retry": "^2.0.1", "socks-proxy-agent": "^7.0.0", - "ssri": "^9.0.0" + "ssri": "^10.0.0" }, "dependencies": { - "@npmcli/fs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", - "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", - "dev": true, - "requires": { - "@gar/promisify": "^1.1.3", - "semver": "^7.3.5" - } - }, - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "cacache": { - "version": "16.1.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", - "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", - "dev": true, - "requires": { - "@npmcli/fs": "^2.1.0", - "@npmcli/move-file": "^2.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "glob": "^8.0.1", - "infer-owner": "^1.0.4", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11", - "unique-filename": "^2.0.0" - } - }, - "glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - } - }, "lru-cache": { "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", "dev": true }, - "minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - }, - "ssri": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", - "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", - "dev": true, - "requires": { - "minipass": "^3.1.1" - } - }, - "unique-filename": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", - "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", - "dev": true, - "requires": { - "unique-slug": "^3.0.0" - } - }, - "unique-slug": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", - "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4" - } + "minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true } } }, @@ -9016,15 +8699,23 @@ } }, "minipass-fetch": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", - "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.3.tgz", + "integrity": "sha512-n5ITsTkDqYkYJZjcRWzZt9qnZKCT7nKCosJhHoj7S7zD+BP4jVbWs+odsniw5TA3E0sLomhTKOKjF86wf11PuQ==", "dev": true, "requires": { "encoding": "^0.1.13", - "minipass": "^3.1.6", + "minipass": "^5.0.0", "minipass-sized": "^1.0.3", "minizlib": "^2.1.2" + }, + "dependencies": { + "minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true + } } }, "minipass-flush": { @@ -9109,15 +8800,16 @@ } }, "node-gyp": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.3.1.tgz", - "integrity": "sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==", + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.0.tgz", + "integrity": "sha512-dMXsYP6gc9rRbejLXmTbVRYjAHw7ppswsKyMxuxJxxOHzluIO1rGp9TOQgjFJ+2MCqcOcQTOPB/8Xwhr+7s4Eg==", "dev": true, "requires": { "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", "glob": "^7.1.4", "graceful-fs": "^4.2.6", - "make-fetch-happen": "^10.0.3", + "make-fetch-happen": "^11.0.3", "nopt": "^6.0.0", "npmlog": "^6.0.0", "rimraf": "^3.0.2", @@ -9228,12 +8920,12 @@ } }, "npm-check-updates": { - "version": "16.10.13", - "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-16.10.13.tgz", - "integrity": "sha512-ZsWrtHnaMkcxAaCtDFEr8i7jgM0Bz2AYsnsJlmxISgltG8ie43bWC6G9icxFKfYSLeJJtcj/Yw1Mq5f8GL2F3g==", + "version": "16.10.16", + "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-16.10.16.tgz", + "integrity": "sha512-d8mNYce/l8o5RHPE5ZUp2P1zj9poI7KWQCh5AsTIP3EhicONEhc63mLQQv4/nkCsMb3wCrikx6YOo4BOwN4+1w==", "dev": true, "requires": { - "chalk": "^5.2.0", + "chalk": "^5.3.0", "cli-table3": "^0.6.3", "commander": "^10.0.0", "fast-memoize": "^2.5.2", @@ -9242,25 +8934,25 @@ "get-stdin": "^8.0.0", "globby": "^11.0.4", "hosted-git-info": "^5.1.0", - "ini": "^4.0.0", + "ini": "^4.1.1", "js-yaml": "^4.1.0", "json-parse-helpfulerror": "^1.0.3", "jsonlines": "^0.1.1", "lodash": "^4.17.21", - "minimatch": "^9.0.0", + "minimatch": "^9.0.3", "p-map": "^4.0.0", - "pacote": "15.1.1", + "pacote": "15.2.0", "parse-github-url": "^1.0.2", "progress": "^2.0.3", "prompts-ncu": "^3.0.0", - "rc-config-loader": "^4.1.2", + "rc-config-loader": "^4.1.3", "remote-git-tags": "^3.0.0", - "rimraf": "^5.0.0", - "semver": "^7.4.0", + "rimraf": "^5.0.1", + "semver": "^7.5.3", "semver-utils": "^1.1.4", "source-map-support": "^0.5.21", "spawn-please": "^2.0.1", - "strip-json-comments": "^5.0.0", + "strip-json-comments": "^5.0.1", "untildify": "^4.0.0", "update-notifier": "^6.0.2" }, @@ -9275,9 +8967,9 @@ } }, "chalk": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", - "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true }, "glob": { @@ -9294,9 +8986,9 @@ } }, "minimatch": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", - "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -9318,26 +9010,26 @@ } }, "strip-json-comments": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.0.tgz", - "integrity": "sha512-V1LGY4UUo0jgwC+ELQ2BNWfPa17TIuwBLg+j1AA/9RPzKINl1lhxVEu2r+ZTTO8aetIsUzE5Qj6LMSBkoGYKKw==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.1.tgz", + "integrity": "sha512-0fk9zBqO67Nq5M/m45qHCJxylV/DhBlIOVExqgOMiCCrzrhU6tCibRXNqE3jwJLftzE9SNuZtYbpzcO+i9FiKw==", "dev": true } } }, "npm-install-checks": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.0.0.tgz", - "integrity": "sha512-SBU9oFglRVZnfElwAtF14NivyulDqF1VKqqwNsFW9HDcbHMAPHpRSsVFgKuwFGq/hVvWZExz62Th0kvxn/XE7Q==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.1.1.tgz", + "integrity": "sha512-dH3GmQL4vsPtld59cOn8uY0iOqRmqKvV+DLGwNXV/Q7MDgD2QfOADWd/mFXcIE5LVhYYGjA3baz6W9JneqnuCw==", "dev": true, "requires": { "semver": "^7.1.1" } }, "npm-normalize-package-bin": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.0.tgz", - "integrity": "sha512-g+DPQSkusnk7HYXr75NtzkIP4+N81i3RPsGFidF3DzHd9MT9wWngmqoeg/fnHFz5MNdtG4w03s+QnhewSLTT2Q==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", "dev": true }, "npm-package-arg": { @@ -9379,9 +9071,9 @@ } }, "npm-pick-manifest": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-8.0.1.tgz", - "integrity": "sha512-mRtvlBjTsJvfCCdmPtiu2bdlx8d/KXtF7yNXNWe7G0Z36qWA9Ny5zXsI2PfBZEv7SXgoxTmNaTzGSbbzDZChoA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-8.0.2.tgz", + "integrity": "sha512-1dKY+86/AIiq1tkKVD3l0WI+Gd3vkknVGAggsFeBkTvbhMQ1OND/LKkYv4JtXPKUJ8bOTCyLiqEg2P6QNdK+Gg==", "dev": true, "requires": { "npm-install-checks": "^6.0.0", @@ -9391,13 +9083,13 @@ } }, "npm-registry-fetch": { - "version": "14.0.3", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-14.0.3.tgz", - "integrity": "sha512-YaeRbVNpnWvsGOjX2wk5s85XJ7l1qQBGAp724h8e2CZFFhMSuw9enom7K1mWVUtvXO1uUSFIAPofQK0pPN0ZcA==", + "version": "14.0.5", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-14.0.5.tgz", + "integrity": "sha512-kIDMIo4aBm6xg7jOttupWZamsZRkAqMqwqqbVXnUqstY5+tapvv6bkH/qMR76jdgV+YljEUCyWx3hRYMrJiAgA==", "dev": true, "requires": { "make-fetch-happen": "^11.0.0", - "minipass": "^4.0.0", + "minipass": "^5.0.0", "minipass-fetch": "^3.0.0", "minipass-json-stream": "^1.0.1", "minizlib": "^2.1.2", @@ -9405,52 +9097,11 @@ "proc-log": "^3.0.0" }, "dependencies": { - "lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true - }, - "make-fetch-happen": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.0.3.tgz", - "integrity": "sha512-oPLh5m10lRNNZDjJ2kP8UpboUx2uFXVaVweVe/lWut4iHWcQEmfqSVJt2ihZsFI8HbpwyyocaXbCAWf0g1ukIA==", - "dev": true, - "requires": { - "agentkeepalive": "^4.2.1", - "cacache": "^17.0.0", - "http-cache-semantics": "^4.1.1", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^4.0.0", - "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^10.0.0" - } - }, "minipass": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", - "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true - }, - "minipass-fetch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.1.tgz", - "integrity": "sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==", - "dev": true, - "requires": { - "encoding": "^0.1.13", - "minipass": "^4.0.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - } } } }, @@ -9514,17 +9165,17 @@ } }, "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "requires": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" } }, "p-cancelable": { @@ -9573,9 +9224,9 @@ } }, "pacote": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.1.1.tgz", - "integrity": "sha512-eeqEe77QrA6auZxNHIp+1TzHQ0HBKf5V6c8zcaYZ134EJe1lCi+fjXATkNiEEfbG+e50nu02GLvUtmZcGOYabQ==", + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.2.0.tgz", + "integrity": "sha512-rJVZeIwHTUta23sIZgEIM62WYwbmGbThdbnkt81ravBplQv+HjyroqnLRNH2+sLJHcGZmLRmhPwACqhfTcOmnA==", "dev": true, "requires": { "@npmcli/git": "^4.0.0", @@ -9584,7 +9235,7 @@ "@npmcli/run-script": "^6.0.0", "cacache": "^17.0.0", "fs-minipass": "^3.0.0", - "minipass": "^4.0.0", + "minipass": "^5.0.0", "npm-package-arg": "^10.0.0", "npm-packlist": "^7.0.0", "npm-pick-manifest": "^8.0.0", @@ -9593,24 +9244,24 @@ "promise-retry": "^2.0.1", "read-package-json": "^6.0.0", "read-package-json-fast": "^3.0.0", - "sigstore": "^1.0.0", + "sigstore": "^1.3.0", "ssri": "^10.0.0", "tar": "^6.1.11" }, "dependencies": { "fs-minipass": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.1.tgz", - "integrity": "sha512-MhaJDcFRTuLidHrIttu0RDGyyXs/IYHVmlcxfLAEFIWjc1vdLAkdwT7Ace2u7DbitWC0toKMl5eJZRYNVreIMw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.2.tgz", + "integrity": "sha512-2GAfyfoaCDRrM6jaOS3UsBts8yJ55VioXdWcOL7dK9zdAuKT71+WBA4ifnNYqVjYv+4SsPxjK0JT4yIIn4cA/g==", "dev": true, "requires": { - "minipass": "^4.0.0" + "minipass": "^5.0.0" } }, "minipass": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", - "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true } } @@ -9654,13 +9305,13 @@ "dev": true }, "path-scurry": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.9.2.tgz", - "integrity": "sha512-qSDLy2aGFPm8i4rsbHd4MNyTcrzHFsLQykrtbuGRknZZCBBVXSv2tSCDN2Cg6Rt/GFRw8GoW9y9Ecw5rIPG1sg==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", "dev": true, "requires": { - "lru-cache": "^9.1.1", - "minipass": "^5.0.0 || ^6.0.2" + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "dependencies": { "lru-cache": { @@ -9793,9 +9444,9 @@ } }, "rc-config-loader": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.1.2.tgz", - "integrity": "sha512-qKTnVWFl9OQYKATPzdfaZIbTxcHziQl92zYSxYC6umhOqyAsoj8H8Gq/+aFjAso68sBdjTz3A7omqeAkkF1MWg==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.1.3.tgz", + "integrity": "sha512-kD7FqML7l800i6pS6pvLyIE2ncbk9Du8Q0gp/4hMPhJU6ZxApkoLcGD8ZeqgiAlfwZ6BlETq6qqe+12DUL207w==", "dev": true, "requires": { "debug": "^4.3.4", @@ -9813,12 +9464,12 @@ } }, "read-package-json": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.0.tgz", - "integrity": "sha512-b/9jxWJ8EwogJPpv99ma+QwtqB7FSl3+V6UXS7Aaay8/5VwMY50oIFooY1UKXMWpfNCM6T/PoGqa5GD1g9xf9w==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.4.tgz", + "integrity": "sha512-AEtWXYfopBj2z5N5PbkAOeNHRPUg5q+Nen7QLxV8M2zJq1ym6/lCz3fYNTCXe19puu2d06jfHhrP7v/S2PtMMw==", "dev": true, "requires": { - "glob": "^8.0.1", + "glob": "^10.2.2", "json-parse-even-better-errors": "^3.0.0", "normalize-package-data": "^5.0.0", "npm-normalize-package-bin": "^3.0.0" @@ -9834,26 +9485,32 @@ } }, "glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "version": "10.3.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.3.tgz", + "integrity": "sha512-92vPiMb/iqpmEgsOoIDvTjc50wf9CCCvMzsi6W0JLPeUKE8TWP1a73PgqSrqy7iAZxaSD1YdzU7QZR5LF51MJw==", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "foreground-child": "^3.1.0", + "jackspeak": "^2.0.3", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" } }, "minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "requires": { "brace-expansion": "^2.0.1" } + }, + "minipass": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.2.tgz", + "integrity": "sha512-eL79dXrE1q9dBbDCLg7xfn/vl7MS4F1gvJAgjJrQli/jbQWdUttuVawphqpffoIYfRdq78LHx6GP4bU/EQ2ATA==", + "dev": true } } }, @@ -10008,9 +9665,9 @@ "optional": true }, "semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { "lru-cache": "^6.0.0" } @@ -10067,63 +9724,15 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "sigstore": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.1.1.tgz", - "integrity": "sha512-4hR3tPP1y59YWlaoAgAWFVZ7srTjNWOrrpkQXWu05qP0BvwFYyt3K3l848+IHo+mKhkOzGcNDf7ktASXLEPC+A==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.8.0.tgz", + "integrity": "sha512-ogU8qtQ3VFBawRJ8wjsBEX/vIFeHuGs1fm4jZtjWQwjo8pfAt7T/rh+udlAN4+QUe0IzA8qRSc/YZ7dHP6kh+w==", "dev": true, "requires": { - "@sigstore/protobuf-specs": "^0.1.0", - "make-fetch-happen": "^11.0.1", - "tuf-js": "^1.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true - }, - "make-fetch-happen": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.0.3.tgz", - "integrity": "sha512-oPLh5m10lRNNZDjJ2kP8UpboUx2uFXVaVweVe/lWut4iHWcQEmfqSVJt2ihZsFI8HbpwyyocaXbCAWf0g1ukIA==", - "dev": true, - "requires": { - "agentkeepalive": "^4.2.1", - "cacache": "^17.0.0", - "http-cache-semantics": "^4.1.1", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^4.0.0", - "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^10.0.0" - } - }, - "minipass": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", - "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", - "dev": true - }, - "minipass-fetch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.1.tgz", - "integrity": "sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==", - "dev": true, - "requires": { - "encoding": "^0.1.13", - "minipass": "^4.0.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - } - } + "@sigstore/bundle": "^1.0.0", + "@sigstore/protobuf-specs": "^0.2.0", + "@sigstore/tuf": "^1.0.3", + "make-fetch-happen": "^11.0.1" } }, "simple-concat": { @@ -10238,18 +9847,18 @@ "dev": true }, "ssri": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.1.tgz", - "integrity": "sha512-WVy6di9DlPOeBWEjMScpNipeSX2jIZBGEn5Uuo8Q7aIuFEuDX0pw8RxcOjlD1TWP4obi24ki7m/13+nFpcbXrw==", + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.4.tgz", + "integrity": "sha512-12+IR2CB2C28MMAw0Ncqwj5QbTcs0nGIhgJzYWzDkb21vWmfNI83KS4f3Ci6GI98WreIfG7o9UXp3C0qbpA8nQ==", "dev": true, "requires": { - "minipass": "^4.0.0" + "minipass": "^5.0.0" }, "dependencies": { "minipass": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", - "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true } } @@ -10411,62 +10020,14 @@ "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" }, "tuf-js": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.1.tgz", - "integrity": "sha512-WTp382/PR96k0dI4GD5RdiRhgOU0rAC7+lnoih/5pZg3cyb3aNMqDozleEEWwyfT3+FOg7Qz9JU3n6A44tLSHw==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.7.tgz", + "integrity": "sha512-i3P9Kgw3ytjELUfpuKVDNBJvk4u5bXL6gskv572mcevPbSKCV3zt3djhmlEQ65yERjIbOSncy7U4cQJaB1CBCg==", "dev": true, "requires": { - "@tufjs/models": "1.0.0", - "make-fetch-happen": "^11.0.1" - }, - "dependencies": { - "lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true - }, - "make-fetch-happen": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.0.3.tgz", - "integrity": "sha512-oPLh5m10lRNNZDjJ2kP8UpboUx2uFXVaVweVe/lWut4iHWcQEmfqSVJt2ihZsFI8HbpwyyocaXbCAWf0g1ukIA==", - "dev": true, - "requires": { - "agentkeepalive": "^4.2.1", - "cacache": "^17.0.0", - "http-cache-semantics": "^4.1.1", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^4.0.0", - "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^10.0.0" - } - }, - "minipass": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", - "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", - "dev": true - }, - "minipass-fetch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.1.tgz", - "integrity": "sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==", - "dev": true, - "requires": { - "encoding": "^0.1.13", - "minipass": "^4.0.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - } - } + "@tufjs/models": "1.0.4", + "debug": "^4.3.4", + "make-fetch-happen": "^11.1.1" } }, "tunnel": { @@ -10728,12 +10289,6 @@ } } }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, "wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", diff --git a/dev/coverage-action/package.json b/dev/coverage-action/package.json index c940e370c4..91535a0875 100644 --- a/dev/coverage-action/package.json +++ b/dev/coverage-action/package.json @@ -14,11 +14,11 @@ "luxon": "3.3.0" }, "devDependencies": { - "eslint": "8.43.0", + "eslint": "8.45.0", "eslint-config-standard": "17.1.0", "eslint-plugin-import": "2.27.5", "eslint-plugin-node": "11.1.0", "eslint-plugin-promise": "6.1.1", - "npm-check-updates": "16.10.13" + "npm-check-updates": "16.10.16" } } diff --git a/dev/deploy-to-container/start.sh b/dev/deploy-to-container/start.sh index 2257aaf11c..5621c68fa5 100644 --- a/dev/deploy-to-container/start.sh +++ b/dev/deploy-to-container/start.sh @@ -27,6 +27,9 @@ if [ -n "$PGHOST" ]; then psql -U django -h $PGHOST -d datatracker -v ON_ERROR_STOP=1 -c '\x' -c 'ALTER USER django set search_path=datatracker,public;' fi +echo "Starting memcached..." +/usr/bin/memcached -d -u root + echo "Running Datatracker checks..." ./ietf/manage.py check diff --git a/dev/diff/package-lock.json b/dev/diff/package-lock.json index 385768d472..901feb4011 100644 --- a/dev/diff/package-lock.json +++ b/dev/diff/package-lock.json @@ -16,7 +16,7 @@ "listr2": "^6.6.0", "lodash-es": "^4.17.21", "luxon": "^3.3.0", - "pretty-bytes": "^6.1.0", + "pretty-bytes": "^6.1.1", "tar": "^6.1.15", "yargs": "^17.7.2" }, @@ -981,9 +981,9 @@ "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" }, "node_modules/pretty-bytes": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.0.tgz", - "integrity": "sha512-Rk753HI8f4uivXi4ZCIYdhmG1V+WKzvRMg/X+M42a6t7D07RcmopXJMDNk6N++7Bl75URRGsb40ruvg7Hcp2wQ==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.1.tgz", + "integrity": "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==", "engines": { "node": "^14.13.1 || >=16.0.0" }, @@ -2032,9 +2032,9 @@ "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" }, "pretty-bytes": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.0.tgz", - "integrity": "sha512-Rk753HI8f4uivXi4ZCIYdhmG1V+WKzvRMg/X+M42a6t7D07RcmopXJMDNk6N++7Bl75URRGsb40ruvg7Hcp2wQ==" + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.1.tgz", + "integrity": "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==" }, "pump": { "version": "3.0.0", diff --git a/dev/diff/package.json b/dev/diff/package.json index 8c3187f1d3..701379b9e4 100644 --- a/dev/diff/package.json +++ b/dev/diff/package.json @@ -12,7 +12,7 @@ "listr2": "^6.6.0", "lodash-es": "^4.17.21", "luxon": "^3.3.0", - "pretty-bytes": "^6.1.0", + "pretty-bytes": "^6.1.1", "tar": "^6.1.15", "yargs": "^17.7.2" }, diff --git a/docker/configs/settings_local.py b/docker/configs/settings_local.py index 647fcd5b22..8178db1eff 100644 --- a/docker/configs/settings_local.py +++ b/docker/configs/settings_local.py @@ -40,7 +40,7 @@ # 'ietf.context_processors.sql_debug', # ] -DOCUMENT_PATH_PATTERN = '/assets/ietf-ftp/{doc.type_id}/' +DOCUMENT_PATH_PATTERN = '/assets/ietfdata/doc/{doc.type_id}/' INTERNET_DRAFT_PATH = '/assets/ietf-ftp/internet-drafts/' RFC_PATH = '/assets/ietf-ftp/rfc/' CHARTER_PATH = '/assets/ietf-ftp/charter/' diff --git a/ietf/api/tests.py b/ietf/api/tests.py index 2285fa1532..5dd1823e72 100644 --- a/ietf/api/tests.py +++ b/ietf/api/tests.py @@ -725,6 +725,15 @@ def test_api_appauth(self): self.assertEqual(r.status_code, 200) jsondata = r.json() self.assertEqual(jsondata['success'], True) + + def test_api_get_session_matherials_no_agenda_meeting_url(self): + meeting = MeetingFactory(type_id='ietf') + session = SessionFactory(meeting=meeting) + url = urlreverse('ietf.meeting.views.api_get_session_materials', kwargs={'session_id': session.pk}) + r = self.client.get(url) + self.assertEqual(r.status_code, 200) + + class DirectAuthApiTests(TestCase): diff --git a/ietf/community/views.py b/ietf/community/views.py index 054bed3024..1dbbfcaf0e 100644 --- a/ietf/community/views.py +++ b/ietf/community/views.py @@ -31,7 +31,7 @@ def view_list(request, username=None): docs = docs_tracked_by_community_list(clist) docs, meta = prepare_document_table(request, docs, request.GET) - subscribed = request.user.is_authenticated and EmailSubscription.objects.filter(community_list=clist, email__person__user=request.user) + subscribed = request.user.is_authenticated and (EmailSubscription.objects.none() if clist.pk is None else EmailSubscription.objects.filter(community_list=clist, email__person__user=request.user)) return render(request, 'community/view_list.html', { 'clist': clist, diff --git a/ietf/doc/factories.py b/ietf/doc/factories.py index 95fbedfaae..a8c20b6bb9 100644 --- a/ietf/doc/factories.py +++ b/ietf/doc/factories.py @@ -1,4 +1,4 @@ -# Copyright The IETF Trust 2016-2020, All Rights Reserved +# Copyright The IETF Trust 2016-2023, All Rights Reserved # -*- coding: utf-8 -*- @@ -23,7 +23,6 @@ from ietf.utils.timezone import date_today - def draft_name_generator(type_id,group,n): return '%s-%s-%s-%s%d'%( type_id, @@ -577,4 +576,31 @@ def states(obj, create, extracted, **kwargs): def reset_canonical_name(obj, create, extracted, **kwargs): if hasattr(obj, '_canonical_name'): del obj._canonical_name - return None + return None + +class StatementFactory(BaseDocumentFactory): + type_id = "statement" + title = factory.Faker("sentence") + group = factory.SubFactory("ietf.group.factories.GroupFactory", acronym="iab") + + name = factory.LazyAttribute( + lambda o: "statement-%s-%s" % (xslugify(o.group.acronym), xslugify(o.title)) + ) + uploaded_filename = factory.LazyAttribute(lambda o: f"{o.name}-{o.rev}.md") + + published_statement_event = factory.RelatedFactory( + "ietf.doc.factories.DocEventFactory", + "doc", + type="published_statement", + time=timezone.now() - datetime.timedelta(days=1), + ) + + @factory.post_generation + def states(obj, create, extracted, **kwargs): + if not create: + return + if extracted: + for state_type_id, state_slug in extracted: + obj.set_state(State.objects.get(type_id=state_type_id, slug=state_slug)) + else: + obj.set_state(State.objects.get(type_id="statement", slug="active")) diff --git a/ietf/doc/management/commands/import_iab_statements.py b/ietf/doc/management/commands/import_iab_statements.py new file mode 100644 index 0000000000..c268101fa7 --- /dev/null +++ b/ietf/doc/management/commands/import_iab_statements.py @@ -0,0 +1,320 @@ +# Copyright The IETF Trust 2023, All Rights Reserved + +import debug # pyflakes:ignore + +import csv +import datetime +import io +import os +import shutil +import subprocess +import tempfile + +from collections import defaultdict +from pathlib import Path + +from django.conf import settings +from django.core.management.base import BaseCommand + +from ietf.doc.models import Document, DocAlias, DocEvent, State +from ietf.utils.text import xslugify + + +class Command(BaseCommand): + help = "Performs a one-time import of IAB statements" + + def handle(self, *args, **options): + if Document.objects.filter(type="statement", group__acronym="iab").exists(): + print("IAB statement documents already exist - exiting") + exit(-1) + tmpdir = tempfile.mkdtemp() + process = subprocess.Popen( + ["git", "clone", "https://github.com/kesara/iab-scraper.git", tmpdir], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + stdout, stderr = process.communicate() + if not Path(tmpdir).joinpath("iab_minutes", "2022-12-14.md").exists(): + print("Git clone of the iab-scraper directory did not go as expected") + print("stdout:", stdout) + print("stderr:", stderr) + print(f"Clean up {tmpdir} manually") + exit(-1) + + spreadsheet_rows = load_spreadsheet() + with open("iab_statement_redirects.csv", "w") as redirect_file: + redirect_writer = csv.writer(redirect_file) + for index, (file_fix, date_string, title, url, _) in enumerate( + spreadsheet_rows + ): + name = url.split("/")[6].lower() + if name.startswith("iabs"): + name = name[5:] + elif name.startswith("iab"): + name = name[4:] + if index == 1: + name += "-archive" # https://www.iab.org/documents/correspondence-reports-documents/2015-2/iab-statement-on-identifiers-and-unicode-7-0-0/archive/ + if index == 100: + name = ( + "2010-" + name + ) # https://www.iab.org/documents/correspondence-reports-documents/docs2010/iab-statement-on-the-rpki/ + if index == 152: + name = ( + "2018-" + name + ) # https://www.iab.org/documents/correspondence-reports-documents/2018-2/iab-statement-on-the-rpki/ + docname = f"statement-iab-{xslugify(name)}" + ext = None + base_sourcename = ( + f"{date_string}-{file_fix}" if file_fix != "" else date_string + ) + if ( + Path(tmpdir) + .joinpath("iab_statements", f"{base_sourcename}.md") + .exists() + ): + ext = "md" + elif ( + Path(tmpdir) + .joinpath("iab_statements", f"{base_sourcename}.pdf") + .exists() + ): + ext = "pdf" + if ext is None: + debug.show( + 'f"Could not find {Path(tmpdir).joinpath("iab_statements", f"{base_path}.md")}"' + ) + continue + filename = f"{docname}-00.{ext}" + # Create Document + doc = Document.objects.create( + name=docname, + type_id="statement", + title=title, + group_id=7, # The IAB group + rev="00", + uploaded_filename=filename, + ) + doc.set_state(State.objects.get(type_id="statement", slug="active")) + DocAlias.objects.create(name=doc.name).docs.add(doc) + year, month, day = [int(part) for part in date_string.split("-")] + e1 = DocEvent.objects.create( + time=datetime.datetime( + year, month, day, 12, 00, tzinfo=datetime.timezone.utc + ), + type="published_statement", + doc=doc, + rev="00", + by_id=1, + desc="Statement published (note: The 1200Z time of day is inaccurate - the actual time of day is not known)", + ) + e2 = DocEvent.objects.create( + type="added_comment", + doc=doc, + rev="00", + by_id=1, # The "(System)" person + desc="Statement moved into datatracker from iab wordpress website", + ) + doc.save_with_history([e1, e2]) + + # Put file in place + source = Path(tmpdir).joinpath( + "iab_statements", f"{base_sourcename}.{ext}" + ) + dest = Path(settings.DOCUMENT_PATH_PATTERN.format(doc=doc)).joinpath( + filename + ) + if dest.exists(): + print(f"WARNING: {dest} already exists - not overwriting it.") + else: + os.makedirs(dest.parent, exist_ok=True) + shutil.copy(source, dest) + + redirect_writer.writerow( + [ + url, + f"https://datatracker.ietf.org/doc/{docname}", + ] + ) + + shutil.rmtree(tmpdir) + + +def load_spreadsheet(): + csv_dump = '''2002-03-01,IAB RFC Publication Process Description(txt) March 2003,https://www.iab.org/documents/correspondence-reports-documents/docs2003/iab-rfc-publication-process/,deprecated +2015-01-27,IAB Statement on Identifiers and Unicode 7.0.0 (archive),https://www.iab.org/documents/correspondence-reports-documents/2015-2/iab-statement-on-identifiers-and-unicode-7-0-0/archive/,deprecated +2010-02-05,Response to the EC’s RFI on Forums and Consortiums,https://www.iab.org/documents/correspondence-reports-documents/docs2010/response-to-the-ecs-rfi-on-forums-and-consortiums/,https://www.iab.org/wp-content/IAB-uploads/2011/03/2010-02-05-IAB-Response-Euro-ICT-Questionnaire.pdf +2011-03-30,IAB responds to NTIA Request for Comments on the IANA Functions,https://www.iab.org/documents/correspondence-reports-documents/2011-2/iab-responds-to-ntia-request-for-comments-on-the-iana-functions/,https://www.iab.org/wp-content/IAB-uploads/2011/04/2011-03-30-iab-iana-noi-response.pdf +2011-07-28,IAB's response to the NTIA FNOI on IANA,https://www.iab.org/documents/correspondence-reports-documents/2011-2/iabs-response-to-the-ntia-fnoi-on-iana/,https://www.iab.org/wp-content/IAB-uploads/2011/07/IANA-IAB-FNOI-2011.pdf +2011-12-16,"Questionnaire in support of the ICANN bid for the IANA function [Dec 16, 2011]",https://www.iab.org/documents/correspondence-reports-documents/2011-2/questionnaire-in-support-of-the-icann-bid-for-the-iana-function/,https://www.iab.org/wp-content/IAB-uploads/2011/12/IAB-Past-Performance-Questionnaire.pdf +2012-04-03,IETF Oversight of the IANA Protocol Parameter Function,https://www.iab.org/documents/correspondence-reports-documents/2012-2/ietf-oversight-of-the-iana-protocol-parameter-function/,https://www.iab.org/wp-content/IAB-uploads/2012/04/IETF-IANA-Oversight.pdf +2012-04-29,IETF and IAB comment on OMB Circular A-119,https://www.iab.org/documents/correspondence-reports-documents/2012-2/ietf-and-iab-comment-on-omb-circular-a-119/,https://www.iab.org/wp-content/IAB-uploads/2012/04/OMB-119.pdf +2012-05-24,IAB submits updated ICANN performance evaluation,https://www.iab.org/documents/correspondence-reports-documents/2012-2/iab-submits-updated-icann-performance-evaluation/,https://www.iab.org/wp-content/IAB-uploads/2012/05/IAB-Past-Performance-Questionnaire-FINAL.pdf +2013-07-02,Open letter to the European Commission and the European Parliament in the matter of the Transatlantic Trade and Investment Partnership (TTIP),https://www.iab.org/documents/correspondence-reports-documents/2013-2/open-letter-to-the-ec/,https://www.iab.org/wp-content/IAB-uploads/2013/07/TTIP_market_driven_standards_EU_letter.pdf +2013-05-10,Comments In the matter of Transatlantic Trade and Investment Partnership (TTIP) (USTR-2013-0019),https://www.iab.org/documents/correspondence-reports-documents/2013-2/comments-in-the-matter-of-transatlantic-trade-and-investment-partnership-ttip-ustr-2013-0019/,https://www.iab.org/wp-content/IAB-uploads/2013/07/TTIP_market_driven_standards_FINAL.pdf +2013-10-23,IAB Comments on Recommendation for Random Number Generation Using Deterministic Random Bit Generators,https://www.iab.org/documents/correspondence-reports-documents/2013-2/nist-sp-800-90a/,https://www.iab.org/wp-content/IAB-uploads/2013/10/IAB-NIST-FINAL.pdf +2014-04-07,IAB Comments on NISTIR 7977,https://www.iab.org/documents/correspondence-reports-documents/2014-2/iab-comments-on-nistir-7977/,https://www.iab.org/wp-content/IAB-uploads/2014/04/IAB-NIST7977-20140407.pdf +2014-04-29,Comments to ICANN on the Transition of NTIA’s Stewardship of the IANA Functions,https://www.iab.org/documents/correspondence-reports-documents/2014-2/iab-response-to-icann-iana-transition-proposal/,https://www.iab.org/wp-content/IAB-uploads/2014/04/iab-response-to-20140408-20140428a.pdf +2016-05-27,"IAB Comments to US NTIA Request for Comments, ""The Benefits, Challenges, and Potential Roles for the Government in Fostering the Advancement of the Internet of Things""",https://www.iab.org/documents/correspondence-reports-documents/2016-2/iab-comments-to-ntia-request-for-comments-the-benefits-challenges-and-potential-roles-for-the-government/,https://www.iab.org/wp-content/IAB-uploads/2016/05/ntia-iot-20160525.pdf +2016-05-24,"IAB Chair Testifies before the United States Senate Committee on Commerce, Science, and Transportation on ""Examining the Multistakeholder Plan for Transitioning the Internet Assigned Number Authority""",https://www.iab.org/documents/correspondence-reports-documents/2016-2/iab-chair-statement-before-us-senate-committee-on-iana-transition/,https://www.iab.org/wp-content/IAB-uploads/2016/05/sullivan-to-senate-commerce-20160524.pdf +2018-07-16,IAB Response to NTIA Notice of Inquiry on International Internet Policy Priorities,https://www.iab.org/documents/correspondence-reports-documents/2018-2/iab-response-to-ntia-notice-of-inquiry-on-international-internet-policy-priorities-response/,https://www.iab.org/wp-content/IAB-uploads/2018/07/IAB-response-to-the-2018-NTIA-Notice-of-Inquiry.pdf +2018-09-09,Internet Architecture Board Comments on the Australian Assistance and Access Bill 2018,https://www.iab.org/documents/correspondence-reports-documents/2018-2/internet-architecture-board-comments-on-the-australian-assistance-and-access-bill-2018/,https://www.iab.org/wp-content/IAB-uploads/2018/09/IAB-Comments-on-Australian-Assistance-and-Access-Bill-2018.pdf +2023-03-03,IAB Response to the Office of the High Commissioner for Human Rights Call for Input on “The relationship between human rights and technical standard-setting processes for new and emerging digital technologies”,https://www.iab.org/documents/correspondence-reports-documents/2023-2/iab-response-to-the-ohchr-call-for-input-on-the-relationship-between-human-rights-and-technical-standard/,https://www.iab.org/wp-content/IAB-uploads/2023/03/IAB-Response-to-OHCHR-consultation.pdf +1998-12-09,"IAB Request to IANA for Delegating IPv6 Address Space, Mail Message, December 1998",https://www.iab.org/documents/correspondence-reports-documents/docs98/iab-request-to-iana-for-delegating-ipv6-address-space-mail-message-december-1998/, +1998-12-18,"1998 Statements on Cryptography, Mail Message, December 1998.",https://www.iab.org/documents/correspondence-reports-documents/docs98/1998-statements-on-cryptography/, +1999-02-22,Correspondence between Bradner and Dyson on Protocol Parameter Parameters,https://www.iab.org/documents/correspondence-reports-documents/docs99/correspondence-between-bradner-and-dyson-on-protocol-parameter-parameters/, +1999-08-13,Comment on ICANN ASO membership,https://www.iab.org/documents/correspondence-reports-documents/docs99/comment-on-icann-aso-membership/, +1999-10-19,Ad Hoc Group on Numbering,https://www.iab.org/documents/correspondence-reports-documents/docs99/ad-hoc-group-on-numbering/, +2000-05-01,"IAB Statement on Infrastructure Domain and Subdomains, May 2000.",https://www.iab.org/documents/correspondence-reports-documents/docs2000/iab-statement-on-infrastructure-domain-and-subdomains-may-2000/, +2002-05-01,"IETF and ITU-T Cooperation Arrangements, May 2002",https://www.iab.org/documents/correspondence-reports-documents/docs2002/ietf-and-itu-t-cooperation-arrangements-may-2002/, +2002-05-03,"IAB replyto ENUM liaison statement, May 2002",https://www.iab.org/documents/correspondence-reports-documents/docs2002/enum-response/, +2002-05-24,"Interim Approval for Internet Telephone Numbering System (ENUM) Provisioning, 24 May 2002",https://www.iab.org/documents/correspondence-reports-documents/docs2002/enum-pr/, +2002-06-01,"IAB response to ICANN Evolution and Reform, June 2002",https://www.iab.org/documents/correspondence-reports-documents/docs2002/icann-response/, +2002-09-01,"IAB response to ICANN Evolution and Reform Committee's Second Interim Report, September 2002",https://www.iab.org/documents/correspondence-reports-documents/docs2002/icann-response-2/, +2002-10-01,"IAB response to ICANN Evolution and Reform Committee's Final Implementation Report, October 2002",https://www.iab.org/documents/correspondence-reports-documents/docs2002/icann-response-3/, +2002-12-10,"IAB Response to RIRs request regarding 6bone address entries in ip6.arpa, December 2002",https://www.iab.org/documents/correspondence-reports-documents/docs2002/3ffe/, +2003-01-03,"IETF Notice of Withdrawal from the Protocol Support Organization, January 2003",https://www.iab.org/documents/correspondence-reports-documents/docs2003/icann-pso-notice/, +2003-01-25,"IAB Response to Verisign GRS IDN Announcement, January 2003",https://www.iab.org/documents/correspondence-reports-documents/docs2003/icann-vgrs-response/, +2003-07-10,"Note: Unified Notification Protocol Considerations, July 2003",https://www.iab.org/documents/correspondence-reports-documents/docs2003/2003-07-10-iab-notification/, +2003-08-01,Open Architectural Issues in the Development of the Internet,https://www.iab.org/documents/correspondence-reports-documents/docs2003/2003-08-architectural-issues/, +2003-08-28,RFC Document editing/ queueing suggestion,https://www.iab.org/documents/correspondence-reports-documents/docs2003/2003-08-28-klensin-rfc-editor/, +2003-09-02,"IAB Chair's announcement of an Advisory Committee, September 2003",https://www.iab.org/documents/correspondence-reports-documents/docs2003/2003-09-02-adv-committee/, +2003-09-19,"IAB Commentary: Architectural Concerns on the Use of DNS Wildcards, September 2003",https://www.iab.org/documents/correspondence-reports-documents/docs2003/2003-09-20-dns-wildcards/, +2003-09-24,"IAB to ICANN: IAB input related to the .cs code in ISO 3166, 24 September 2003",https://www.iab.org/documents/correspondence-reports-documents/docs2003/2003-09-25-icann-cs-code/, +2003-09-24,"IAB to ISO: IAB comment on stability of ISO 3166 and other infrastructure standards, 24 September 2003",https://www.iab.org/documents/correspondence-reports-documents/docs2003/2003-09-25-iso-cs-code/, +2003-09-25,"Correspondance to ISO concerning .cs code, and advice to ICANN, 25 September 2003",https://www.iab.org/documents/correspondence-reports-documents/docs2003/2003-09-25-icann-cs-code-2/, +2003-09-25,"Correspondance to ISO concerning .cs code, and advice to ICANN, 25 September 2003",https://www.iab.org/documents/correspondence-reports-documents/docs2003/2003-09-25-iso-cs-code-2/, +2003-09-26,ISO Codes,https://www.iab.org/documents/correspondence-reports-documents/docs2003/2003-09-23-isocodes/, +2003-10-02,"IESG to IAB: Checking data for validity before usage in a protocol, 2 October 2003",https://www.iab.org/documents/correspondence-reports-documents/docs2003/2003-10-02-iesg-dns-validity-check-query/, +2003-10-14,"Survey of Current Security Work in the IETF, October 2003",https://www.iab.org/documents/correspondence-reports-documents/docs2003/2003-10-14-security-survey/, +2003-10-17,"IAB to ICANN SESAC:Wildcard entries in DNS domains, 17 October 2003",https://www.iab.org/documents/correspondence-reports-documents/docs2003/2003-10-17-crocker-wildcards-2/, +2003-10-17,"IAB note to Steve Crocker, Chair, ICANN Security and Stability Advisory Committee, October 2003",https://www.iab.org/documents/correspondence-reports-documents/docs2003/2003-10-17-crocker-wildcards/, +2003-10-18,"IAB concerns against permanent deployment of edge-based port filtering, October 2003",https://www.iab.org/documents/correspondence-reports-documents/docs2003/2003-10-18-edge-filters/, +2003-11-08,"IAB Response to IESG architectural query: Checking data for validity before usage in protocol, November 2003",https://www.iab.org/documents/correspondence-reports-documents/docs2003/2003-11-08-iesg-dns-validity-check-query-response/, +2004-01-19,"Number Resource Organisation (NRO) formation, 19 January 2004",https://www.iab.org/documents/correspondence-reports-documents/docs2004/2004-01-19-nro/, +2004-01-22,"IAB to RIPE NCC:ENUM Administration, 22 January 2004",https://www.iab.org/documents/correspondence-reports-documents/docs2004/2004-01-22-enum-subcodes/, +2004-02-09,"IAB to IANA: Instructions to IANA -Delegation of 2.0.0.2.ip6.arpa, 9 February, 2004",https://www.iab.org/documents/correspondence-reports-documents/docs2004/2004-02-09-6to4-rev-delegation/, +2004-02-26,The IETF -- what is it?,https://www.iab.org/documents/correspondence-reports-documents/docs2004/2004-02-26-ietf-defn/, +2004-04-15,"IAB to ICANN: Validity checks for names, 15 April, 2004",https://www.iab.org/documents/correspondence-reports-documents/docs2004/2004-04-15-icann-dns-validity-check/, +2004-05-07,"IAB to IANA: IPv6 Allocation Policy , 7 May, 2004",https://www.iab.org/documents/correspondence-reports-documents/docs2004/2004-05-07-iana-v6alloc/, +2004-05-24,"IAB to IANA: Instructions to IANA -Delegation of 3.f.f.e.ip6.arpa, 24 May, 2004",https://www.iab.org/documents/correspondence-reports-documents/docs2004/2004-05-24-3ffe-rev-delegation/, +2004-05-27,"IAB to ICANN:Concerns regarding IANA Report, 27 May, 2004",https://www.iab.org/documents/correspondence-reports-documents/docs2004/2004-05-27-iana-report/, +2004-07-16,"Upcoming clarifications to RIPE NCC instructions for e164.arpa operation, 16 July 2004",https://www.iab.org/documents/correspondence-reports-documents/docs2004/2004-07-15-enum-instructions/, +2004-07-16,"IANA Delegation Requests, 16 July 2004",https://www.iab.org/documents/correspondence-reports-documents/docs2004/2004-07-16-iana-delegation/, +2004-08-06,OMA-IETF Standardization Collaboration,https://www.iab.org/documents/correspondence-reports-documents/docs2004/2004-08-draft-iab-oma-liaison-00/, +2004-08-12,"IAB to RIPE NCC:Notice of revision of instructions concerning the ENUM Registry, 12 August, 2004",https://www.iab.org/documents/correspondence-reports-documents/docs2004/2004-08-12-enum-instructions/, +2004-08-12,"Response to your letter of August 4, 12 August 2004",https://www.iab.org/documents/correspondence-reports-documents/docs2004/2004-08-12-icann-wildcard/, +2004-09-27,"IAB to ICANN:Report of Concerns over IANA Performance , 27 September, 2004",https://www.iab.org/documents/correspondence-reports-documents/docs2004/2004-09-27-iana-concerns/, +2004-09-27,"IAB Report of IETF IANA Functions , 27 September 2004",https://www.iab.org/documents/correspondence-reports-documents/docs2004/2004-09-27-iana-report/, +2004-11-03,"IAB to IESG:Comments on Teredo , 3 November, 2004",https://www.iab.org/documents/correspondence-reports-documents/docs2004/2004-11-03-teredo-comments/, +2004-11-12,"IAB to ICANN:Response to ICANN Request for assistance with new TLD Policy , 12 November, 2004",https://www.iab.org/documents/correspondence-reports-documents/docs2004/2004-11-12-icann-new-tld-policy/, +2004-11-29,"The IETF and IPv6 Address Allocation , 29 November 2004",https://www.iab.org/documents/correspondence-reports-documents/docs2004/2004-11-29-ipv6-allocs/, +2004-12-15,"IAB Comment to Internet AD:Comments on IANA Considerations in IPv6 ULA draft, 15 December, 2004",https://www.iab.org/documents/correspondence-reports-documents/docs2004/2004-12-15-ipv6-ula-iana-considerations/, +2005-02-16,"IAB review of Structure of the IETF Administrative Support Activity, 16 February 2005",https://www.iab.org/documents/correspondence-reports-documents/docs2005/2005-02-16-iasa/, +2005-08-26,"SiteFinder returns, 26 August 2005",https://www.iab.org/documents/correspondence-reports-documents/docs2005/2005-08-26-ssac-note/, +2005-09-01,"Re: SiteFinder returns, 1 September 2005",https://www.iab.org/documents/correspondence-reports-documents/docs2005/2005-09-01-ssac-response/, +2005-10-14,"IAB to ICANN: IAB comments on ICANN IDN Guidelines, 14 October 2005",https://www.iab.org/documents/correspondence-reports-documents/docs2005/2005-10-14-idn-guidelines/, +2005-11-07,"IAB to ICANN – Nameserver change for e164.arpa, 7 November 2005",https://www.iab.org/documents/correspondence-reports-documents/docs2005/2005-11-07-nameserver-change/, +2005-11-22,"IETF to ICANN – IANA structural status, 22 November 2005",https://www.iab.org/documents/correspondence-reports-documents/docs2005/2005-11-22-iana-structure/, +2005-11-29,"IAB to IANA – Teredo prefix assignment, 29 November 2005",https://www.iab.org/documents/correspondence-reports-documents/docs2005/2005-11-29-teredo-prefix/, +2005-12-22,"IAB to ICANN – dot arpa TLD management, 22 December 2005",https://www.iab.org/documents/correspondence-reports-documents/docs2005/2005-12-22-dot-arpa/, +2006-03-06,"IAB Position on the IETF IANA Technical Parameter Function, 6 March 2006",https://www.iab.org/documents/correspondence-reports-documents/docs2006/iab-iana-position/, +2006-03-28,"IAB to ICANN – Name server changes for ip6.arpa, 28 March 2006",https://www.iab.org/documents/correspondence-reports-documents/docs2006/2006-03-28-nameserver-change/, +2006-04-20,"IAB to IANA – Administrative contact information change for arpa, 20 April 2006",https://www.iab.org/documents/correspondence-reports-documents/docs2006/2006-04-20-update-to-administrative-contact-information-for-arpa-iana/, +2006-04-20,"IAB to ITU TSB – FYI re contact info changes for e164.arpa, 20 April 2006",https://www.iab.org/documents/correspondence-reports-documents/docs2006/2006-04-20-update-to-contact-information-for-e164-arpa-hill/, +2006-04-20,"IAB to IANA – Contact information changes for e164.arpa, 20 April 2006",https://www.iab.org/documents/correspondence-reports-documents/docs2006/2006-04-20-update-to-contact-information-for-e164-arpa-iana/, +2006-05-15,"IAB to IANA – Request to IANA for status update on deployment of DNSSEC on IANA managed zones, 15 May 2006",https://www.iab.org/documents/correspondence-reports-documents/docs2006/2006-05-15-iab-request-to-iana-to-sign-dnssec-zones/, +2006-06-07,"The IAB announces the mailing list for the discussion of the independent submissions process, 7 June 2006",https://www.iab.org/documents/correspondence-reports-documents/docs2006/2006-06-07-independent-submissions/, +2006-06-19,"Procedural issues with liaison on nextsteps, 19 June 2006",https://www.iab.org/documents/correspondence-reports-documents/docs2006/2006-06-16-response-to-idn-liaison-issues/, +2006-10-12,"The IAB sends a note to the Registry Services Technical Evaluation Panel on the use of wildcards in the .travel TLD, 12 October 2006",https://www.iab.org/documents/correspondence-reports-documents/docs2006/2006-10-12-rstep-note/, +2006-10-19,"The IAB sends a note to the OIF Technical Committee Chair on IETF Protocol Extensions, 19 October 2006",https://www.iab.org/documents/correspondence-reports-documents/docs2006/2006-10-19-oifnote/, +2007-05-21,"The IAB responds to ITU Consultation on Resolution 102, 21 May 2007",https://www.iab.org/documents/correspondence-reports-documents/docs2007/2007-05-21-itu-resolution-102/, +2007-07-05,"Correspondence from the RIPE NCC regarding deployment of DNSSEC in the E164.ARPA zone, 5 July 2007",https://www.iab.org/documents/correspondence-reports-documents/docs2007/2007-07-05-ripe-ncc-dnssec-e164/, +2007-07-24,"Correspondence from the IAB to the ITU-TSB Director regarding deployment of DNSSEC in the E164.ARPA zone, 24 July 2007",https://www.iab.org/documents/correspondence-reports-documents/docs2007/2007-07-24-iab-itu-dnssec-e164/, +2007-10-10,"Follow-up work on NAT-PT, 10 October 2007",https://www.iab.org/documents/correspondence-reports-documents/docs2007/follow-up-work-on-nat-pt/, +2008-02-15,"Correspondence from the IAB to the National Telecommunications and Information Administration, US Department of Commerce regarding the ICANN/DoC Joint Project Agreement, 15 February 2008",https://www.iab.org/documents/correspondence-reports-documents/docs2008/2008-02-15-midterm-view-icann-doc-jpa/, +2008-03-07,"The IAB’s response to ICANN’s solicitation on DNS stability, 7 March 2008",https://www.iab.org/documents/correspondence-reports-documents/docs2008/2008-03-07-icann-new-gtlds/, +2008-06-04,Proposed RFC Editor Structure,https://www.iab.org/documents/correspondence-reports-documents/docs2008/2008-06-04-rfc-editor-model/, +2008-08-16,"The IAB’s response to Geoff Huston’s request concerning 32-bit AS numbers, 16 August 2008",https://www.iab.org/documents/correspondence-reports-documents/docs2008/2008-08-16-32bit-as-huston/, +2008-09-05,Proposed RFC Editor Structure,https://www.iab.org/documents/correspondence-reports-documents/docs2008/2008-09-05-rfc-editor-model/, +2008-11-18,"The IAB’s correspondence with NTIA on DNSSEC deployment at the root, 18 November 2008",https://www.iab.org/documents/correspondence-reports-documents/docs2008/2008-11-18-dnssec-deployment-at-the-root/, +2008-12-04,"IAB correspondence with Geoff Huston on TAs, IANA, RIRs et al.., 4 December 2008",https://www.iab.org/documents/correspondence-reports-documents/docs2008/2008-12-04-huston-tas-iana-rirs/, +2009-06-02,"IAB correspondence with IANA on the Signing of .ARPA, 2 June 2009",https://www.iab.org/documents/correspondence-reports-documents/docs2009/2009-06-02-roseman-signing-by-iana-of-arpa/, +2009-10-14,"IAB correspondence with ICANN on their “Scaling the Root” study., 14 October 2009",https://www.iab.org/documents/correspondence-reports-documents/docs2009/2009-10-14-icann-scaling-the-root/, +2010-01-27,IAB statement on the RPKI,https://www.iab.org/documents/correspondence-reports-documents/docs2010/iab-statement-on-the-rpki/, +2010-07-30,Transition of IN-ADDR.ARPA generation,https://www.iab.org/documents/correspondence-reports-documents/docs2010/transition-of-in-addr-arpa-generation/, +2011-06-22,Response to ARIN's request for guidance regarding Draft Policy ARIN-2011-5,https://www.iab.org/documents/correspondence-reports-documents/2011-2/response-to-arins-request-for-guidance-regarding-draft-policy-arin-2011-5/, +2011-07-25,"IAB Response to ""Some IESG Thoughts on Liaisons""",https://www.iab.org/documents/correspondence-reports-documents/2011-2/iab-response-to-some-iesg-thoughts-on-liaisons/, +2011-09-16,Letter to the European Commission on Global Interoperability in Emergency Services,https://www.iab.org/documents/correspondence-reports-documents/2011-2/letter-to-the-european-commission-on-global-interoperability-in-emergency-services/, +2012-02-08,"IAB Statement: ""The interpretation of rules in the ICANN gTLD Applicant Guidebook""",https://www.iab.org/documents/correspondence-reports-documents/2012-2/iab-statement-the-interpretation-of-rules-in-the-icann-gtld-applicant-guidebook/, +2012-03-26,"Response to ICANN questions concerning ""The interpretation of rules in the ICANN gTLD Applicant Guidebook""",https://www.iab.org/documents/correspondence-reports-documents/2012-2/response-to-icann-questions-concerning-the-interpretation-of-rules-in-the-icann-gtld-applicant-guidebook/, +2012-03-30,IAB Member Roles in Evaluating New Work Proposals,https://www.iab.org/documents/correspondence-reports-documents/2012-2/iab-member-roles-in-evaluating-new-work-proposals/, +2012-08-29,Leading Global Standards Organizations Endorse ‘OpenStand’ Principles that Drive Innovation and Borderless Commerce,https://www.iab.org/documents/correspondence-reports-documents/2012-2/leading-global-standards-organizations-endorse-%e2%80%98openstand/, +2013-03-28,IAB Response to RSSAC restructure document (28 March 2013),https://www.iab.org/documents/correspondence-reports-documents/2013-2/iab-response-to-rssac-restructure-document-28-march-2013/, +2013-05-28,Consultation on Root Zone KSK Rollover from the IAB,https://www.iab.org/documents/correspondence-reports-documents/2013-2/consultation-on-root-zone-ksk-rollover-from-the-iab/, +2013-07-10,IAB Statement: Dotless Domains Considered Harmful,https://www.iab.org/documents/correspondence-reports-documents/2013-2/iab-statement-dotless-domains-considered-harmful/, +2013-07-16,IAB Response to ICANN Consultation on the Source of Policies & User Instructions for Internet Number Resource Requests,https://www.iab.org/documents/correspondence-reports-documents/2013-2/iab-response-to-iana-policies-user-instructions-25jun13/, +2013-10-03,Statement from the IAB on the Strengths of the OpenStand Principles,https://www.iab.org/documents/correspondence-reports-documents/2013-2/statement-from-openstand-on-the-strengths-of-the-openstand-principles/, +2013-10-07,Montevideo Statement on the Future of Internet Cooperation,https://www.iab.org/documents/correspondence-reports-documents/2013-2/montevideo-statement-on-the-future-of-internet-cooperation/, +2013-11-27,IAB Statement on draft-farrell-perpass-attack-00,https://www.iab.org/documents/correspondence-reports-documents/2013-2/iab-statement-on-draft-farrell-perpass-attack-00/, +2014-01-23,IAB Comments Regarding the IRTF CFRG chair,https://www.iab.org/documents/correspondence-reports-documents/2014-2/0123-iab-comments-regarding-the-irtf-cfrg-chair/, +2014-02-14,"Statement from the I* Leaders Coordination Meeting, Santa Monica, 14 February 2014",https://www.iab.org/documents/correspondence-reports-documents/2014-2/statement-from-the-i-leaders-coordination-meeting-santa-monica-14-february-2014/, +2014-03-11,Re: Guiding the Evolution of the IANA Protocol Parameter Registries,https://www.iab.org/documents/correspondence-reports-documents/2014-2/re-guiding-the-evolution-of-the-iana-protocol-parameter-registries/, +2014-03-14,Internet Technical Leaders Welcome IANA Globalization Progress,https://www.iab.org/documents/correspondence-reports-documents/2014-2/internet-technical-leaders-welcome-iana-globalization-progress/, +2014-05-13,I* Post-NETmundial Meeting Statement,https://www.iab.org/documents/correspondence-reports-documents/2014-2/i-post-netmundial-meeting-statement/, +2014-06-05,Comments on ICANN Board Member Compensation from the IAB,https://www.iab.org/documents/correspondence-reports-documents/2014-2/comments-on-icann-board-member-compensation/, +2014-11-13,IAB Statement on Internet Confidentiality,https://www.iab.org/documents/correspondence-reports-documents/2014-2/iab-statement-on-internet-confidentiality/, +2014-12-04,IAB statement on the NETmundial Initiative,https://www.iab.org/documents/correspondence-reports-documents/2014-2/iab-statement-on-the-netmundial-initiative/, +2014-12-17,IAB Comments on CSTD Report Mapping International Internet Public Policy Issues,https://www.iab.org/documents/correspondence-reports-documents/2014-2/iab-comments-on-cstd-report-mapping-international-public-policy-issues/, +2015-02-11,IAB liaison to ICANN Root Server System Advisory Committee (RSSAC),https://www.iab.org/documents/correspondence-reports-documents/2015-2/iab-liaison-to-icann-root-server-system-advisory-council-rssac/, +2015-02-11,IAB Statement on Identifiers and Unicode 7.0.0,https://www.iab.org/documents/correspondence-reports-documents/2015-2/iab-statement-on-identifiers-and-unicode-7-0-0/, +2015-03-02,IAB Statement on Liaison Compensation,https://www.iab.org/documents/correspondence-reports-documents/2015-2/iab-statement-on-liaison-compensation/, +2015-04-09,IAB Comments on The HTTPS-Only Standard,https://www.iab.org/documents/correspondence-reports-documents/2015-2/iab-comments-on-the-https-only-standard/, +2015-06-03,IAB comments on CCWG-Accountability Draft Report,https://www.iab.org/documents/correspondence-reports-documents/2015-2/iab-comments-on-ccwg-accountability-draft-report/, +2015-06-12,IAB Statement on the Trade in Security Technologies,https://www.iab.org/documents/correspondence-reports-documents/2015-2/iab-statement-on-the-trade-in-security-technologies/, +2015-06-24,"IAB Correspondence to U.S. Bureau of Industry and Security, re RIN 0694-AG49",https://www.iab.org/documents/correspondence-reports-documents/2015-2/rin-0694-ag49/, +2015-09-07,Internet Architecture Board comments on the ICG Proposal,https://www.iab.org/documents/correspondence-reports-documents/2015-2/iab-comments-on-icg-proposal/, +2015-09-09,IAB comments on the CCWG accountability 2d draft report,https://www.iab.org/documents/correspondence-reports-documents/2015-2/iab-comments-on-ccwg-accountability/, +2015-10-07,IAB Comments to FCC on Rules regarding Authorization of Radiofrequency Equipment,https://www.iab.org/documents/correspondence-reports-documents/2015-2/iab-comments-on-fcc-15-92/, +2015-12-16,IAB comments on the CCWG accountability 3d draft report,https://www.iab.org/documents/correspondence-reports-documents/2015-2/iab-comments-on-the-ccwg-accountability-3d-draft-report/, +2016-01-13,"Comments from the Internet Architecture Board (IAB) on ""Registration Data Access Protocol (RDAP) Operational Profile for gTLD Registries and Registrars""",https://www.iab.org/documents/correspondence-reports-documents/2016-2/comments-from-the-internet-architecture-board-iab-on-registration-data-access-protocol-rdap-operational-profile-for-gtld-registries-and-registrars/, +2016-05-04,IAB comments on Draft New ICANN Bylaws,https://www.iab.org/documents/correspondence-reports-documents/2016-2/iab-comments-on-draft-new-icann-bylaws/, +2016-05-11,IAB Comments on Proposed Changes to Internet Society Bylaws,https://www.iab.org/documents/correspondence-reports-documents/2016-2/iab-comments-on-proposed-changes-to-internet-society-bylaws/, +2016-07-17,Comments from the IAB on LGRs for second level,https://www.iab.org/documents/correspondence-reports-documents/2016-2/comments-from-the-iab-on-lgrs-for-second-level/, +2016-09-01,IAB statement on IANA Intellectual Property Rights,https://www.iab.org/documents/correspondence-reports-documents/2016-2/iab-statement-on-iana-intellectual-property-rights/, +2016-09-14,IAB Statement on the IANA Stewardship Transition,https://www.iab.org/documents/correspondence-reports-documents/2016-2/iab-statement-on-the-iana-stewardship-transition/, +2016-11-07,IAB Statement on IPv6,https://www.iab.org/documents/correspondence-reports-documents/2016-2/iab-statement-on-ipv6/, +2016-12-07,"IAB comment on ""Revised Proposed Implementation of GNSO Thick Whois Consensus Policy Requiring Consistent Labeling and Display of RDDS (Whois) Output for All gTLDs""",https://www.iab.org/documents/correspondence-reports-documents/2016-2/iab-comment-on-revised-proposed-implementation-of-gnso-thick-whois-consensus-policy-requiring-consistent-labeling-and-display-of-rdds-whois-output-for-all-gtlds/, +2017-01-04,IAB comments on Identifier Technology Health Indicators: Definition,https://www.iab.org/documents/correspondence-reports-documents/2017-2/iab-comments-on-identifier-technology-health-indicators-definition/, +2017-02-01,IAB Statement on OCSP Stapling,https://www.iab.org/documents/correspondence-reports-documents/2017-2/iab-statement-on-ocsp-stapling/, +2017-02-16,Follow up on barriers to entry blog post,https://www.iab.org/documents/correspondence-reports-documents/2017-2/follow-up-on-barriers-to-entry-blog-post/, +2017-03-02,IAB Comments to United States NTIA on the Green Paper: Fostering the Advancement of the Internet of Things,https://www.iab.org/documents/correspondence-reports-documents/2017-2/iab-comments-to-ntia-on-fostering-the-advancement-of-iot/, +2017-03-30,Internet Architecture Board statement on the registration of special use names in the ARPA domain,https://www.iab.org/documents/correspondence-reports-documents/2017-2/iab-statement-on-the-registration-of-special-use-names-in-the-arpa-domain/, +2017-05-01,Comments from the IAB on IDN Implementation Guidelines,https://www.iab.org/documents/correspondence-reports-documents/2017-2/comments-from-the-iab-on-idn-implementation-guidelines/, +2017-07-31,IAB Response to FCC-17-89,https://www.iab.org/documents/correspondence-reports-documents/2017-2/iab-response-to-fcc-17-89/, +2018-03-15,IAB Statement on Identifiers and Unicode,https://www.iab.org/documents/correspondence-reports-documents/2018-2/iab-statement-on-identifiers-and-unicode/, +2018-04-03,IAB Statement on the RPKI,https://www.iab.org/documents/correspondence-reports-documents/2018-2/iab-statement-on-the-rpki/, +2019-05-02,Revised Operating Instructions for e164.arpa (ENUM),https://www.iab.org/documents/correspondence-reports-documents/2019-2/revised-operating-instructions-for-e164-arpa-enum/, +2019-06-26,Comments on Evolving the Governance of the Root Server System,https://www.iab.org/documents/correspondence-reports-documents/2019-2/comments-on-evolving-the-governance-of-the-root-server-system/, +2019-09-04,Avoiding Unintended Harm to Internet Infrastructure,https://www.iab.org/documents/correspondence-reports-documents/2019-2/avoiding-unintended-harm-to-internet-infrastructure/, +2020-07-01,"IAB correspondence with the National Telecommunications and Information Administration (NTIA) on DNSSEC deployment for the Root Zone [Docket No. 100603240-0240-01], 1 July 2010",https://www.iab.org/documents/correspondence-reports-documents/docs2010/2010-07-01-alexander-dnssec-deployment-for-the-root-zone/, +2020-09-29,IAB Comments on the Draft Final Report on the new gTLD Subsequent Procedures Policy Development Process,https://www.iab.org/documents/correspondence-reports-documents/2020-2/iab-comments-on-new-gtld-subsequent-procedures/, +2021-07-14,IAB Statement on Inclusive Language in IAB Stream Documents,https://www.iab.org/documents/correspondence-reports-documents/2021-2/iab-statement-on-inclusive-language-in-iab-stream-documents/, +2022-04-08,IAB comment on Mandated Browser Root Certificates in the European Union’s eIDAS Regulation on the Internet,https://www.iab.org/documents/correspondence-reports-documents/2022-2/iab-comment-on-mandated-browser-root-certificates-in-the-european-unions-eidas-regulation-on-the-internet/, +2022-04-08,"IAB Comments on A Notice by the Federal Communications Commission on Secure Internet Routing, issued 03/11/2022",https://www.iab.org/documents/correspondence-reports-documents/2022-2/iab-comments-on-a-notice-by-the-federal-communications-commission-on-secure-internet-routing-issued-03-11-2022/, +2022-07-08,IAB Statement to OSTP on Privacy-Enhancing Technologies,https://www.iab.org/documents/correspondence-reports-documents/2022-2/iab-statement-to-ostp-on-privacy-enhancing-technologies/, +2022-11-21,IAB Comments on a notice by the Federal Trade Commission on “Trade Regulation Rule on Commercial Surveillance and Data Security” (16 CFR Part 464),https://www.iab.org/documents/correspondence-reports-documents/2022-2/iab-comments-on-a-notice-by-the-federal-trade-commission-on-trade-regulation-rule-on-commercial-surveillance-and-data-security-16-cfr-part-464/, +''' + + rows = [] + date_count = defaultdict(lambda: 0) + with io.StringIO(csv_dump) as csv_file: + reader = csv.reader(csv_file) + for row in reader: + date = row[0] + if date_count[date] == 0: + row.insert(0, "") + else: + row.insert(0, date_count[date]) + date_count[date] += 1 + rows.append(row) + return rows diff --git a/ietf/doc/migrations/0005_alter_docevent_type.py b/ietf/doc/migrations/0005_alter_docevent_type.py new file mode 100644 index 0000000000..f8a3cfc795 --- /dev/null +++ b/ietf/doc/migrations/0005_alter_docevent_type.py @@ -0,0 +1,86 @@ +# Copyright The IETF Trust 2023, All Rights Reserved + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("doc", "0004_alter_dochistory_ad_alter_dochistory_shepherd_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="docevent", + name="type", + field=models.CharField( + choices=[ + ("new_revision", "Added new revision"), + ("new_submission", "Uploaded new revision"), + ("changed_document", "Changed document metadata"), + ("added_comment", "Added comment"), + ("added_message", "Added message"), + ("edited_authors", "Edited the documents author list"), + ("deleted", "Deleted document"), + ("changed_state", "Changed state"), + ("changed_stream", "Changed document stream"), + ("expired_document", "Expired document"), + ("extended_expiry", "Extended expiry of document"), + ("requested_resurrect", "Requested resurrect"), + ("completed_resurrect", "Completed resurrect"), + ("changed_consensus", "Changed consensus"), + ("published_rfc", "Published RFC"), + ( + "added_suggested_replaces", + "Added suggested replacement relationships", + ), + ( + "reviewed_suggested_replaces", + "Reviewed suggested replacement relationships", + ), + ("changed_action_holders", "Changed action holders for document"), + ("changed_group", "Changed group"), + ("changed_protocol_writeup", "Changed protocol writeup"), + ("changed_charter_milestone", "Changed charter milestone"), + ("initial_review", "Set initial review time"), + ("changed_review_announcement", "Changed WG Review text"), + ("changed_action_announcement", "Changed WG Action text"), + ("started_iesg_process", "Started IESG process on document"), + ("created_ballot", "Created ballot"), + ("closed_ballot", "Closed ballot"), + ("sent_ballot_announcement", "Sent ballot announcement"), + ("changed_ballot_position", "Changed ballot position"), + ("changed_ballot_approval_text", "Changed ballot approval text"), + ("changed_ballot_writeup_text", "Changed ballot writeup text"), + ("changed_rfc_editor_note_text", "Changed RFC Editor Note text"), + ("changed_last_call_text", "Changed last call text"), + ("requested_last_call", "Requested last call"), + ("sent_last_call", "Sent last call"), + ("scheduled_for_telechat", "Scheduled for telechat"), + ("iesg_approved", "IESG approved document (no problem)"), + ("iesg_disapproved", "IESG disapproved document (do not publish)"), + ("approved_in_minute", "Approved in minute"), + ("iana_review", "IANA review comment"), + ("rfc_in_iana_registry", "RFC is in IANA registry"), + ( + "rfc_editor_received_announcement", + "Announcement was received by RFC Editor", + ), + ("requested_publication", "Publication at RFC Editor requested"), + ( + "sync_from_rfc_editor", + "Received updated information from RFC Editor", + ), + ("requested_review", "Requested review"), + ("assigned_review_request", "Assigned review request"), + ("closed_review_request", "Closed review request"), + ("closed_review_assignment", "Closed review assignment"), + ("downref_approved", "Downref approved"), + ("posted_related_ipr", "Posted related IPR"), + ("removed_related_ipr", "Removed related IPR"), + ("changed_editors", "Changed BOF Request editors"), + ("published_statement", "Published statement"), + ], + max_length=50, + ), + ), + ] diff --git a/ietf/doc/migrations/0006_statements.py b/ietf/doc/migrations/0006_statements.py new file mode 100644 index 0000000000..9a074292e5 --- /dev/null +++ b/ietf/doc/migrations/0006_statements.py @@ -0,0 +1,43 @@ +# Copyright The IETF Trust 2023, All Rights Reserved + +from django.db import migrations + + +def forward(apps, schema_editor): + StateType = apps.get_model("doc", "StateType") + State = apps.get_model("doc", "State") + + StateType.objects.create(slug="statement", label="Statement State") + State.objects.create( + slug="active", + type_id="statement", + name="Active", + order=0, + desc="The statement is active", + ) + State.objects.create( + slug="replaced", + type_id="statement", + name="Replaced", + order=0, + desc="The statement has been replaced", + ) + + +def reverse(apps, schema_editor): + StateType = apps.get_model("doc", "StateType") + State = apps.get_model("doc", "State") + + State.objects.filter(type_id="statement").delete() + StateType.objects.filter(slug="statement").delete() + + +class Migration(migrations.Migration): + dependencies = [ + ("doc", "0005_alter_docevent_type"), + ("name", "0004_statements"), + ] + + operations = [ + migrations.RunPython(forward, reverse), + ] diff --git a/ietf/doc/models.py b/ietf/doc/models.py index 86d814d737..d480326763 100644 --- a/ietf/doc/models.py +++ b/ietf/doc/models.py @@ -1,4 +1,4 @@ -# Copyright The IETF Trust 2010-2020, All Rights Reserved +# Copyright The IETF Trust 2010-2023, All Rights Reserved # -*- coding: utf-8 -*- @@ -162,7 +162,7 @@ def get_file_path(self): self._cached_file_path = settings.CONFLICT_REVIEW_PATH elif self.type_id == "statchg": self._cached_file_path = settings.STATUS_CHANGE_PATH - elif self.type_id == "bofreq": + elif self.type_id == "bofreq": # TODO: This is probably unneeded, as is the separate path setting self._cached_file_path = settings.BOFREQ_PATH else: self._cached_file_path = settings.DOCUMENT_PATH_PATTERN.format(doc=self) @@ -186,7 +186,7 @@ def get_base_name(self): elif self.type_id == 'review': # TODO: This will be wrong if a review is updated on the same day it was created (or updated more than once on the same day) self._cached_base_name = "%s.txt" % self.name - elif self.type_id == 'bofreq': + elif self.type_id in ['bofreq', 'statement']: self._cached_base_name = "%s-%s.md" % (self.name, self.rev) else: if self.rev: @@ -1290,7 +1290,11 @@ class DocReminder(models.Model): ("removed_related_ipr", "Removed related IPR"), # Bofreq Editor events - ("changed_editors", "Changed BOF Request editors") + ("changed_editors", "Changed BOF Request editors"), + + # Statement events + ("published_statement", "Published statement"), + ] class DocEvent(models.Model): diff --git a/ietf/doc/tests.py b/ietf/doc/tests.py index 89899f24a6..f66d77681e 100644 --- a/ietf/doc/tests.py +++ b/ietf/doc/tests.py @@ -261,6 +261,17 @@ def test_search_for_name(self): parsed = urlparse(r["Location"]) self.assertEqual(parsed.path, urlreverse('ietf.doc.views_search.search')) self.assertEqual(parse_qs(parsed.query)["name"][0], "draft-ietf-doesnotexist-42") + + def test_search_rfc(self): + rfc = WgRfcFactory(name="rfc0000") + + # search for existing RFC should redirect directly to the RFC page + r = self.client.get(urlreverse('ietf.doc.views_search.search_for_name', kwargs=dict(name=rfc.name))) + self.assertRedirects(r, f'/doc/{rfc.name}/', status_code=302, target_status_code=200) + + # search for existing RFC with revision number should redirect to the RFC page + r = self.client.get(urlreverse('ietf.doc.views_search.search_for_name', kwargs=dict(name=rfc.name + "-99")), follow=True) + self.assertRedirects(r, f'/doc/{rfc.name}/', status_code=302, target_status_code=200) def test_frontpage(self): r = self.client.get("/") @@ -1617,6 +1628,10 @@ def test_document_charter(self): CharterFactory(name='charter-ietf-mars') r = self.client.get(urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name="charter-ietf-mars"))) self.assertEqual(r.status_code, 200) + + def test_incorrect_rfc_url(self): + r = self.client.get(urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name="rfc8989", rev="00"))) + self.assertEqual(r.status_code, 404) def test_document_conflict_review(self): ConflictReviewFactory(name='conflict-review-imaginary-irtf-submission') @@ -1993,6 +2008,12 @@ def test_document_bibtex(self): # self.assertNotIn('day', entry) + # test for incorrect case - revision for RFC + rfc = WgRfcFactory(name="rfc0000") + url = urlreverse('ietf.doc.views_doc.document_bibtex', kwargs=dict(name=rfc.name, rev='00')) + r = self.client.get(url) + self.assertEqual(r.status_code, 404) + april1 = IndividualRfcFactory.create( stream_id = 'ise', states = [('draft','rfc'),('draft-iesg','pub')], diff --git a/ietf/doc/tests_draft.py b/ietf/doc/tests_draft.py index 5b6dd63b97..85efbf1a6c 100644 --- a/ietf/doc/tests_draft.py +++ b/ietf/doc/tests_draft.py @@ -1,4 +1,4 @@ -# Copyright The IETF Trust 2011-2020, All Rights Reserved +# Copyright The IETF Trust 2011-2023, All Rights Reserved # -*- coding: utf-8 -*- @@ -311,6 +311,24 @@ def test_request_last_call(self): # action holders self.assertCountEqual(draft.action_holders.all(), [ad]) + def test_iesg_state_edit_button(self): + ad = Person.objects.get(user__username="ad") + draft = WgDraftFactory(ad=ad,states=[('draft','active'),('draft-iesg','ad-eval')]) + + url = urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=draft.name)) + self.client.login(username="ad", password="ad+password") + + r = self.client.get(url) + self.assertEqual(r.status_code, 200) + q = PyQuery(r.content) + self.assertIn("Edit", q('tr:contains("IESG state")').text()) + + draft.set_state(State.objects.get(used=True, type="draft-iesg", slug="dead")) + r = self.client.get(url) + self.assertEqual(r.status_code, 200) + q = PyQuery(r.content) + self.assertNotIn("Edit", q('tr:contains("IESG state")').text()) + class EditInfoTests(TestCase): def test_edit_info(self): diff --git a/ietf/doc/tests_statement.py b/ietf/doc/tests_statement.py new file mode 100644 index 0000000000..4234a18c81 --- /dev/null +++ b/ietf/doc/tests_statement.py @@ -0,0 +1,359 @@ +# Copyright The IETF Trust 2023, All Rights Reserved + +import debug # pyflakes:ignore + +from pyquery import PyQuery + +from pathlib import Path +from zoneinfo import ZoneInfo + +from django.conf import settings +from django.core.files.uploadedfile import SimpleUploadedFile +from django.template.loader import render_to_string +from django.urls import reverse as urlreverse + +from ietf.doc.factories import StatementFactory, DocEventFactory +from ietf.doc.models import Document, DocAlias, State, NewRevisionDocEvent +from ietf.group.models import Group +from ietf.person.factories import PersonFactory +from ietf.utils.mail import outbox, empty_outbox +from ietf.utils.test_utils import ( + TestCase, + reload_db_objects, + login_testing_unauthorized, +) + + +class StatementsTestCase(TestCase): + settings_temp_path_overrides = TestCase.settings_temp_path_overrides + [ + "DOCUMENT_PATH_PATTERN" + ] + + def extract_content(self, response): + if not hasattr(response, "_cached_extraction"): + response._cached_extraction = list(response.streaming_content)[0].decode( + "utf-8" + ) + return response._cached_extraction + + def write_statement_markdown_file(self, statement): + ( + Path(settings.DOCUMENT_PATH_PATTERN.format(doc=statement)) + / ("%s-%s.md" % (statement.name, statement.rev)) + ).write_text( + """# This is a test statement. +Version: {statement.rev} + +## A section + +This test section has some text. +""" + ) + + def write_statement_pdf_file(self, statement): + ( + Path(settings.DOCUMENT_PATH_PATTERN.format(doc=statement)) + / ("%s-%s.pdf" % (statement.name, statement.rev)) + ).write_text( + f"{statement.rev} This is not valid PDF, but the test does not need it to be" + ) + + def test_statement_doc_view(self): + doc = StatementFactory() + self.write_statement_markdown_file(doc) + url = urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=doc.name)) + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + q = PyQuery(response.content) + self.assertEqual(q("#statement-state").text(), "Active") + self.assertEqual(q("#statement-type").text(), "IAB Statement") + self.assertIn("has some text", q(".card-body").text()) + published = doc.docevent_set.filter(type="published_statement").last().time + self.assertIn( + published.astimezone(ZoneInfo(settings.TIME_ZONE)).date().isoformat(), + q("#published").text(), + ) + + doc.set_state(State.objects.get(type_id="statement", slug="replaced")) + doc2 = StatementFactory() + doc2.relateddocument_set.create( + relationship_id="replaces", target=doc.docalias.first() + ) + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + q = PyQuery(response.content) + self.assertEqual(q("#statement-state").text(), "Replaced") + self.assertEqual(q("#statement-type").text(), "Replaced IAB Statement") + self.assertEqual(q("#statement-type").next().text(), f"Replaced by {doc2.name}") + + url = urlreverse( + "ietf.doc.views_doc.document_main", kwargs=dict(name=doc2.name) + ) + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + q = PyQuery(response.content) + self.assertEqual(q("#statement-type").text(), "IAB Statement") + self.assertEqual(q("#statement-type").next().text(), f"Replaces {doc.name}") + + def test_serve_pdf(self): + url = urlreverse( + "ietf.doc.views_statement.serve_pdf", + kwargs=dict(name="statement-does-not-exist"), + ) + r = self.client.get(url) + self.assertEqual(r.status_code, 404) + + doc = StatementFactory() + url = urlreverse( + "ietf.doc.views_statement.serve_pdf", kwargs=dict(name=doc.name) + ) + r = self.client.get(url) + self.assertEqual(r.status_code, 404) # File not found + + self.write_statement_pdf_file(doc) + doc.rev = "01" + e = DocEventFactory(type="published_statement", doc=doc, rev=doc.rev) + doc.save_with_history([e]) + self.write_statement_pdf_file(doc) + + r = self.client.get(url) + self.assertEqual(r.status_code, 200) + self.assertEqual(r.get("Content-Type"), "application/pdf") + self.assertTrue( + self.extract_content(r).startswith(doc.rev) + ) # relies on test doc not actually being pdf + + url = urlreverse( + "ietf.doc.views_statement.serve_pdf", kwargs=dict(name=doc.name, rev="00") + ) + r = self.client.get(url) + self.assertEqual(r.status_code, 200) + self.assertTrue(self.extract_content(r).startswith("00 ")) + url = urlreverse( + "ietf.doc.views_statement.serve_pdf", kwargs=dict(name=doc.name, rev="01") + ) + r = self.client.get(url) + self.assertEqual(r.status_code, 200) + self.assertTrue(self.extract_content(r).startswith("01 ")) + + def test_submit(self): + doc = StatementFactory() + url = urlreverse("ietf.doc.views_statement.submit", kwargs=dict(name=doc.name)) + + rev = doc.rev + r = self.client.post( + url, {"statement_submission": "enter", "statement_content": "# oiwefrase"} + ) + self.assertEqual(r.status_code, 302) + doc = reload_db_objects(doc) + self.assertEqual(rev, doc.rev) + + nobody = PersonFactory() + self.client.login( + username=nobody.user.username, password=nobody.user.username + "+password" + ) + r = self.client.post( + url, {"statement_submission": "enter", "statement_content": "# oiwefrase"} + ) + self.assertEqual(r.status_code, 403) + doc = reload_db_objects(doc) + self.assertEqual(rev, doc.rev) + self.client.logout() + + for username in ["secretary"]: # There is potential for expanding this list + self.client.login(username=username, password=username + "+password") + r = self.client.get(url) + self.assertEqual(r.status_code, 200) + file = SimpleUploadedFile( + "random.pdf", + b"not valid pdf", + content_type="application/pdf", + ) + for postdict in [ + { + "statement_submission": "enter", + "statement_content": f"# {username}", + }, + { + "statement_submission": "upload", + "statement_file": file, + }, + ]: + docevent_count = doc.docevent_set.count() + empty_outbox() + r = self.client.post(url, postdict) + self.assertEqual(r.status_code, 302) + doc = reload_db_objects(doc) + self.assertEqual("%02d" % (int(rev) + 1), doc.rev) + if postdict["statement_submission"] == "enter": + self.assertEqual(f"# {username}", doc.text()) + else: + self.assertEqual("not valid pdf", doc.text()) + self.assertEqual(docevent_count + 1, doc.docevent_set.count()) + self.assertEqual(0, len(outbox)) + rev = doc.rev + self.client.logout() + + def test_start_new_statement(self): + url = urlreverse("ietf.doc.views_statement.new_statement") + login_testing_unauthorized(self, "secretary", url) + r = self.client.get(url) + self.assertContains( + r, + "Replace this with the content of the statement in markdown source", + status_code=200, + ) + group = Group.objects.get(acronym="iab") + r = self.client.post( + url, + dict( + group=group.pk, + title="default", + statement_submission="enter", + statement_content=render_to_string( + "doc/statement/statement_template.md", {"settings": settings} + ), + ), + ) + self.assertContains(r, "The example content may not be saved.", status_code=200) + + file = SimpleUploadedFile( + "random.pdf", + b"not valid pdf", + content_type="application/pdf", + ) + group = Group.objects.get(acronym="iab") + for postdict in [ + dict( + group=group.pk, + title="title one", + statement_submission="enter", + statement_content="some stuff", + ), + dict( + group=group.pk, + title="title two", + statement_submission="upload", + statement_file=file, + ), + ]: + empty_outbox() + r = self.client.post(url, postdict) + self.assertEqual(r.status_code, 302) + name = f"statement-{group.acronym}-{postdict['title']}".replace( + " ", "-" + ) # cheap slugification + statement = Document.objects.filter( + name=name, type_id="statement" + ).first() + self.assertIsNotNone(statement) + self.assertIsNotNone(DocAlias.objects.filter(name=name).first()) + self.assertEqual(statement.title, postdict["title"]) + self.assertEqual(statement.rev, "00") + self.assertEqual(statement.get_state_slug(), "active") + self.assertEqual( + statement.latest_event(NewRevisionDocEvent).rev, "00" + ) + self.assertIsNotNone(statement.latest_event(type="published_statement")) + if postdict["statement_submission"] == "enter": + self.assertEqual(statement.text_or_error(), "some stuff") + else: + self.assertTrue(statement.uploaded_filename.endswith("pdf")) + self.assertEqual(len(outbox), 0) + + existing_statement = StatementFactory() + for postdict in [ + dict( + group=group.pk, + title="", + statement_submission="enter", + statement_content="some stuff", + ), + dict( + group=group.pk, + title="a title", + statement_submission="enter", + statement_content="", + ), + dict( + group=group.pk, + title=existing_statement.title, + statement_submission="enter", + statement_content="some stuff", + ), + dict( + group=group.pk, + title="森川", + statement_submission="enter", + statement_content="some stuff", + ), + dict( + group=group.pk, + title="a title", + statement_submission="", + statement_content="some stuff", + ), + dict( + group="", + title="a title", + statement_submission="enter", + statement_content="some stuff", + ), + dict( + group=0, + title="a title", + statement_submission="enter", + statement_content="some stuff", + ), + ]: + r = self.client.post(url, postdict) + self.assertEqual(r.status_code, 200, f"Wrong status_code for {postdict}") + q = PyQuery(r.content) + self.assertTrue( + q("form div.is-invalid"), f"Expected an error for {postdict}" + ) + + def test_submit_non_markdown_formats(self): + doc = StatementFactory() + + file = SimpleUploadedFile( + "random.pdf", + b"01 This is not valid PDF, but the test does not need it to be", + content_type="application/pdf", + ) + + url = urlreverse("ietf.doc.views_statement.submit", kwargs=dict(name=doc.name)) + login_testing_unauthorized(self, "secretary", url) + + r = self.client.post( + url, + { + "statement_submission": "upload", + "statement_file": file, + }, + ) + self.assertEqual(r.status_code, 302) + self.assertEqual( + r["Location"], + urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=doc.name)), + ) + + doc = reload_db_objects(doc) + self.assertEqual(doc.rev, "01") + r = self.client.get(url) + self.assertEqual(r.status_code, 200) + q = PyQuery(r.content) + self.assertEqual( + q("#id_statement_content").text().strip(), + "The current revision of this statement is in pdf format", + ) + + file = SimpleUploadedFile( + "random.mp4", b"29ucdvn2o09hano5", content_type="video/mp4" + ) + r = self.client.post( + url, {"statement_submission": "upload", "statement_file": file} + ) + self.assertEqual(r.status_code, 200) + q = PyQuery(r.content) + self.assertTrue("Unexpected content" in q("#id_statement_file").next().text()) diff --git a/ietf/doc/tests_status_change.py b/ietf/doc/tests_status_change.py index 571d9ed1db..4064b52523 100644 --- a/ietf/doc/tests_status_change.py +++ b/ietf/doc/tests_status_change.py @@ -14,7 +14,7 @@ from django.conf import settings from django.urls import reverse as urlreverse -from ietf.doc.factories import DocumentFactory, IndividualRfcFactory, WgRfcFactory +from ietf.doc.factories import DocumentFactory, IndividualRfcFactory, WgRfcFactory, DocEventFactory from ietf.doc.models import ( Document, DocAlias, State, DocEvent, BallotPositionDocEvent, NewRevisionDocEvent, TelechatDocEvent, WriteupDocEvent ) from ietf.doc.utils import create_ballot_if_not_open @@ -86,6 +86,16 @@ def test_start_review(self): status_change = Document.objects.get(name='status-change-imaginary-new2') self.assertIsNone(status_change.ad) + # Verify that the right thing happens if a control along the way uppercases RFC + r = self.client.post(url,dict( + document_name="imaginary-new3",title="A new imaginary status change", + create_in_state=state_strpk,notify='ipu@ietf.org',new_relation_row_blah="RFC9999", + statchg_relation_row_blah="tois") + ) + self.assertEqual(r.status_code, 302) + status_change = Document.objects.get(name='status-change-imaginary-new3') + self.assertTrue(status_change.relateddocument_set.filter(relationship__slug='tois',target__name='rfc9999')) + def test_change_state(self): @@ -289,7 +299,19 @@ def test_edit_lc(self): self.assertEqual(r.status_code,200) self.assertContains(r, 'RFC9999 from Proposed Standard to Internet Standard') self.assertContains(r, 'RFC9998 from Informational to Historic') - + q = PyQuery(r.content) + self.assertEqual(len(q("button[name='send_last_call_request']")), 1) + + # Make sure request LC isn't offered with no responsible AD. + doc.ad = None + doc.save_with_history([DocEventFactory(doc=doc)]) + r = self.client.get(url) + self.assertEqual(r.status_code,200) + q = PyQuery(r.content) + self.assertEqual(len(q("button[name='send_last_call_request']")), 0) + doc.ad = Person.objects.get(name='Ad No2') + doc.save_with_history([DocEventFactory(doc=doc)]) + # request last call messages_before = len(outbox) r = self.client.post(url,dict(last_call_text='stuff',send_last_call_request='Save+and+Request+Last+Call')) diff --git a/ietf/doc/urls.py b/ietf/doc/urls.py index f4b6728045..c2addc5c92 100644 --- a/ietf/doc/urls.py +++ b/ietf/doc/urls.py @@ -1,4 +1,4 @@ -# Copyright The IETF Trust 2009-2020, All Rights Reserved +# Copyright The IETF Trust 2009-2023, All Rights Reserved # -*- coding: utf-8 -*- # Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). # All rights reserved. Contact: Pasi Eronen @@ -37,7 +37,7 @@ from django.urls import include from django.views.generic import RedirectView -from ietf.doc import views_search, views_draft, views_ballot, views_status_change, views_doc, views_downref, views_stats, views_help, views_bofreq +from ietf.doc import views_search, views_draft, views_ballot, views_status_change, views_doc, views_downref, views_stats, views_help, views_bofreq, views_statement from ietf.utils.urls import url session_patterns = [ @@ -57,6 +57,7 @@ url(r'^start-rfc-status-change/(?:%(name)s/)?$' % settings.URL_REGEXPS, views_status_change.start_rfc_status_change), url(r'^bof-requests/?$', views_bofreq.bof_requests), url(r'^bof-requests/new/$', views_bofreq.new_bof_request), + url(r'^statement/new/$', views_statement.new_statement), url(r'^iesg/?$', views_search.drafts_in_iesg_process), url(r'^email-aliases/?$', views_doc.email_aliases), url(r'^downref/?$', views_downref.downref_registry), @@ -169,6 +170,7 @@ url(r'^%(charter)s/' % settings.URL_REGEXPS, include('ietf.doc.urls_charter')), url(r'^%(bofreq)s/' % settings.URL_REGEXPS, include('ietf.doc.urls_bofreq')), + url(r'^%(statement)s/' % settings.URL_REGEXPS, include('ietf.doc.urls_statement')), url(r'^%(name)s/conflict-review/' % settings.URL_REGEXPS, include('ietf.doc.urls_conflict_review')), url(r'^%(name)s/status-change/' % settings.URL_REGEXPS, include('ietf.doc.urls_status_change')), url(r'^%(name)s/material/' % settings.URL_REGEXPS, include('ietf.doc.urls_material')), diff --git a/ietf/doc/urls_statement.py b/ietf/doc/urls_statement.py new file mode 100644 index 0000000000..e130c453ba --- /dev/null +++ b/ietf/doc/urls_statement.py @@ -0,0 +1,10 @@ +# Copyright The IETF Trust 2023, All Rights Reserved + +from django.conf import settings +from ietf.doc import views_statement +from ietf.utils.urls import url + +urlpatterns = [ + url(r"^(?:%(rev)s/)?pdf/$" % settings.URL_REGEXPS, views_statement.serve_pdf), + url(r"^submit/$", views_statement.submit), +] diff --git a/ietf/doc/views_ballot.py b/ietf/doc/views_ballot.py index 86c30e22a4..98fb126109 100644 --- a/ietf/doc/views_ballot.py +++ b/ietf/doc/views_ballot.py @@ -721,7 +721,7 @@ def ballot_rfceditornote(request, name): e = WriteupDocEvent(doc=doc, rev=doc.rev, by=login) e.by = login e.type = "changed_rfc_editor_note_text" - e.desc = "RFC Editor Note was changed" + e.desc = f"RFC Editor Note was changed to \n{t}" e.text = t.rstrip() e.save() diff --git a/ietf/doc/views_doc.py b/ietf/doc/views_doc.py index f63530e543..b9b9d89176 100644 --- a/ietf/doc/views_doc.py +++ b/ietf/doc/views_doc.py @@ -1,4 +1,4 @@ -# Copyright The IETF Trust 2009-2022, All Rights Reserved +# Copyright The IETF Trust 2009-2023, All Rights Reserved # -*- coding: utf-8 -*- # # Parts Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies). @@ -79,7 +79,7 @@ from ietf.meeting.models import Session from ietf.meeting.utils import group_sessions, get_upcoming_manageable_sessions, sort_sessions, add_event_info_to_session_qs from ietf.review.models import ReviewAssignment -from ietf.review.utils import can_request_review_of_doc, review_assignments_to_list_for_docs +from ietf.review.utils import can_request_review_of_doc, review_assignments_to_list_for_docs, review_requests_to_list_for_docs from ietf.review.utils import no_review_from_teams_on_doc from ietf.utils import markup_txt, log, markdown from ietf.utils.draft import PlaintextDraft @@ -191,6 +191,9 @@ def interesting_doc_relations(doc): return interesting_relations_that, interesting_relations_that_doc def document_main(request, name, rev=None, document_html=False): + if name.startswith("rfc") and rev is not None: + raise Http404() + doc = get_object_or_404(Document.objects.select_related(), docalias__name=name) # take care of possible redirections @@ -498,6 +501,7 @@ def document_main(request, name, rev=None, document_html=False): started_iesg_process = doc.latest_event(type="started_iesg_process") review_assignments = review_assignments_to_list_for_docs([doc]).get(doc.name, []) + review_requests = review_requests_to_list_for_docs([doc]).get(doc.name, []) no_review_from_teams = no_review_from_teams_on_doc(doc, rev or doc.rev) exp_comment = doc.latest_event(IanaExpertDocEvent,type="comment") @@ -512,11 +516,13 @@ def document_main(request, name, rev=None, document_html=False): # Do not show the Auth48 URL in the "Additional URLs" section additional_urls = doc.documenturl_set.exclude(tag_id='auth48') - # Stream description passing test + # Stream description and name passing test if doc.stream != None: stream_desc = doc.stream.desc + stream = "draft-stream-" + doc.stream.slug else: stream_desc = "(None)" + stream = "(None)" html = None js = None @@ -554,6 +560,7 @@ def document_main(request, name, rev=None, document_html=False): split_content=split_content, revisions=simple_diff_revisions if document_html else revisions, snapshot=snapshot, + stream=stream, stream_desc=stream_desc, latest_revision=latest_revision, latest_rev=latest_rev, @@ -614,6 +621,7 @@ def document_main(request, name, rev=None, document_html=False): actions=actions, presentations=presentations, review_assignments=review_assignments, + review_requests=review_requests, no_review_from_teams=no_review_from_teams, due_date=due_date, diff_revisions=diff_revisions @@ -843,7 +851,40 @@ def document_main(request, name, rev=None, document_html=False): ) ) + if doc.type_id == "statement": + if doc.uploaded_filename: + basename = doc.uploaded_filename.split(".")[0] # strip extension + else: + basename = f"{doc.name}-{doc.rev}" + variants = set([match.name.split(".")[1] for match in Path(doc.get_file_path()).glob(f"{basename}.*")]) + inlineable = any([ext in variants for ext in ["md", "txt"]]) + if inlineable: + content = markdown.markdown(doc.text_or_error()) + else: + content = "No format available to display inline" + if "pdf" in variants: + pdf_url = urlreverse( + "ietf.doc.views_statement.serve_pdf", + kwargs=dict(name=doc.name, rev=doc.rev), + ) + content += f" - Download [pdf]({pdf_url})" + content = markdown.markdown(content) + can_manage = has_role(request.user,["Secretariat"]) # Add IAB or IESG as appropriate + interesting_relations_that, interesting_relations_that_doc = interesting_doc_relations(doc) + published = doc.latest_event(type="published_statement").time + return render(request, "doc/document_statement.html", + dict(doc=doc, + top=top, + revisions=revisions, + latest_rev=latest_rev, + published=published, + content=content, + snapshot=snapshot, + replaces=interesting_relations_that_doc.filter(relationship="replaces"), + replaced_by=interesting_relations_that.filter(relationship="replaces"), + can_manage=can_manage, + )) raise Http404("Document not found: %s" % (name + ("-%s"%rev if rev else ""))) @@ -1081,6 +1122,9 @@ def document_history(request, name): def document_bibtex(request, name, rev=None): + if name.startswith('rfc') and rev is not None: + raise Http404() + # Make sure URL_REGEXPS did not grab too much for the rev number if rev != None and len(rev) != 2: mo = re.search(r"^(?P[0-9]{1,2})-(?P[0-9]{2})$", rev) @@ -1113,6 +1157,11 @@ def document_bibtex(request, name, rev=None): else: doi = None + if doc.is_dochistory(): + latest_event = doc.latest_event(type='new_revision', rev=rev) + if latest_event: + doc.pub_date = latest_event.time + return render(request, "doc/document_bibtex.bib", dict(doc=doc, replaced_by=replaced_by, diff --git a/ietf/doc/views_help.py b/ietf/doc/views_help.py index 43c029ac70..73cdcdd20f 100644 --- a/ietf/doc/views_help.py +++ b/ietf/doc/views_help.py @@ -1,3 +1,5 @@ +# Copyright The IETF Trust 2013-2023, All Rights Reserved + from django.shortcuts import render, get_object_or_404 from django.http import Http404 @@ -5,11 +7,13 @@ from ietf.name.models import DocRelationshipName, DocTagName from ietf.doc.utils import get_tags_for_stream_id -def state_help(request, type): +def state_help(request, type=None): slug, title = { "draft-iesg": ("draft-iesg", "IESG States for Internet-Drafts"), "draft-rfceditor": ("draft-rfceditor", "RFC Editor States for Internet-Drafts"), "draft-iana-action": ("draft-iana-action", "IANA Action States for Internet-Drafts"), + "draft-iana-review": ("draft-iana-review", "IANA Review States for Internet-Drafts"), + "draft-iana-experts": ("draft-iana-experts", "IANA Expert Review States for Internet-Drafts"), "draft-stream-ietf": ("draft-stream-ietf", "IETF Stream States for Internet-Drafts"), "draft-stream-irtf": ("draft-stream-irtf", "IRTF Stream States for Internet-Drafts"), "draft-stream-ise": ("draft-stream-ise", "ISE Stream States for Internet-Drafts"), @@ -19,10 +23,11 @@ def state_help(request, type): "status-change": ("statchg", "RFC Status Change States"), "bofreq": ("bofreq", "BOF Request States"), "procmaterials": ("procmaterials", "Proceedings Materials States"), + "statement": {"statement", "Statement States"} }.get(type, (None, None)) state_type = get_object_or_404(StateType, slug=slug) - states = State.objects.filter(type=state_type).order_by("order") + states = State.objects.filter(used=True, type=state_type).order_by("order") has_next_states = False for state in states: diff --git a/ietf/doc/views_review.py b/ietf/doc/views_review.py index fa6e3a7ffe..f758032f95 100644 --- a/ietf/doc/views_review.py +++ b/ietf/doc/views_review.py @@ -389,9 +389,6 @@ def reject_reviewer_assignment(request, name, assignment_id): state=review_assignment.state, ) - policy = get_reviewer_queue_policy(review_assignment.review_request.team) - policy.return_reviewer_to_rotation_top(review_assignment.reviewer.person, form.cleaned_data['wants_to_be_next']) - msg = render_to_string("review/reviewer_assignment_rejected.txt", { "by": request.user.person, "message_to_secretary": form.cleaned_data.get("message_to_secretary"), @@ -441,7 +438,7 @@ def withdraw_reviewer_assignment(request, name, assignment_id): ) policy = get_reviewer_queue_policy(review_assignment.review_request.team) - policy.return_reviewer_to_rotation_top(review_assignment.reviewer.person, True) + policy.set_wants_to_be_next(review_assignment.reviewer.person) msg = "Review assignment withdrawn by %s"%request.user.person diff --git a/ietf/doc/views_search.py b/ietf/doc/views_search.py index c500e702eb..6645333cc0 100644 --- a/ietf/doc/views_search.py +++ b/ietf/doc/views_search.py @@ -58,7 +58,7 @@ IESG_BALLOT_ACTIVE_STATES, IESG_STATCHG_CONFLREV_ACTIVE_STATES, IESG_CHARTER_ACTIVE_STATES ) from ietf.doc.fields import select2_id_doc_name_json -from ietf.doc.utils import get_search_cache_key, augment_events_with_revision +from ietf.doc.utils import get_search_cache_key, augment_events_with_revision, needed_ballot_positions from ietf.group.models import Group from ietf.idindex.index import active_drafts_index_by_group from ietf.name.models import DocTagName, DocTypeName, StreamName @@ -290,8 +290,8 @@ def cached_redirect(cache_key, url): redirect_to = find_unique(rev_split.group(1)) if redirect_to: rev = rev_split.group(2) - # check if we can redirect directly to the rev - if DocHistory.objects.filter(doc__docalias__name=redirect_to, rev=rev).exists(): + # check if we can redirect directly to the rev if it's draft, if rfc - always redirect to main page + if not redirect_to.startswith('rfc') and DocHistory.objects.filter(doc__docalias__name=redirect_to, rev=rev).exists(): return cached_redirect(cache_key, urlreverse("ietf.doc.views_doc.document_main", kwargs={ "name": redirect_to, "rev": rev })) else: return cached_redirect(cache_key, urlreverse("ietf.doc.views_doc.document_main", kwargs={ "name": redirect_to })) @@ -497,6 +497,7 @@ def ad_workload(request): [ ("Publication Requested Internet-Draft", False), ("AD Evaluation Internet-Draft", False), + ("Last Call Requested Internet-Draft", True), ("In Last Call Internet-Draft", True), ("Waiting for Writeup Internet-Draft", False), ("IESG Evaluation - Defer Internet-Draft", False), @@ -532,6 +533,7 @@ def ad_workload(request): [ ("Publication Requested Status Change", False), ("AD Evaluation Status Change", False), + ("Last Call Requested Status Change", True), ("In Last Call Status Change", True), ("Waiting for Writeup Status Change", False), ("IESG Evaluation Status Change", True), @@ -705,18 +707,20 @@ def docs_for_ad(request, name): for d in results: d.search_heading = ad_dashboard_group(d) - # - # Additional content showing docs with blocking positions by this ad + + # Additional content showing docs with blocking positions by this AD, + # and docs that the AD hasn't balloted on that are lacking ballot positions to progress blocked_docs = [] + not_balloted_docs = [] if ad in get_active_ads(): - possible_docs = Document.objects.filter(Q(states__type="draft-iesg", - states__slug__in=IESG_BALLOT_ACTIVE_STATES) | - Q(states__type="charter", - states__slug__in=IESG_CHARTER_ACTIVE_STATES) | - Q(states__type__in=("statchg", "conflrev"), - states__slug__in=IESG_STATCHG_CONFLREV_ACTIVE_STATES), - docevent__ballotpositiondocevent__pos__blocking=True, - docevent__ballotpositiondocevent__balloter=ad).distinct() + iesg_docs = Document.objects.filter(Q(states__type="draft-iesg", + states__slug__in=IESG_BALLOT_ACTIVE_STATES) | + Q(states__type="charter", + states__slug__in=IESG_CHARTER_ACTIVE_STATES) | + Q(states__type__in=("statchg", "conflrev"), + states__slug__in=IESG_STATCHG_CONFLREV_ACTIVE_STATES)).distinct() + possible_docs = iesg_docs.filter(docevent__ballotpositiondocevent__pos__blocking=True, + docevent__ballotpositiondocevent__balloter=ad) for doc in possible_docs: ballot = doc.active_ballot() if not ballot: @@ -737,12 +741,26 @@ def docs_for_ad(request, name): if blocked_docs: blocked_docs.sort(key=lambda d: min(p.time for p in d.blocking_positions if p.balloter==ad), reverse=True) - for d in blocked_docs: - if d.get_base_name() == 'charter-ietf-shmoo-01-04.txt': - print('Is in list') + possible_docs = iesg_docs.exclude( + Q(docevent__ballotpositiondocevent__balloter=ad) + ) + for doc in possible_docs: + ballot = doc.active_ballot() + if ( + not ballot + or doc.get_state_slug("draft") == "repl" + or (doc.telechat_date() and doc.telechat_date() > timezone.now().date()) + ): + continue + + iesg_ballot_summary = needed_ballot_positions( + doc, list(ballot.active_balloter_positions().values()) + ) + if re.search(r"\bNeeds\s+\d+", iesg_ballot_summary): + not_balloted_docs.append(doc) return render(request, 'doc/drafts_for_ad.html', { - 'form':form, 'docs':results, 'meta':meta, 'ad_name': ad.plain_name(), 'blocked_docs': blocked_docs + 'form':form, 'docs':results, 'meta':meta, 'ad_name': ad.plain_name(), 'blocked_docs': blocked_docs, 'not_balloted_docs': not_balloted_docs }) def drafts_in_last_call(request): lc_state = State.objects.get(type="draft-iesg", slug="lc").pk diff --git a/ietf/doc/views_statement.py b/ietf/doc/views_statement.py new file mode 100644 index 0000000000..0ffa6a3c4d --- /dev/null +++ b/ietf/doc/views_statement.py @@ -0,0 +1,274 @@ +# Copyright The IETF Trust 2023, All Rights Reserved + +import debug # pyflakes: ignore + +from pathlib import Path + +from django import forms +from django.conf import settings +from django.http import FileResponse, Http404 +from django.views.decorators.cache import cache_control +from django.shortcuts import get_object_or_404, render, redirect +from django.template.loader import render_to_string +from ietf.utils import markdown +from django.utils.html import escape + +from ietf.doc.models import Document, DocAlias, DocEvent, NewRevisionDocEvent, State +from ietf.group.models import Group +from ietf.ietfauth.utils import role_required +from ietf.utils.text import xslugify +from ietf.utils.textupload import get_cleaned_text_file_content + +CONST_PDF_REV_NOTICE = "The current revision of this statement is in pdf format" + + +@cache_control(max_age=3600) +def serve_pdf(self, name, rev=None): + doc = get_object_or_404(Document, name=name) + if rev is None: + rev = doc.rev + p = Path(doc.get_file_path()).joinpath(f"{doc.name}-{rev}.pdf") + if not p.exists(): + raise Http404 + else: + return FileResponse(p.open(mode="rb"), content_type="application/pdf") + + +class StatementUploadForm(forms.Form): + ACTIONS = [ + ("enter", "Enter content directly"), + ("upload", "Upload content from file"), + ] + statement_submission = forms.ChoiceField(choices=ACTIONS, widget=forms.RadioSelect) + statement_file = forms.FileField( + label="Markdown or PDF source file to upload", required=False + ) + statement_content = forms.CharField( + widget=forms.Textarea(attrs={"rows": 30}), required=False, strip=False + ) + + def clean(self): + def require_field(f): + if not self.cleaned_data.get(f): + self.add_error(f, forms.ValidationError("You must fill in this field.")) + return False + else: + return True + + submission_method = self.cleaned_data.get("statement_submission") + markdown_content = "" + if submission_method == "enter": + if require_field("statement_content"): + markdown_content = self.cleaned_data["statement_content"].replace( + "\r", "" + ) + default_content = render_to_string( + "doc/statement/statement_template.md", {} + ) + if markdown_content == default_content: + raise forms.ValidationError( + "The example content may not be saved. Edit it to contain the next revision statement content." + ) + if markdown_content == CONST_PDF_REV_NOTICE: + raise forms.ValidationError( + "Not proceeding with the text noting that the current version is pdf. Did you mean to upload a new PDF?" + ) + elif submission_method == "upload": + if require_field("statement_file"): + content_type = self.cleaned_data["statement_file"].content_type + acceptable_types = ( + "application/pdf", + ) + settings.DOC_TEXT_FILE_VALID_UPLOAD_MIME_TYPES + if not content_type.startswith( + acceptable_types + ): # dances around decoration of types with encoding etc. + self.add_error( + "statement_file", + forms.ValidationError( + f"Unexpected content type: Expected one of {', '.join(acceptable_types)}" + ), + ) + elif content_type != "application/pdf": + markdown_content = get_cleaned_text_file_content( + self.cleaned_data["statement_file"] + ) + if markdown_content != "": + try: + _ = markdown.markdown(markdown_content) + except Exception as e: + raise forms.ValidationError(f"Markdown processing failed: {e}") + + +@role_required("Secretariat") +def submit(request, name): + statement = get_object_or_404(Document, type="statement", name=name) + + if request.method == "POST": + form = StatementUploadForm(request.POST, request.FILES) + if form.is_valid(): + statement_submission = form.cleaned_data["statement_submission"] + writing_pdf = ( + statement_submission == "upload" + and form.cleaned_data["statement_file"].content_type + == "application/pdf" + ) + + statement.rev = "%02d" % (int(statement.rev) + 1) + statement.uploaded_filename = ( + f"{statement.name}-{statement.rev}.{'pdf' if writing_pdf else 'md'}" + ) + e = NewRevisionDocEvent.objects.create( + type="new_revision", + doc=statement, + by=request.user.person, + rev=statement.rev, + desc="New revision available", + ) + statement.save_with_history([e]) + markdown_content = "" + if statement_submission == "upload": + if not writing_pdf: + markdown_content = get_cleaned_text_file_content( + form.cleaned_data["statement_file"] + ) + else: + markdown_content = form.cleaned_data["statement_content"] + with Path(statement.get_file_name()).open( + mode="wb" if writing_pdf else "w" + ) as destination: + if writing_pdf: + for chunk in form.cleaned_data["statement_file"].chunks(): + destination.write(chunk) + else: + destination.write(markdown_content) + return redirect("ietf.doc.views_doc.document_main", name=statement.name) + + else: + if statement.uploaded_filename.endswith("pdf"): + text = CONST_PDF_REV_NOTICE + else: + text = statement.text_or_error() + init = { + "statement_content": text, + "statement_submission": "enter", + } + form = StatementUploadForm(initial=init) + return render( + request, "doc/statement/upload_content.html", {"form": form, "doc": statement} + ) + + +class NewStatementForm(StatementUploadForm): + group = forms.ModelChoiceField( + queryset=Group.objects.filter(acronym__in=["iab", "iesg"]) + ) + title = forms.CharField(max_length=255) + field_order = [ + "group", + "title", + "statement_submission", + "statement_file", + "statement_content", + ] + + def name_from_title_and_group(self, title, group): + title_slug = xslugify(title) + if title_slug.startswith(f"{group.acronym}-"): + title_slug = title_slug[len(f"{group.acronym}-") :] + name = f"statement-{group.acronym}-{title_slug[:240]}" + return name.replace("_", "-") + + def clean(self): + if all([field in self.cleaned_data for field in ["title", "group"]]): + title = self.cleaned_data["title"] + group = self.cleaned_data["group"] + name = self.name_from_title_and_group(title, group) + if name == self.name_from_title_and_group("", group): + self.add_error( + "title", + forms.ValidationError( + "The filename derived from this title is empty. Please include a few descriptive words using ascii or numeric characters" + ), + ) + if Document.objects.filter(name=name).exists(): + self.add_error( + "title", + forms.ValidationError( + "This title produces a filename already used by an existing statement" + ), + ) + return super().clean() + + +@role_required("Secretariat") +def new_statement(request): + if request.method == "POST": + form = NewStatementForm(request.POST, request.FILES) + if form.is_valid(): + statement_submission = form.cleaned_data["statement_submission"] + writing_pdf = ( + statement_submission == "upload" + and form.cleaned_data["statement_file"].content_type + == "application/pdf" + ) + + group = form.cleaned_data["group"] + title = form.cleaned_data["title"] + name = form.name_from_title_and_group(title, group) + statement = Document.objects.create( + type_id="statement", + group=group, + name=name, + title=title, + abstract="", + rev="00", + uploaded_filename=f"{name}-00.{'pdf' if writing_pdf else 'md'}", + ) + statement.set_state(State.objects.get(type_id="statement", slug="active")) + e1 = NewRevisionDocEvent.objects.create( + type="new_revision", + doc=statement, + by=request.user.person, + rev=statement.rev, + desc="New revision available", + time=statement.time, + ) + e2 = DocEvent.objects.create( + type="published_statement", + doc=statement, + rev=statement.rev, + by=request.user.person, + desc="Statement published", + ) + statement.save_with_history([e1, e2]) + alias = DocAlias.objects.create(name=name) + alias.docs.set([statement]) + markdown_content = "" + if statement_submission == "upload": + if not writing_pdf: + markdown_content = get_cleaned_text_file_content( + form.cleaned_data["statement_file"] + ) + else: + markdown_content = form.cleaned_data["statement_content"] + with Path(statement.get_file_name()).open( + mode="wb" if writing_pdf else "w" + ) as destination: + if writing_pdf: + for chunk in form.cleaned_data["statement_file"].chunks(): + destination.write(chunk) + else: + destination.write(markdown_content) + return redirect("ietf.doc.views_doc.document_main", name=statement.name) + + else: + init = { + "statement_content": escape( + render_to_string( + "doc/statement/statement_template.md", {"settings": settings} + ) + ), + "statement_submission": "enter", + } + form = NewStatementForm(initial=init) + return render(request, "doc/statement/new_statement.html", {"form": form}) diff --git a/ietf/doc/views_status_change.py b/ietf/doc/views_status_change.py index ec914eebeb..5f9b6090fc 100644 --- a/ietf/doc/views_status_change.py +++ b/ietf/doc/views_status_change.py @@ -418,7 +418,7 @@ def clean_helper(form, formtype): rfc_fields = {} status_fields={} for k in sorted(form.data.keys()): - v = form.data[k] + v = form.data[k].lower() if k.startswith('new_relation_row'): if re.match(r'\d{1,4}',v): v = 'rfc'+v @@ -685,7 +685,7 @@ def last_call(request, name): form = LastCallTextForm(initial=dict(last_call_text=escape(last_call_event.text))) if request.method == 'POST': - if "save_last_call_text" in request.POST or "send_last_call_request" in request.POST: + if "save_last_call_text" in request.POST or ("send_last_call_request" in request.POST and status_change.ad is not None): form = LastCallTextForm(request.POST) if form.is_valid(): events = [] diff --git a/ietf/group/tests_info.py b/ietf/group/tests_info.py index cc90c4477b..e0a738d073 100644 --- a/ietf/group/tests_info.py +++ b/ietf/group/tests_info.py @@ -283,12 +283,6 @@ def test_group_charter(self): self.assertContains(r, milestone.desc) self.assertContains(r, milestone.docs.all()[0].name) - def test_about_rendertest(self): - group = CharterFactory().group - url = urlreverse('ietf.group.views.group_about_rendertest', kwargs=dict(acronym=group.acronym)) - r = self.client.get(url) - self.assertEqual(r.status_code,200) - def test_group_about(self): diff --git a/ietf/group/tests_review.py b/ietf/group/tests_review.py index 6b673ad959..af374f6765 100644 --- a/ietf/group/tests_review.py +++ b/ietf/group/tests_review.py @@ -101,8 +101,20 @@ def test_suggested_review_requests(self): self.assertEqual(list(suggested_review_requests_for_team(team)), []) + # blocked by an already existing request (don't suggest it again) + review_req.state_id = "requested" + review_req.save() + self.assertEqual(list(suggested_review_requests_for_team(team)), []) + + # ... but not for a previous version + review_req.requested_rev = prev_rev + review_req.save() + self.assertEqual(len(suggested_review_requests_for_team(team)), 1) + + # blocked by completion review_req.state = ReviewRequestStateName.objects.get(slug="assigned") + review_req.requested_rev = "" review_req.save() assignment.state = ReviewAssignmentStateName.objects.get(slug="completed") assignment.reviewed_rev = review_req.doc.rev @@ -116,6 +128,7 @@ def test_suggested_review_requests(self): self.assertEqual(len(suggested_review_requests_for_team(team)), 1) + def test_suggested_review_requests_on_lc_and_telechat(self): review_req = ReviewRequestFactory(state_id='assigned') doc = review_req.doc @@ -199,13 +212,13 @@ def test_reviewer_overview(self): r = self.client.get(url) self.assertEqual(r.status_code, 200) # review team members can see reason for being unavailable - self.assertContains(r, "Availability") + self.assertContains(r, "Available") self.client.login(username="secretary", password="secretary+password") r = self.client.get(url) self.assertEqual(r.status_code, 200) # secretariat can see reason for being unavailable - self.assertContains(r, "Availability") + self.assertContains(r, "Available") # add one closed review with no response and see it is visible review_req2 = ReviewRequestFactory(state_id='completed',team=team) diff --git a/ietf/group/urls.py b/ietf/group/urls.py index 0e4f7ef2fb..814fb9733a 100644 --- a/ietf/group/urls.py +++ b/ietf/group/urls.py @@ -1,4 +1,4 @@ -# Copyright The IETF Trust 2013-2020, All Rights Reserved +# Copyright The IETF Trust 2013-2023, All Rights Reserved from django.conf import settings from django.urls import include @@ -20,7 +20,6 @@ url(r'^documents/subscription/$', community_views.subscription), url(r'^charter/$', views.group_about), url(r'^about/$', views.group_about), - url(r'^about/rendertest/$', views.group_about_rendertest), url(r'^about/status/$', views.group_about_status), url(r'^about/status/edit/$', views.group_about_status_edit), url(r'^about/status/meeting/(?P\d+)/$', views.group_about_status_meeting), @@ -48,6 +47,7 @@ url(r'^secretarysettings/$', views.change_review_secretary_settings), url(r'^reset_next_reviewer/$', views.reset_next_reviewer), url(r'^email-aliases/$', RedirectView.as_view(pattern_name=views.email,permanent=False),name='ietf.group.urls_info_details.redirect.email'), + url(r'^statements/$', views.statements), ] diff --git a/ietf/group/utils.py b/ietf/group/utils.py index b701d6a7c7..b82474b497 100644 --- a/ietf/group/utils.py +++ b/ietf/group/utils.py @@ -1,4 +1,4 @@ -# Copyright The IETF Trust 2012-2021, All Rights Reserved +# Copyright The IETF Trust 2012-2023, All Rights Reserved # -*- coding: utf-8 -*- @@ -233,6 +233,8 @@ def construct_group_menu_context(request, group, selected, group_type, others): if group.features.has_meetings: entries.append(("Meetings", urlreverse("ietf.group.views.meetings", kwargs=kwargs))) + if group.acronym in ["iab", "iesg"]: + entries.append(("Statements", urlreverse("ietf.group.views.statements", kwargs=kwargs))) entries.append(("History", urlreverse("ietf.group.views.history", kwargs=kwargs))) entries.append(("Photos", urlreverse("ietf.group.views.group_photos", kwargs=kwargs))) entries.append(("Email expansions", urlreverse("ietf.group.views.email", kwargs=kwargs))) diff --git a/ietf/group/views.py b/ietf/group/views.py index 88b25a1091..19c277c763 100644 --- a/ietf/group/views.py +++ b/ietf/group/views.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright The IETF Trust 2009-2022, All Rights Reserved +# Copyright The IETF Trust 2009-2023, All Rights Reserved # # Portion Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). # All rights reserved. Contact: Pasi Eronen @@ -48,7 +48,7 @@ from django import forms from django.conf import settings from django.contrib.auth.decorators import login_required -from django.db.models import Q, Count +from django.db.models import Q, Count, OuterRef, Subquery from django.http import HttpResponse, HttpResponseRedirect, Http404, JsonResponse from django.shortcuts import render, redirect, get_object_or_404 from django.template.loader import render_to_string @@ -61,7 +61,7 @@ from ietf.community.models import CommunityList, EmailSubscription from ietf.community.utils import docs_tracked_by_community_list -from ietf.doc.models import DocTagName, State, DocAlias, RelatedDocument, Document +from ietf.doc.models import DocTagName, State, DocAlias, RelatedDocument, Document, DocEvent from ietf.doc.templatetags.ietf_filters import clean_whitespace from ietf.doc.utils import get_chartering_type, get_tags_for_stream_id from ietf.doc.utils_charter import charter_name_for_group, replace_charter_of_replaced_group @@ -604,17 +604,6 @@ def all_status(request): } ) -def group_about_rendertest(request, acronym, group_type=None): - group = get_group_or_404(acronym, group_type) - charter = None - if group.charter: - charter = get_charter_text(group) - try: - rendered = markdown.markdown(charter) - except Exception as e: - rendered = f'Markdown rendering failed: {e}' - return render(request, 'group/group_about_rendertest.html', {'group':group, 'charter':charter, 'rendered':rendered}) - def group_about_status(request, acronym, group_type=None): group = get_group_or_404(acronym, group_type) status_update = group.latest_event(type='status_update') @@ -2093,7 +2082,32 @@ def reset_next_reviewer(request, acronym, group_type=None): return render(request, 'group/reset_next_reviewer.html', { 'group':group, 'form': form,}) - +def statements(request, acronym, group_type=None): + if not acronym in ["iab", "iesg"]: + raise Http404 + group = get_group_or_404(acronym, group_type) + statements = group.document_set.filter(type_id="statement").annotate( + published=Subquery( + DocEvent.objects.filter( + doc=OuterRef("pk"), + type="published_statement" + ).order_by("-time").values("time")[:1] + ) + ).order_by("-published") + return render( + request, + "group/statements.html", + construct_group_menu_context( + request, + group, + "statements", + group_type, + { + "group": group, + "statements": statements, + }, + ), + ) diff --git a/ietf/ietfauth/utils.py b/ietf/ietfauth/utils.py index 52f582ca86..6fa9cddbcb 100644 --- a/ietf/ietfauth/utils.py +++ b/ietf/ietfauth/utils.py @@ -223,7 +223,7 @@ def is_bofreq_editor(user, doc): def openid_userinfo(claims, user): # Populate claims dict. person = get_object_or_404(Person, user=user) - email = person.email() + email = person.email_allowing_inactive() if person.photo: photo_url = person.cdn_photo_url() else: diff --git a/ietf/mailtrigger/migrations/0002_slidesubmitter.py b/ietf/mailtrigger/migrations/0002_slidesubmitter.py new file mode 100644 index 0000000000..394c7d92ce --- /dev/null +++ b/ietf/mailtrigger/migrations/0002_slidesubmitter.py @@ -0,0 +1,31 @@ +# Copyright The IETF Trust 2023, All Rights Reserved + +from django.db import migrations + +def forward(apps, schema_editor): + MailTrigger = apps.get_model("mailtrigger", "MailTrigger") + Recipient = apps.get_model("mailtrigger", "Recipient") + r = Recipient.objects.create( + slug="slides_proposer", + desc="Person who proposed slides", + template="{{ proposer.email }}" + ) + mt = MailTrigger.objects.get(slug="slides_proposed") + mt.cc.add(r) + +def reverse(apps, schema_editor): + MailTrigger = apps.get_model("mailtrigger", "MailTrigger") + Recipient = apps.get_model("mailtrigger", "Recipient") + mt = MailTrigger.objects.get(slug="slides_proposed") + r = Recipient.objects.get(slug="slides_proposer") + mt.cc.remove(r) + r.delete() + +class Migration(migrations.Migration): + dependencies = [ + ("mailtrigger", "0001_initial"), + ] + + operations = [ + migrations.RunPython(forward, reverse) + ] diff --git a/ietf/mailtrigger/utils.py b/ietf/mailtrigger/utils.py index 48d91ff6aa..496f20dc28 100644 --- a/ietf/mailtrigger/utils.py +++ b/ietf/mailtrigger/utils.py @@ -1,4 +1,4 @@ -# Copyright The IETF Trust 2015-2019, All Rights Reserved +# Copyright The IETF Trust 2015-2023, All Rights Reserved from collections import namedtuple @@ -70,7 +70,7 @@ def starts_with(prefix): relevant.add('doc_state_edited') - if not doc.type_id in ['bofreq',]: + if not doc.type_id in ['bofreq', 'statement']: relevant.update(['doc_telechat_details_changed','ballot_deferred','iesg_ballot_saved']) if doc.type_id in ['draft','statchg']: diff --git a/ietf/meeting/tests_views.py b/ietf/meeting/tests_views.py index 50323a5433..9609fad3df 100644 --- a/ietf/meeting/tests_views.py +++ b/ietf/meeting/tests_views.py @@ -648,6 +648,20 @@ def do_test_materials(self, meeting, session): self.assertFalse(row.find("a:contains(\"Bad Slideshow\")")) # test with no meeting number in url + # Add various group sessions + groups = [] + parent_groups = [ + GroupFactory.create(type_id="area", acronym="gen"), + GroupFactory.create(acronym="iab"), + GroupFactory.create(acronym="irtf"), + ] + for parent in parent_groups: + groups.append(GroupFactory.create(parent=parent)) + for acronym in ["rsab", "edu"]: + groups.append(GroupFactory.create(acronym=acronym)) + for group in groups: + SessionFactory(meeting=meeting, group=group) + self.write_materials_files(meeting, session) url = urlreverse("ietf.meeting.views.materials", kwargs=dict()) r = self.client.get(url) self.assertEqual(r.status_code, 200) @@ -657,6 +671,10 @@ def do_test_materials(self, meeting, session): self.assertTrue(row.find('a:contains("Minutes")')) self.assertTrue(row.find('a:contains("Slideshow")')) self.assertFalse(row.find("a:contains(\"Bad Slideshow\")")) + # test for different sections + sections = ["plenaries", "gen", "iab", "editorial", "irtf", "training"] + for section in sections: + self.assertEqual(len(q(f"#{section}")), 1, f"{section} section should exists in proceedings") # test with a loggged-in wg chair self.client.login(username="marschairman", password="marschairman+password") @@ -7632,6 +7650,13 @@ def _assertProceedingsMaterialsDisplayed(self, response, meeting): 'Correct title and link for each ProceedingsMaterial should appear in the correct order' ) + def _assertGroupSessions(self, response, meeting): + """Checks that group/sessions are present""" + pq = PyQuery(response.content) + sections = ["plenaries", "gen", "iab", "editorial", "irtf", "training"] + for section in sections: + self.assertEqual(len(pq(f"#{section}")), 1, f"{section} section should exists in proceedings") + def test_proceedings(self): """Proceedings should be displayed correctly @@ -7645,6 +7670,20 @@ def test_proceedings(self): SessionPresentationFactory(document__type_id='recording',session=session) SessionPresentationFactory(document__type_id='recording',session=session,document__title="Audio recording for tests") + # Add various group sessions + groups = [] + parent_groups = [ + GroupFactory.create(type_id="area", acronym="gen"), + GroupFactory.create(acronym="iab"), + GroupFactory.create(acronym="irtf"), + ] + for parent in parent_groups: + groups.append(GroupFactory.create(parent=parent)) + for acronym in ["rsab", "edu"]: + groups.append(GroupFactory.create(acronym=acronym)) + for group in groups: + SessionFactory(meeting=meeting, group=group) + self.write_materials_files(meeting, session) self._create_proceedings_materials(meeting) @@ -7691,6 +7730,7 @@ def test_proceedings(self): # configurable contents self._assertMeetingHostsDisplayed(r, meeting) self._assertProceedingsMaterialsDisplayed(r, meeting) + self._assertGroupSessions(r, meeting) def test_named_session(self): """Session with a name should appear separately in the proceedings""" diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py index eded3c438a..e0364e63b5 100644 --- a/ietf/meeting/views.py +++ b/ietf/meeting/views.py @@ -159,18 +159,19 @@ def materials(request, num=None): irtf = sessions.filter(group__parent__acronym = 'irtf') training = sessions.filter(group__acronym__in=['edu','iaoc'], type_id__in=['regular', 'other', ]) iab = sessions.filter(group__parent__acronym = 'iab') + editorial = sessions.filter(group__acronym__in=['rsab','rswg']) - session_pks = [s.pk for ss in [plenaries, ietf, irtf, training, iab] for s in ss] + session_pks = [s.pk for ss in [plenaries, ietf, irtf, training, iab, editorial] for s in ss] other = sessions.filter(type__in=['regular'], group__type__features__has_meetings=True).exclude(pk__in=session_pks) - for topic in [plenaries, ietf, training, irtf, iab]: + for topic in [plenaries, ietf, training, irtf, iab, editorial]: for event in topic: date_list = [] for slide_event in event.all_meeting_slides(): date_list.append(slide_event.time) for agenda_event in event.all_meeting_agendas(): date_list.append(agenda_event.time) if date_list: setattr(event, 'last_update', sorted(date_list, reverse=True)[0]) - for session_list in [plenaries, ietf, training, irtf, iab, other]: + for session_list in [plenaries, ietf, training, irtf, iab, editorial, other]: for session in session_list: session.past_cutoff_date = past_cutoff_date @@ -183,6 +184,7 @@ def materials(request, num=None): irtf, _ = organize_proceedings_sessions(irtf) training, _ = organize_proceedings_sessions(training) iab, _ = organize_proceedings_sessions(iab) + editorial, _ = organize_proceedings_sessions(editorial) other, _ = organize_proceedings_sessions(other) ietf_areas = [] @@ -202,6 +204,7 @@ def materials(request, num=None): 'training': training, 'irtf': irtf, 'iab': iab, + 'editorial': editorial, 'other': other, 'cut_off_date': cut_off_date, 'cor_cut_off_date': cor_cut_off_date, @@ -1704,9 +1707,11 @@ def api_get_session_materials (request, session_id=None): }) else: pass # no action available if it's past cutoff - + + agenda = session.agenda() + agenda_url = agenda.get_href() if agenda is not None else None return JsonResponse({ - "url": session.agenda().get_href(), + "url": agenda_url, "slides": { "decks": list(map(agenda_extract_slide, session.slides())), "actions": slides_actions, @@ -2885,7 +2890,7 @@ def propose_session_slides(request, session_id, num): submission.filename = filename submission.save() - (to, cc) = gather_address_lists('slides_proposed', group=session.group).as_strings() + (to, cc) = gather_address_lists('slides_proposed', group=session.group, proposer=request.user.person).as_strings() msg_txt = render_to_string("meeting/slides_proposed.txt", { "to": to, "cc": cc, @@ -3777,6 +3782,10 @@ def proceedings(request, num=None): sessions.filter(group__parent__acronym = 'iab') .exclude(current_status='notmeet') ) + editorial, _ = organize_proceedings_sessions( + sessions.filter(group__acronym__in=['rsab','rswg']) + .exclude(current_status='notmeet') + ) ietf = sessions.filter(group__parent__type__slug = 'area').exclude(group__acronym='edu').order_by('group__parent__acronym', 'group__acronym') ietf_areas = [] @@ -3796,6 +3805,7 @@ def proceedings(request, num=None): 'training': training, 'irtf': irtf, 'iab': iab, + 'editorial': editorial, 'ietf_areas': ietf_areas, 'cut_off_date': cut_off_date, 'cor_cut_off_date': cor_cut_off_date, diff --git a/ietf/name/fixtures/names.json b/ietf/name/fixtures/names.json index 58bc3859ce..f746231a4a 100644 --- a/ietf/name/fixtures/names.json +++ b/ietf/name/fixtures/names.json @@ -2539,6 +2539,32 @@ "model": "doc.state", "pk": 174 }, + { + "fields": { + "desc": "The statement is active", + "name": "Active", + "next_states": [], + "order": 0, + "slug": "active", + "type": "statement", + "used": true + }, + "model": "doc.state", + "pk": 175 + }, + { + "fields": { + "desc": "The statement has been replaced", + "name": "Replaced", + "next_states": [], + "order": 0, + "slug": "replaced", + "type": "statement", + "used": true + }, + "model": "doc.state", + "pk": 176 + }, { "fields": { "label": "State" @@ -2742,6 +2768,13 @@ "model": "doc.statetype", "pk": "statchg" }, + { + "fields": { + "label": "Statement State" + }, + "model": "doc.statetype", + "pk": "statement" + }, { "fields": { "about_page": "ietf.group.views.group_about", @@ -5557,7 +5590,9 @@ }, { "fields": { - "cc": [], + "cc": [ + "slides_proposer" + ], "desc": "Recipients when slides are proposed for a given session", "to": [ "group_chairs", @@ -6348,6 +6383,14 @@ "model": "mailtrigger.recipient", "pk": "session_requests" }, + { + "fields": { + "desc": "Person who proposed slides", + "template": "{{ proposer.email }}" + }, + "model": "mailtrigger.recipient", + "pk": "slides_proposer" + }, { "fields": { "desc": "The managers of any related streams", @@ -10593,6 +10636,17 @@ "model": "name.doctypename", "pk": "statchg" }, + { + "fields": { + "desc": "", + "name": "Statement", + "order": 0, + "prefix": "statement", + "used": true + }, + "model": "name.doctypename", + "pk": "statement" + }, { "fields": { "desc": "", @@ -11059,8 +11113,9 @@ { "fields": { "desc": "", + "legend": "C", "name": "Comment", - "order": 0, + "order": 1, "used": true }, "model": "name.feedbacktypename", @@ -11069,8 +11124,9 @@ { "fields": { "desc": "", + "legend": "J", "name": "Junk", - "order": 0, + "order": 5, "used": true }, "model": "name.feedbacktypename", @@ -11079,8 +11135,9 @@ { "fields": { "desc": "", + "legend": "N", "name": "Nomination", - "order": 0, + "order": 2, "used": true }, "model": "name.feedbacktypename", @@ -11089,8 +11146,20 @@ { "fields": { "desc": "", + "legend": "O", + "name": "Overcome by events", + "order": 4, + "used": true + }, + "model": "name.feedbacktypename", + "pk": "obe" + }, + { + "fields": { + "desc": "", + "legend": "Q", "name": "Questionnaire response", - "order": 0, + "order": 3, "used": true }, "model": "name.feedbacktypename", @@ -11099,8 +11168,9 @@ { "fields": { "desc": "", + "legend": "R", "name": "Read", - "order": 0, + "order": 6, "used": true }, "model": "name.feedbacktypename", @@ -13180,7 +13250,7 @@ "desc": "Flipchars", "name": "Flipcharts", "order": 0, - "used": true + "used": false }, "model": "name.roomresourcename", "pk": "flipcharts" @@ -13230,7 +13300,7 @@ "desc": "Experimental Room Setup (U-Shape and classroom, subject to availability)", "name": "Experimental Room Setup (U-Shape and classroom)", "order": 0, - "used": true + "used": false }, "model": "name.roomresourcename", "pk": "u-shape" @@ -16385,7 +16455,7 @@ "fields": { "command": "xym", "switch": "--version", - "time": "2023-05-14T07:09:32.713Z", + "time": "2023-07-17T07:09:47.664Z", "used": true, "version": "xym 0.7.0" }, @@ -16396,7 +16466,7 @@ "fields": { "command": "pyang", "switch": "--version", - "time": "2023-05-14T07:09:33.045Z", + "time": "2023-07-17T07:09:48.075Z", "used": true, "version": "pyang 2.5.3" }, @@ -16407,7 +16477,7 @@ "fields": { "command": "yanglint", "switch": "--version", - "time": "2023-05-14T07:09:33.065Z", + "time": "2023-07-17T07:09:48.104Z", "used": true, "version": "yanglint SO 1.9.2" }, @@ -16418,9 +16488,9 @@ "fields": { "command": "xml2rfc", "switch": "--version", - "time": "2023-05-14T07:09:33.970Z", + "time": "2023-07-17T07:09:49.075Z", "used": true, - "version": "xml2rfc 3.17.1" + "version": "xml2rfc 3.17.4" }, "model": "utils.versioninfo", "pk": 4 diff --git a/ietf/name/migrations/0004_statements.py b/ietf/name/migrations/0004_statements.py new file mode 100644 index 0000000000..ea37799746 --- /dev/null +++ b/ietf/name/migrations/0004_statements.py @@ -0,0 +1,21 @@ +# Copyright The IETF Trust 2023, All Rights Reserved + +from django.db import migrations + +def forward(apps, schema_editor): + DocTypeName = apps.get_model("name", "DocTypeName") + DocTypeName.objects.create(slug="statement", name="Statement", prefix="statement", desc="", used=True) + + +def reverse(apps, schema_editor): + DocTypeName = apps.get_model("name", "DocTypeName") + DocTypeName.objects.filter(slug="statement").delete() + +class Migration(migrations.Migration): + dependencies = [ + ("name", "0003_populate_telechatagendasectionname"), + ] + + operations = [ + migrations.RunPython(forward, reverse), + ] diff --git a/ietf/name/migrations/0005_feedbacktypename_schema.py b/ietf/name/migrations/0005_feedbacktypename_schema.py new file mode 100644 index 0000000000..cedb129be3 --- /dev/null +++ b/ietf/name/migrations/0005_feedbacktypename_schema.py @@ -0,0 +1,20 @@ +# Copyright The IETF Trust 2023, All Rights Reserved + +from django.db import migrations, models + +class Migration(migrations.Migration): + dependencies = [ + ("name", "0004_statements"), + ] + + operations = [ + migrations.AddField( + model_name="FeedbackTypeName", + name="legend", + field=models.CharField( + default="", + help_text="One-character legend for feedback classification form", + max_length=1, + ), + ), + ] diff --git a/ietf/name/migrations/0006_feedbacktypename_data.py b/ietf/name/migrations/0006_feedbacktypename_data.py new file mode 100644 index 0000000000..f11fca889b --- /dev/null +++ b/ietf/name/migrations/0006_feedbacktypename_data.py @@ -0,0 +1,36 @@ +# Copyright The IETF Trust 2023, All Rights Reserved + +from django.db import migrations + +def forward(apps, schema_editor): + FeedbackTypeName = apps.get_model("name", "FeedbackTypeName") + FeedbackTypeName.objects.create(slug="obe", name="Overcome by events") + for slug, legend, order in ( + ('comment', 'C', 1), + ('nomina', 'N', 2), + ('questio', 'Q', 3), + ('obe', 'O', 4), + ('junk', 'J', 5), + ('read', 'R', 6), + ): + ft = FeedbackTypeName.objects.get(slug=slug) + ft.legend = legend + ft.order = order + ft.save() + +def reverse(apps, schema_editor): + FeedbackTypeName = apps.get_model("name", "FeedbackTypeName") + FeedbackTypeName.objects.filter(slug="obe").delete() + for ft in FeedbackTypeName.objects.all(): + ft.legend = "" + ft.order = 0 + ft.save() + +class Migration(migrations.Migration): + dependencies = [ + ("name", "0005_feedbacktypename_schema"), + ] + + operations = [ + migrations.RunPython(forward, reverse), + ] diff --git a/ietf/name/models.py b/ietf/name/models.py index b9e75e8f99..4eda88afda 100644 --- a/ietf/name/models.py +++ b/ietf/name/models.py @@ -94,6 +94,7 @@ class NomineePositionStateName(NameModel): """Status of a candidate for a position: None, Accepted, Declined""" class FeedbackTypeName(NameModel): """Type of feedback: questionnaires, nominations, comments""" + legend = models.CharField(max_length=1, default="", help_text="One-character legend for feedback classification form") class DBTemplateTypeName(NameModel): """reStructuredText, Plain, Django""" class DraftSubmissionStateName(NameModel): diff --git a/ietf/nomcom/forms.py b/ietf/nomcom/forms.py index ad7bc67c23..919ed6e187 100644 --- a/ietf/nomcom/forms.py +++ b/ietf/nomcom/forms.py @@ -653,7 +653,7 @@ def clean_key(self): class PendingFeedbackForm(forms.ModelForm): - type = forms.ModelChoiceField(queryset=FeedbackTypeName.objects.all().order_by('pk'), widget=forms.RadioSelect, empty_label='Unclassified', required=False) + type = forms.ModelChoiceField(queryset=FeedbackTypeName.objects.all(), widget=forms.RadioSelect, empty_label='Unclassified', required=False) class Meta: model = Feedback diff --git a/ietf/nomcom/management/commands/create_test_nomcom.py b/ietf/nomcom/management/commands/create_test_nomcom.py index bfca892b88..3365ea8f40 100644 --- a/ietf/nomcom/management/commands/create_test_nomcom.py +++ b/ietf/nomcom/management/commands/create_test_nomcom.py @@ -11,7 +11,7 @@ from ietf.nomcom.factories import nomcom_kwargs_for_year, NomComFactory, NomineePositionFactory, key from ietf.person.factories import EmailFactory from ietf.group.models import Group -from ietf.person.models import User +from ietf.person.models import Person, User class Command(BaseCommand): help = ("Create (or delete) a nomcom for test and development purposes.") @@ -27,7 +27,9 @@ def handle(self, *args, **options): if opt_delete: if Group.objects.filter(acronym='nomcom7437').exists(): Group.objects.filter(acronym='nomcom7437').delete() - User.objects.filter(username__in=['testchair','testmember','testcandidate']).delete() + users_to_delete = ['testchair','testmember','testcandidate'] + Person.objects.filter(user__username__in=users_to_delete).delete() + User.objects.filter(username__in=users_to_delete).delete() self.stdout.write("Deleted test group 'nomcom7437' and its related objects.") else: self.stderr.write("test nomcom 'nomcom7437' does not exist; nothing to do.\n") @@ -57,6 +59,6 @@ def handle(self, *args, **options): position__nomcom=nc, position__name='Test Area Director', position__is_iesg_position=True, ) - self.stdout.write("%s\n" % key) + self.stdout.write("%s\n" % key.decode()) self.stdout.write("Nomcom 7437 created. The private key can also be found at any time\nin ietf/nomcom/factories.py. Note that it is NOT a secure key.\n") diff --git a/ietf/nomcom/tests.py b/ietf/nomcom/tests.py index 322dac6b69..3dee493873 100644 --- a/ietf/nomcom/tests.py +++ b/ietf/nomcom/tests.py @@ -1450,7 +1450,7 @@ def test_feedback_index_totals(self): self.assertEqual(response.status_code,200) q = PyQuery(response.content) r = q('tfoot').eq(0).find('td').contents() - self.assertEqual([a.strip() for a in r], ['1', '1', '1']) + self.assertEqual([a.strip() for a in r], ['1', '1', '1', '0']) class FeedbackLastSeenTests(TestCase): @@ -2863,3 +2863,92 @@ def test_decorate_volunteers_with_qualifications(self): self.assertEqual(v.qualifications,'path_2') if v.person == author_person: self.assertEqual(v.qualifications,'path_3') + +class ReclassifyFeedbackTests(TestCase): + """Tests for feedback reclassification""" + + def setUp(self): + super().setUp() + setup_test_public_keys_dir(self) + nomcom_test_data() + self.nc = NomComFactory.create(**nomcom_kwargs_for_year()) + self.chair = self.nc.group.role_set.filter(name='chair').first().person + self.member = self.nc.group.role_set.filter(name='member').first().person + self.nominee = self.nc.nominee_set.order_by('pk').first() + self.position = self.nc.position_set.first() + self.topic = self.nc.topic_set.first() + + def tearDown(self): + teardown_test_public_keys_dir(self) + super().tearDown() + + def test_reclassify_feedback_nominee(self): + fb = FeedbackFactory.create(nomcom=self.nc,type_id='comment') + fb.positions.add(self.position) + fb.nominees.add(self.nominee) + fb.save() + self.assertEqual(Feedback.objects.comments().count(), 1) + + url = reverse('ietf.nomcom.views.view_feedback_nominee', kwargs={'year':self.nc.year(), 'nominee_id':self.nominee.id}) + login_testing_unauthorized(self,self.member.user.username,url) + provide_private_key_to_test_client(self) + response = self.client.post(url, {'feedback_id': fb.id, 'type': 'obe'}) + self.assertEqual(response.status_code, 403) + + self.client.logout() + self.client.login(username=self.chair.user.username, password=self.chair.user.username + "+password") + provide_private_key_to_test_client(self) + + response = self.client.post(url, {'feedback_id': fb.id, 'type': 'obe'}) + self.assertEqual(response.status_code, 200) + + fb = Feedback.objects.get(id=fb.id) + self.assertEqual(fb.type_id,'obe') + self.assertEqual(Feedback.objects.comments().count(), 0) + self.assertEqual(Feedback.objects.filter(type='obe').count(), 1) + + def test_reclassify_feedback_topic(self): + fb = FeedbackFactory.create(nomcom=self.nc,type_id='comment') + fb.topics.add(self.topic) + fb.save() + self.assertEqual(Feedback.objects.comments().count(), 1) + + url = reverse('ietf.nomcom.views.view_feedback_topic', kwargs={'year':self.nc.year(), 'topic_id':self.topic.id}) + login_testing_unauthorized(self,self.member.user.username,url) + provide_private_key_to_test_client(self) + response = self.client.post(url, {'feedback_id': fb.id, 'type': 'unclassified'}) + self.assertEqual(response.status_code, 403) + + self.client.logout() + self.client.login(username=self.chair.user.username, password=self.chair.user.username + "+password") + provide_private_key_to_test_client(self) + + response = self.client.post(url, {'feedback_id': fb.id, 'type': 'unclassified'}) + self.assertEqual(response.status_code, 200) + + fb = Feedback.objects.get(id=fb.id) + self.assertEqual(fb.type_id,None) + self.assertEqual(Feedback.objects.comments().count(), 0) + self.assertEqual(Feedback.objects.filter(type=None).count(), 1) + + def test_reclassify_feedback_unrelated(self): + fb = FeedbackFactory(nomcom=self.nc, type_id='read') + self.assertEqual(Feedback.objects.filter(type='read').count(), 1) + + url = reverse('ietf.nomcom.views.view_feedback_unrelated', kwargs={'year':self.nc.year()}) + login_testing_unauthorized(self,self.member.user.username,url) + provide_private_key_to_test_client(self) + response = self.client.post(url, {'feedback_id': fb.id, 'type': 'junk'}) + self.assertEqual(response.status_code, 403) + + self.client.logout() + self.client.login(username=self.chair.user.username, password=self.chair.user.username + "+password") + provide_private_key_to_test_client(self) + + response = self.client.post(url, {'feedback_id': fb.id, 'type': 'junk'}) + self.assertEqual(response.status_code, 200) + + fb = Feedback.objects.get(id=fb.id) + self.assertEqual(fb.type_id, 'junk') + self.assertEqual(Feedback.objects.filter(type='read').count(), 0) + self.assertEqual(Feedback.objects.filter(type='junk').count(), 1) diff --git a/ietf/nomcom/views.py b/ietf/nomcom/views.py index 1b18ae6379..b36f664500 100644 --- a/ietf/nomcom/views.py +++ b/ietf/nomcom/views.py @@ -1,10 +1,10 @@ -# Copyright The IETF Trust 2012-2020, All Rights Reserved +# Copyright The IETF Trust 2012-2023, All Rights Reserved # -*- coding: utf-8 -*- import datetime import re -from collections import OrderedDict, Counter +from collections import Counter import csv import hmac @@ -14,7 +14,7 @@ from django.contrib.auth.models import AnonymousUser from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from django.forms.models import modelformset_factory, inlineformset_factory -from django.http import Http404, HttpResponseRedirect, HttpResponse +from django.http import Http404, HttpResponseRedirect, HttpResponse, HttpResponseForbidden from django.shortcuts import render, get_object_or_404, redirect from django.template.loader import render_to_string from django.urls import reverse @@ -236,7 +236,7 @@ def private_index(request, year): 'position__id':p.pk, 'position': p, } for p in positions] - states = list(NomineePositionStateName.objects.values('slug', 'name')) + [{'slug': questionnaire_state, 'name': 'Questionnaire'}] + states = [{'slug': questionnaire_state, 'name': 'Accepted and sent Questionnaire'}] + list(NomineePositionStateName.objects.values('slug', 'name')) positions = set([ n.position for n in all_nominee_positions.order_by('position__name') ]) for s in stats: for state in states: @@ -767,7 +767,6 @@ def process_nomination_status(request, year, nominee_position_id, state, date, h 'selected': 'feedback', 'form': form }) - @role_required("Nomcom") @nomcom_private_key_required def view_feedback(request, year): @@ -775,7 +774,7 @@ def view_feedback(request, year): nominees = Nominee.objects.get_by_nomcom(nomcom).not_duplicated().distinct() independent_feedback_types = [] nominee_feedback_types = [] - for ft in FeedbackTypeName.objects.all(): + for ft in FeedbackTypeName.objects.filter(used=True): if ft.slug in settings.NOMINEE_FEEDBACK_TYPES: nominee_feedback_types.append(ft) else: @@ -838,7 +837,8 @@ def nominee_staterank(nominee): 'topics_feedback': topics_feedback, 'independent_feedback': independent_feedback, 'nominees_feedback': nominees_feedback, - 'nomcom': nomcom}) + 'nomcom': nomcom, + }) @role_required("Nomcom Chair", "Nomcom Advisor") @@ -924,23 +924,13 @@ def view_feedback_pending(request, year): formset = FeedbackFormSet(queryset=feedback_page.object_list) for form in formset.forms: form.set_nomcom(nomcom, request.user) - type_dict = OrderedDict() - for t in FeedbackTypeName.objects.all().order_by('pk'): - rest = t.name - slug = rest[0] - rest = rest[1:] - while slug in type_dict and rest: - slug = rest[0] - rest = rest[1] - type_dict[slug] = t return render(request, 'nomcom/view_feedback_pending.html', {'year': year, 'selected': 'feedback_pending', 'formset': formset, 'extra_step': extra_step, - 'type_dict': type_dict, 'extra_ids': extra_ids, - 'types': FeedbackTypeName.objects.all().order_by('pk'), + 'types': FeedbackTypeName.objects.filter(used=True), 'nomcom': nomcom, 'is_chair_task' : True, 'page': feedback_page, @@ -951,22 +941,59 @@ def view_feedback_pending(request, year): @nomcom_private_key_required def view_feedback_unrelated(request, year): nomcom = get_nomcom_by_year(year) + + if request.method == 'POST': + if not nomcom.group.has_role(request.user, ['chair','advisor']): + return HttpResponseForbidden('Restricted to roles: Nomcom Chair, Nomcom Advisor') + feedback_id = request.POST.get('feedback_id', None) + feedback = get_object_or_404(Feedback, id=feedback_id) + type = request.POST.get('type', None) + if type: + if type == 'unclassified': + feedback.type = None + messages.success(request, 'The selected feedback has been de-classified. Please reclassify it in the Pending emails tab.') + else: + feedback.type = FeedbackTypeName.objects.get(slug=type) + messages.success(request, f'The selected feedback has been reclassified as {feedback.type.name}.') + feedback.save() + else: + return render(request, 'nomcom/view_feedback_unrelated.html', + {'year': year, + 'nomcom': nomcom, + 'feedback_types': FeedbackTypeName.objects.filter(used=True).exclude(slug__in=settings.NOMINEE_FEEDBACK_TYPES), + 'reclassify_feedback': feedback, + 'is_chair_task' : True, + }) + feedback_types = [] - for ft in FeedbackTypeName.objects.exclude(slug__in=settings.NOMINEE_FEEDBACK_TYPES): + for ft in FeedbackTypeName.objects.filter(used=True).exclude(slug__in=settings.NOMINEE_FEEDBACK_TYPES): feedback_types.append({'ft': ft, 'feedback': ft.feedback_set.get_by_nomcom(nomcom)}) - return render(request, 'nomcom/view_feedback_unrelated.html', {'year': year, - 'selected': 'view_feedback', 'feedback_types': feedback_types, - 'nomcom': nomcom}) + 'nomcom': nomcom, + }) @role_required("Nomcom") @nomcom_private_key_required def view_feedback_topic(request, year, topic_id): - nomcom = get_nomcom_by_year(year) + # At present, the only feedback type for topics is 'comment'. + # Reclassifying from 'comment' to 'comment' is a no-op, + # so the only meaningful action is to de-classify it. + if request.method == 'POST': + nomcom = get_nomcom_by_year(year) + if not nomcom.group.has_role(request.user, ['chair','advisor']): + return HttpResponseForbidden('Restricted to roles: Nomcom Chair, Nomcom Advisor') + feedback_id = request.POST.get('feedback_id', None) + feedback = get_object_or_404(Feedback, id=feedback_id) + feedback.type = None + feedback.topics.clear() + feedback.save() + messages.success(request, 'The selected feedback has been de-classified. Please reclassify it in the Pending emails tab.') + topic = get_object_or_404(Topic, id=topic_id) + nomcom = get_nomcom_by_year(year) feedback_types = FeedbackTypeName.objects.filter(slug__in=['comment',]) last_seen = TopicFeedbackLastSeen.objects.filter(reviewer=request.user.person,topic=topic).first() @@ -978,18 +1005,42 @@ def view_feedback_topic(request, year, topic_id): return render(request, 'nomcom/view_feedback_topic.html', {'year': year, - 'selected': 'view_feedback', 'topic': topic, 'feedback_types': feedback_types, 'last_seen_time' : last_seen_time, - 'nomcom': nomcom}) + 'nomcom': nomcom, + }) @role_required("Nomcom") @nomcom_private_key_required def view_feedback_nominee(request, year, nominee_id): nomcom = get_nomcom_by_year(year) nominee = get_object_or_404(Nominee, id=nominee_id) - feedback_types = FeedbackTypeName.objects.filter(slug__in=settings.NOMINEE_FEEDBACK_TYPES) + feedback_types = FeedbackTypeName.objects.filter(used=True, slug__in=settings.NOMINEE_FEEDBACK_TYPES) + + if request.method == 'POST': + if not nomcom.group.has_role(request.user, ['chair','advisor']): + return HttpResponseForbidden('Restricted to roles: Nomcom Chair, Nomcom Advisor') + feedback_id = request.POST.get('feedback_id', None) + feedback = get_object_or_404(Feedback, id=feedback_id) + type = request.POST.get('type', None) + if type: + if type == 'unclassified': + feedback.type = None + feedback.nominees.clear() + messages.success(request, 'The selected feedback has been de-classified. Please reclassify it in the Pending emails tab.') + else: + feedback.type = FeedbackTypeName.objects.get(slug=type) + messages.success(request, f'The selected feedback has been reclassified as {feedback.type.name}.') + feedback.save() + else: + return render(request, 'nomcom/view_feedback_nominee.html', + {'year': year, + 'nomcom': nomcom, + 'feedback_types': feedback_types, + 'reclassify_feedback': feedback, + 'is_chair_task': True, + }) last_seen = FeedbackLastSeen.objects.filter(reviewer=request.user.person,nominee=nominee).first() last_seen_time = (last_seen and last_seen.time) or datetime.datetime(year=1, month=1, day=1, tzinfo=datetime.timezone.utc) @@ -1000,11 +1051,11 @@ def view_feedback_nominee(request, year, nominee_id): return render(request, 'nomcom/view_feedback_nominee.html', {'year': year, - 'selected': 'view_feedback', 'nominee': nominee, 'feedback_types': feedback_types, 'last_seen_time' : last_seen_time, - 'nomcom': nomcom}) + 'nomcom': nomcom, + }) @role_required("Nomcom Chair", "Nomcom Advisor") diff --git a/ietf/person/models.py b/ietf/person/models.py index a09656b810..22c63d4a0f 100644 --- a/ietf/person/models.py +++ b/ietf/person/models.py @@ -145,6 +145,14 @@ def email(self): e = self.email_set.filter(active=True).order_by("-time").first() self._cached_email = e return self._cached_email + def email_allowing_inactive(self): + if not hasattr(self, "_cached_email_allowing_inactive"): + e = self.email() + if not e: + e = self.email_set.order_by("-time").first() + log.assertion(statement="e is not None", note=f"Person {self.pk} has no Email objects") + self._cached_email_allowing_inactive = e + return self._cached_email_allowing_inactive def email_address(self): e = self.email() if e: diff --git a/ietf/person/tests.py b/ietf/person/tests.py index 11e1a5b663..bb75b438db 100644 --- a/ietf/person/tests.py +++ b/ietf/person/tests.py @@ -112,6 +112,14 @@ def test_person_profile_without_email(self): r = self.client.get(url) self.assertContains(r, person.name, status_code=200) + def test_case_insensitive(self): + # Case insensitive seach + person = PersonFactory(name="Test Person") + url = urlreverse("ietf.person.views.profile", kwargs={ "email_or_name": "test person"}) + r = self.client.get(url) + self.assertContains(r, person.name, status_code=200) + self.assertNotIn('More than one person', r.content.decode()) + def test_person_profile_duplicates(self): # same Person name and email - should not show on the profile as multiple Person records person = PersonFactory(name="bazquux@example.com", user__email="bazquux@example.com") diff --git a/ietf/person/views.py b/ietf/person/views.py index 4e3f7d8c30..23a8dea3d2 100644 --- a/ietf/person/views.py +++ b/ietf/person/views.py @@ -69,11 +69,11 @@ def ajax_select2_search(request, model_name): def profile(request, email_or_name): - aliases = Alias.objects.filter(name=email_or_name) + aliases = Alias.objects.filter(name__iexact=email_or_name) persons = set(a.person for a in aliases) if '@' in email_or_name: - emails = Email.objects.filter(address=email_or_name) + emails = Email.objects.filter(address__iexact=email_or_name) persons.update(e.person for e in emails) persons = [p for p in persons if p and p.id] diff --git a/ietf/review/policies.py b/ietf/review/policies.py index fe6519a5ef..ac3cca2835 100644 --- a/ietf/review/policies.py +++ b/ietf/review/policies.py @@ -84,7 +84,7 @@ def default_reviewer_rotation_list(self, include_unavailable=False): rotation_list = self._filter_unavailable_reviewers(rotation_list) return rotation_list - def return_reviewer_to_rotation_top(self, reviewer_person, wants_to_be_next): + def set_wants_to_be_next(self, reviewer_person): """ Return a reviewer to the top of the rotation, e.g. because they rejected a review, and should retroactively not have been rotated over. @@ -475,14 +475,13 @@ def default_reviewer_rotation_list(self, include_unavailable=False): return reviewers[next_reviewer_index:] + reviewers[:next_reviewer_index] - def return_reviewer_to_rotation_top(self, reviewer_person, wants_to_be_next): + def set_wants_to_be_next(self, reviewer_person): # As RotateAlphabetically does not keep a full rotation list, # returning someone to a particular order is complex. # Instead, the "assign me next" flag is set. - if wants_to_be_next: - settings = self._reviewer_settings_for(reviewer_person) - settings.request_assignment_next = wants_to_be_next - settings.save() + settings = self._reviewer_settings_for(reviewer_person) + settings.request_assignment_next = True + settings.save() def _update_skip_next(self, rotation_pks, assignee_person): """Decrement skip_next for all users skipped @@ -570,14 +569,13 @@ def default_reviewer_rotation_list(self, include_unavailable=False): rotation_list += reviewers_with_assignment return rotation_list - def return_reviewer_to_rotation_top(self, reviewer_person, wants_to_be_next): + def set_wants_to_be_next(self, reviewer_person): # Reviewer rotation for this policy ignores rejected/withdrawn # reviews, so it automatically adjusts the position of someone # who rejected a review and no further action is needed. - if wants_to_be_next: - settings = self._reviewer_settings_for(reviewer_person) - settings.request_assignment_next = wants_to_be_next - settings.save() + settings = self._reviewer_settings_for(reviewer_person) + settings.request_assignment_next = True + settings.save() QUEUE_POLICY_NAME_MAPPING = { diff --git a/ietf/review/tests_policies.py b/ietf/review/tests_policies.py index d1d26997b4..ca687ff862 100644 --- a/ietf/review/tests_policies.py +++ b/ietf/review/tests_policies.py @@ -115,7 +115,7 @@ def reviewer_settings_for(self, person): return (ReviewerSettings.objects.filter(team=self.team, person=person).first() or ReviewerSettings(team=self.team, person=person)) - def test_return_reviewer_to_rotation_top(self): + def test_set_wants_to_be_next(self): # Subclass must implement this raise NotImplementedError @@ -507,11 +507,9 @@ def test_default_reviewer_rotation_list_with_nextreviewerinteam(self): rotation = self.policy.default_reviewer_rotation_list() self.assertEqual(rotation, available_reviewers[2:] + available_reviewers[:1]) - def test_return_reviewer_to_rotation_top(self): + def test_set_wants_to_be_next(self): reviewer = self.append_reviewer() - self.policy.return_reviewer_to_rotation_top(reviewer, False) - self.assertFalse(self.reviewer_settings_for(reviewer).request_assignment_next) - self.policy.return_reviewer_to_rotation_top(reviewer, True) + self.policy.set_wants_to_be_next(reviewer) self.assertTrue(self.reviewer_settings_for(reviewer).request_assignment_next) def test_update_policy_state_for_assignment(self): @@ -725,11 +723,9 @@ def test_default_review_rotation_list_uses_assigned_on_date(self): self.assertEqual(self.policy.default_reviewer_rotation_list(), available_reviewers[2:] + [first_reviewer, second_reviewer]) - def test_return_reviewer_to_rotation_top(self): + def test_set_wants_to_be_next(self): reviewer = self.append_reviewer() - self.policy.return_reviewer_to_rotation_top(reviewer, False) - self.assertFalse(self.reviewer_settings_for(reviewer).request_assignment_next) - self.policy.return_reviewer_to_rotation_top(reviewer, True) + self.policy.set_wants_to_be_next(reviewer) self.assertTrue(self.reviewer_settings_for(reviewer).request_assignment_next) def test_assign_reviewer_updates_skip_next_without_add_skip(self): diff --git a/ietf/review/utils.py b/ietf/review/utils.py index 31b6b401fe..058e8cee93 100644 --- a/ietf/review/utils.py +++ b/ietf/review/utils.py @@ -79,6 +79,11 @@ def review_assignments_to_list_for_docs(docs): return extract_revision_ordered_review_assignments_for_documents_and_replaced(assignment_qs, doc_names) +def review_requests_to_list_for_docs(docs): + review_requests_qs = ReviewRequest.objects.filter(Q(state_id='requested')) + doc_names = [d.name for d in docs] + return extract_revision_ordered_review_requests_for_documents_and_replaced(review_requests_qs, doc_names) + def augment_review_requests_with_events(review_reqs): req_dict = { r.pk: r for r in review_reqs } for e in ReviewRequestDocEvent.objects.filter(review_request__in=review_reqs, type__in=["assigned_review_request", "closed_review_request"]).order_by("time"): @@ -589,10 +594,12 @@ def blocks(existing, request): and existing.reviewassignment_set.filter(state_id__in=("assigned", "accepted")).exists() and (not existing.requested_rev or existing.requested_rev == request.doc.rev)) request_closed = existing.state_id not in ('requested','assigned') + # Is there a review request for this document already in system + requested = existing.state_id in ('requested') and (not existing.requested_rev or existing.requested_rev == request.doc.rev) # at least one assignment was completed for the requested version or the current doc version if no specific version was requested: some_assignment_completed = existing.reviewassignment_set.filter(reviewed_rev=existing.requested_rev or existing.doc.rev, state_id='completed').exists() - return any([no_review_document, no_review_rev, pending, request_closed, some_assignment_completed]) + return any([no_review_document, no_review_rev, pending, request_closed, requested, some_assignment_completed]) res = [r for r in requests.values() if not any(blocks(e, r) for e in existing_requests[r.doc_id])] diff --git a/ietf/settings.py b/ietf/settings.py index abb7cde1d5..b92129ccec 100644 --- a/ietf/settings.py +++ b/ietf/settings.py @@ -1,4 +1,4 @@ -# Copyright The IETF Trust 2007-2022, All Rights Reserved +# Copyright The IETF Trust 2007-2023, All Rights Reserved # -*- coding: utf-8 -*- @@ -10,6 +10,7 @@ import sys import datetime import warnings +from hashlib import sha384 from typing import Any, Dict, List, Tuple # pyflakes:ignore warnings.simplefilter("always", DeprecationWarning) @@ -657,6 +658,7 @@ def skip_unreadable_post(record): "acronym": r"(?P[-a-z0-9]+)", "bofreq": r"(?Pbofreq-[-a-z0-9]+)", "charter": r"(?Pcharter-[-a-z0-9]+)", + "statement": r"(?Pstatement-[-a-z0-9]+)", "date": r"(?P\d{4}-\d{2}-\d{2})", "name": r"(?P[A-Za-z0-9._+-]+?)", "document": r"(?P[a-z][-a-z0-9]+)", # regular document names @@ -668,7 +670,6 @@ def skip_unreadable_post(record): # Override this in settings_local.py if needed # *_PATH variables ends with a slash/ . -#DOCUMENT_PATH_PATTERN = '/a/www/ietf-ftp/{doc.type_id}/' DOCUMENT_PATH_PATTERN = '/a/ietfdata/doc/{doc.type_id}/' INTERNET_DRAFT_PATH = '/a/ietfdata/doc/draft/repository' INTERNET_DRAFT_PDF_PATH = '/a/www/ietf-datatracker/pdf/' @@ -725,44 +726,6 @@ def skip_unreadable_post(record): CACHE_MIDDLEWARE_SECONDS = 300 CACHE_MIDDLEWARE_KEY_PREFIX = '' -# The default with no CACHES setting is 'django.core.cache.backends.locmem.LocMemCache' -# This setting is possibly overridden further down, after the import of settings_local -CACHES = { - 'default': { - 'BACKEND': 'ietf.utils.cache.LenientMemcacheCache', - 'LOCATION': '127.0.0.1:11211', - 'VERSION': __version__, - 'KEY_PREFIX': 'ietf:dt', - }, - 'sessions': { - 'BACKEND': 'ietf.utils.cache.LenientMemcacheCache', - 'LOCATION': '127.0.0.1:11211', - # No release-specific VERSION setting. - 'KEY_PREFIX': 'ietf:dt', - }, - 'htmlized': { - 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', - 'LOCATION': '/a/cache/datatracker/htmlized', - 'OPTIONS': { - 'MAX_ENTRIES': 100000, # 100,000 - }, - }, - 'pdfized': { - 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', - 'LOCATION': '/a/cache/datatracker/pdfized', - 'OPTIONS': { - 'MAX_ENTRIES': 100000, # 100,000 - }, - }, - 'slowpages': { - 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', - 'LOCATION': '/a/cache/datatracker/slowpages', - 'OPTIONS': { - 'MAX_ENTRIES': 5000, - }, - }, -} - HTMLIZER_VERSION = 1 HTMLIZER_URL_PREFIX = "/doc/html" HTMLIZER_CACHE_TIME = 60*60*24*14 # 14 days @@ -802,7 +765,7 @@ def skip_unreadable_post(record): NOMCOM_FROM_EMAIL = 'nomcom-chair-{year}@ietf.org' OPENSSL_COMMAND = '/usr/bin/openssl' DAYS_TO_EXPIRE_NOMINATION_LINK = '' -NOMINEE_FEEDBACK_TYPES = ['comment', 'questio', 'nomina'] +NOMINEE_FEEDBACK_TYPES = ['comment', 'questio', 'nomina', 'obe'] # SlideSubmission settings SLIDE_STAGING_PATH = '/a/www/www6s/staging/' @@ -1228,6 +1191,84 @@ def skip_unreadable_post(record): MIDDLEWARE += DEV_MIDDLEWARE TEMPLATES[0]['OPTIONS']['context_processors'] += DEV_TEMPLATE_CONTEXT_PROCESSORS +if 'CACHES' not in locals(): + if SERVER_MODE == 'production': + CACHES = { + 'default': { + 'BACKEND': 'ietf.utils.cache.LenientMemcacheCache', + 'LOCATION': '127.0.0.1:11211', + 'VERSION': __version__, + 'KEY_PREFIX': 'ietf:dt', + 'KEY_FUNCTION': lambda key, key_prefix, version: ( + f"{key_prefix}:{version}:{sha384(str(key).encode('utf8')).hexdigest()}" + ), + }, + 'sessions': { + 'BACKEND': 'ietf.utils.cache.LenientMemcacheCache', + 'LOCATION': '127.0.0.1:11211', + # No release-specific VERSION setting. + 'KEY_PREFIX': 'ietf:dt', + }, + 'htmlized': { + 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', + 'LOCATION': '/a/cache/datatracker/htmlized', + 'OPTIONS': { + 'MAX_ENTRIES': 100000, # 100,000 + }, + }, + 'pdfized': { + 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', + 'LOCATION': '/a/cache/datatracker/pdfized', + 'OPTIONS': { + 'MAX_ENTRIES': 100000, # 100,000 + }, + }, + 'slowpages': { + 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', + 'LOCATION': '/a/cache/datatracker/slowpages', + 'OPTIONS': { + 'MAX_ENTRIES': 5000, + }, + }, + } + else: + CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', + #'BACKEND': 'ietf.utils.cache.LenientMemcacheCache', + #'LOCATION': '127.0.0.1:11211', + #'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', + 'VERSION': __version__, + 'KEY_PREFIX': 'ietf:dt', + }, + 'sessions': { + 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', + }, + 'htmlized': { + 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', + #'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', + 'LOCATION': '/var/cache/datatracker/htmlized', + 'OPTIONS': { + 'MAX_ENTRIES': 1000, + }, + }, + 'pdfized': { + 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', + #'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', + 'LOCATION': '/var/cache/datatracker/pdfized', + 'OPTIONS': { + 'MAX_ENTRIES': 1000, + }, + }, + 'slowpages': { + 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', + #'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', + 'LOCATION': '/var/cache/datatracker/', + 'OPTIONS': { + 'MAX_ENTRIES': 5000, + }, + }, + } # We provide a secret key only for test and development modes. It's # absolutely vital that django fails to start in production mode unless a @@ -1238,44 +1279,6 @@ def skip_unreadable_post(record): loaders = TEMPLATES[0]['OPTIONS']['loaders'] loaders = tuple(l for e in loaders for l in (e[1] if isinstance(e, tuple) and "cached.Loader" in e[0] else (e,))) TEMPLATES[0]['OPTIONS']['loaders'] = loaders - - CACHES = { - 'default': { - 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', - #'BACKEND': 'ietf.utils.cache.LenientMemcacheCache', - #'LOCATION': '127.0.0.1:11211', - #'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', - 'VERSION': __version__, - 'KEY_PREFIX': 'ietf:dt', - }, - 'sessions': { - 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', - }, - 'htmlized': { - 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', - #'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', - 'LOCATION': '/var/cache/datatracker/htmlized', - 'OPTIONS': { - 'MAX_ENTRIES': 1000, - }, - }, - 'pdfized': { - 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', - #'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', - 'LOCATION': '/var/cache/datatracker/pdfized', - 'OPTIONS': { - 'MAX_ENTRIES': 1000, - }, - }, - 'slowpages': { - 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', - #'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', - 'LOCATION': '/var/cache/datatracker/', - 'OPTIONS': { - 'MAX_ENTRIES': 5000, - }, - }, - } SESSION_ENGINE = "django.contrib.sessions.backends.db" if 'SECRET_KEY' not in locals(): diff --git a/ietf/static/css/document_html_txt.scss b/ietf/static/css/document_html_txt.scss index 126de8d4ea..a75c491d26 100644 --- a/ietf/static/css/document_html_txt.scss +++ b/ietf/static/css/document_html_txt.scss @@ -424,8 +424,8 @@ sup, sub { /* Authors */ address, address.vcard { font-style: normal; - // margin: 2em 0 var(--line) 3ch; - margin-top: 2em; + // margin: var(--line) 0 var(--line) 3ch + margin-top: var(--line); margin-right: 0; margin-bottom: var(--line); margin-left: 3ch; diff --git a/ietf/static/css/ietf.scss b/ietf/static/css/ietf.scss index 5051f01f11..0970f45891 100644 --- a/ietf/static/css/ietf.scss +++ b/ietf/static/css/ietf.scss @@ -88,6 +88,34 @@ html { scroll-padding-top: 60px; } +// Make submenus open on hover. +@include media-breakpoint-up(lg) { + .dropdown-menu>li>ul { + display: none; + } + + .dropdown-menu>li:hover>ul { + display: block; + } + +} + +@include media-breakpoint-up(md) { + .leftmenu .nav>li>ul { + display: none; + } + + .leftmenu .nav>li:hover>ul { + display: block; + } +} + +:is(.dropdown-menu, .leftmenu .nav) .dropdown-menu { + top: 0; + left: 100%; + right: auto; +} + // Make textareas in forms use a monospace font textarea.form-control { font-family: $font-family-code; diff --git a/ietf/static/js/ietf.js b/ietf/static/js/ietf.js index d66213bcf5..7f7e924153 100644 --- a/ietf/static/js/ietf.js +++ b/ietf/static/js/ietf.js @@ -93,18 +93,6 @@ $(document) $(document) .ready(function () { - - function dropdown_hover(e) { - var navbar = $(this) - .closest(".navbar"); - if (navbar.length === 0 || navbar.find(".navbar-toggler") - .is(":hidden")) { - $(this) - .children(".dropdown-toggle") - .dropdown(e.type == "mouseenter" ? "show" : "hide"); - } - } - // load data for the menu $.ajax({ url: $(document.body) @@ -140,9 +128,6 @@ $(document) } attachTo.append(menu.join("")); } - - $("ul.nav li.dropdown, ul.nav li.dropend") - .on("mouseenter mouseleave", dropdown_hover); } }); }); diff --git a/ietf/static/js/upload_statement.js b/ietf/static/js/upload_statement.js new file mode 100644 index 0000000000..7e8a4e8643 --- /dev/null +++ b/ietf/static/js/upload_statement.js @@ -0,0 +1,29 @@ +$(document) + .ready(function () { + var form = $("form.upload-content"); + // review submission selection + form.find("[name=statement_submission]") + .on("click change", function () { + var val = form.find("[name=statement_submission]:checked") + .val(); + + var shouldBeVisible = { + enter: ['[name="statement_content"]'], + upload: ['[name="statement_file"]'], + }; + + for (var v in shouldBeVisible) { + for (var i in shouldBeVisible[v]) { + var selector = shouldBeVisible[v][i]; + var row = form.find(selector); + if (!row.is(".row")) + row = row.closest(".row"); + if ($.inArray(selector, shouldBeVisible[val]) != -1) + row.show(); + else + row.hide(); + } + } + }) + .trigger("change"); + }); diff --git a/ietf/submit/tests.py b/ietf/submit/tests.py index 6eeaa47c56..81534aaadc 100644 --- a/ietf/submit/tests.py +++ b/ietf/submit/tests.py @@ -2878,7 +2878,7 @@ def test_submission_status(self): self.assertEqual(r.status_code, 200) self.assertEqual( r.json(), - {'id': str(s.pk), 'state': 'validating'}, + {'id': str(s.pk), 'state': 'validating', 'state_desc': s.state.name}, ) s.state_id = 'uploaded' @@ -2887,7 +2887,7 @@ def test_submission_status(self): self.assertEqual(r.status_code, 200) self.assertEqual( r.json(), - {'id': str(s.pk), 'state': 'uploaded'}, + {'id': str(s.pk), 'state': 'uploaded', 'state_desc': s.state.name}, ) # try an invalid one diff --git a/ietf/submit/views.py b/ietf/submit/views.py index b198d38f4b..798fbf307f 100644 --- a/ietf/submit/views.py +++ b/ietf/submit/views.py @@ -183,6 +183,7 @@ def api_submission_status(request, submission_id): { 'id': str(submission.pk), 'state': submission.state.slug, + 'state_desc': submission.state.name, } ) diff --git a/ietf/templates/base/menu.html b/ietf/templates/base/menu.html index d979808059..2f88aadca8 100644 --- a/ietf/templates/base/menu.html +++ b/ietf/templates/base/menu.html @@ -10,7 +10,6 @@ + {% if doc.stream_id == 'ietf' %} WG {% else %} @@ -274,12 +274,12 @@ IESG - + IESG state - {% if iesg_state.slug != 'idexists' and can_edit %} + {% if iesg_state.slug != 'idexists' and iesg_state.slug != 'dead' and can_edit %} Edit @@ -468,7 +468,7 @@ IANA - + IANA review state @@ -497,7 +497,7 @@ {% if not can_edit_iana_state and not iana_review_state %}IANA{% endif %} - + IANA action state @@ -526,7 +526,7 @@ {% if not can_edit_iana_state and not iana_review_state and not iana_action_state %}IANA{% endif %} - + IANA expert review state @@ -587,7 +587,7 @@ RFC Editor - + RFC Editor state diff --git a/ietf/templates/doc/document_info.html b/ietf/templates/doc/document_info.html index 860bc30788..b2265c254a 100644 --- a/ietf/templates/doc/document_info.html +++ b/ietf/templates/doc/document_info.html @@ -339,7 +339,10 @@ {% for review_assignment in review_assignments %} - {% include "doc/review_assignment_summary.html" with current_doc_name=doc.name current_rev=doc.rev %} + {% include "doc/review_assignment_summary.html" with current_doc_name=doc.name current_rev=doc.rev review_assignment=review_assignment only %} + {% endfor %} + {% for review_request in review_requests %} + {% include "doc/review_request_summary.html" with review_request=review_request only %} {% endfor %} {% if no_review_from_teams %} {% for team in no_review_from_teams %} diff --git a/ietf/templates/doc/document_statement.html b/ietf/templates/doc/document_statement.html new file mode 100644 index 0000000000..7e6d5b9478 --- /dev/null +++ b/ietf/templates/doc/document_statement.html @@ -0,0 +1,134 @@ +{% extends "base.html" %} +{# Copyright The IETF Trust 2023, All Rights Reserved #} +{% load origin %} +{% load static %} +{% load ietf_filters %} +{% load person_filters textfilters %} +{% block title %}{{ doc.title }}{% endblock %} +{% block content %} + {% origin %} + {{ top|safe }} + {% include "doc/revisions_list.html" %} +
+ {% if doc.rev != latest_rev %} +
The information below is for an older version of this statement.
+ {% endif %} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {% with doc.docextresource_set.all as resources %} + {% if resources or can_manage %} + + + + + + + {% endif %} + {% endwith %} + + + + + + + +
DocumentType + {% if doc.get_state.slug != "active" %}{{doc.get_state.name}} {% endif %}{% if doc.group %}{{doc.group.acronym|upper}} {%endif%}Statement + {% if snapshot %}Snapshot{% endif %} + {% if replaced_by %}
Replaced by {{ replaced_by|urlize_related_source_list:False|join:", " }}
{% endif %} + {% if replaces %}
Replaces {{ replaces|urlize_related_target_list:False|join:", " }}
{% endif %} +
Title{{ doc.title }}
Published{{ published|date:"Y-m-d" }}
Metadata last updated{{ doc.time|date:"Y-m-d" }}
+ State + + {% if doc.get_state %} + {{ doc.get_state.name }} + {% else %} + No document state + {% endif %} +
Additional resources + {% if can_manage %} + Edit + {% endif %} + + {% if resources %} + {% for resource in resources|dictsort:"display_name" %} + {% if resource.name.type.slug == 'url' or resource.name.type.slug == 'email' %} + + {% firstof resource.display_name resource.name.name %} + +
+ {# Maybe make how a resource displays itself a method on the class so templates aren't doing this switching #} + {% else %} + {% firstof resource.display_name resource.name.name %}: {{ resource.value|escape }} +
+ {% endif %} + {% endfor %} + {% endif %} +
+ Send notices to + + {% if not snapshot %} + {% if can_manage %} + {% doc_edit_button 'ietf.doc.views_doc.edit_notify' name=doc.name %} + {% endif %} + {% endif %} + + {{ doc.notify|default:'(None)' }} +
+ {% if not snapshot %} + {% if request.user|has_role:"Secretariat" %} +

+ + Edit or upload revised statement text + +

+ {% endif %} +{% endif %} + +
+
+ {{ doc.name }}-{{ doc.rev }} +
+
+ {{ content }} +
+
+{% endblock %} +{% block js %} + + +{% endblock %} \ No newline at end of file diff --git a/ietf/templates/doc/drafts_for_ad.html b/ietf/templates/doc/drafts_for_ad.html index e02fed18c0..28ebb2225b 100644 --- a/ietf/templates/doc/drafts_for_ad.html +++ b/ietf/templates/doc/drafts_for_ad.html @@ -52,8 +52,35 @@

Blocking positions held by {{ ad_name }}

{% endfor %} -

Documents for {{ ad_name }}

{% endif %} + {% if not_balloted_docs %} +

Missing ballot positions for {{ ad_name }}

+ + + + + + + + + + {% for doc in not_balloted_docs %} + + + {% include "doc/search/status_columns.html" %} + + + {% endfor %} + +
DocumentStatusResponsible AD
{{ doc.displayname_with_link }} + {% if doc.ad %} + {% person_link doc.ad %} + {% else %} + (None) + {% endif %} +
+ {% endif %} +

Documents for {{ ad_name }}

{% include "doc/search/search_results.html" with start_table=True end_table=True %} {% endblock %} {% block js %} diff --git a/ietf/templates/doc/review_assignment_summary.html b/ietf/templates/doc/review_assignment_summary.html index 3172530e1d..af748a4e91 100644 --- a/ietf/templates/doc/review_assignment_summary.html +++ b/ietf/templates/doc/review_assignment_summary.html @@ -19,10 +19,9 @@ {% else %} - {{ review_assignment.review_request.team.acronym|upper }} {{ review_assignment.review_request.type.name }} Review - - - Incomplete, due {{ review_assignment.review_request.deadline|date:"Y-m-d" }} + {{ review_assignment.review_request.team.acronym|upper }} {{ review_assignment.review_request.type.name }} Review due {{ review_assignment.review_request.deadline|date:"Y-m-d" }} + + Incomplete {% endif %} \ No newline at end of file diff --git a/ietf/templates/doc/review_request_summary.html b/ietf/templates/doc/review_request_summary.html new file mode 100644 index 0000000000..efeb4a030e --- /dev/null +++ b/ietf/templates/doc/review_request_summary.html @@ -0,0 +1,9 @@ + diff --git a/ietf/templates/doc/search/status_columns.html b/ietf/templates/doc/search/status_columns.html index 5e5c7b5d4e..aa0f049754 100644 --- a/ietf/templates/doc/search/status_columns.html +++ b/ietf/templates/doc/search/status_columns.html @@ -3,9 +3,7 @@ {% origin %} {% load ietf_filters ballot_icon person_filters %} - {% if doc.ballot %} -
{% ballot_icon doc %}
- {% endif %} +
{% ballot_icon doc %}
{% if not doc.get_state_slug == "rfc" %} {% if '::' in doc.friendly_state %} {{ doc.friendly_state|safe }} diff --git a/ietf/templates/doc/state_help.html b/ietf/templates/doc/state_help.html index d7678987ac..34481b7863 100644 --- a/ietf/templates/doc/state_help.html +++ b/ietf/templates/doc/state_help.html @@ -1,7 +1,6 @@ {% extends "base.html" %} {# Copyright The IETF Trust 2015, All Rights Reserved #} -{% load origin %} -{% load static %} +{% load origin static ietf_filters textfilters %} {% block title %}{{ title }}{% endblock %} {% block pagehead %} @@ -27,7 +26,7 @@

{{ title }}

{% for state in states %} {{ state.name }} - {{ state.desc|safe|linebreaksbr }} + {{ state.desc|urlize_ietf_docs|linkify }} {% if has_next_states %} {% for s in state.next_states.all %} diff --git a/ietf/templates/doc/statement/new_statement.html b/ietf/templates/doc/statement/new_statement.html new file mode 100644 index 0000000000..0742314ed1 --- /dev/null +++ b/ietf/templates/doc/statement/new_statement.html @@ -0,0 +1,18 @@ +{% extends "base.html" %} +{# Copyright The IETF Trust 2023, All Rights Reserved #} +{% load origin django_bootstrap5 static textfilters %} +{% block title %}Start a new Statement{% endblock %} +{% block content %} + {% origin %} +

Start a new Statement

+
+ {% csrf_token %} + {% bootstrap_form form layout="horizontal" %} + +
+{% endblock %} +{% block js %} + +{% endblock %} \ No newline at end of file diff --git a/ietf/templates/doc/statement/statement_template.md b/ietf/templates/doc/statement/statement_template.md new file mode 100644 index 0000000000..cc311530ec --- /dev/null +++ b/ietf/templates/doc/statement/statement_template.md @@ -0,0 +1 @@ +Replace this with the content of the statement in markdown source diff --git a/ietf/templates/doc/statement/upload_content.html b/ietf/templates/doc/statement/upload_content.html new file mode 100644 index 0000000000..712c44043d --- /dev/null +++ b/ietf/templates/doc/statement/upload_content.html @@ -0,0 +1,23 @@ +{% extends "base.html" %} +{# Copyright The IETF Trust 2023, All Rights Reserved #} +{% load origin django_bootstrap5 static %} +{% block title %}Upload new revision: {{ doc.name }}{% endblock %} +{% block content %} + {% origin %} +

+ Upload New Revision +
+ {{ doc.name }} +

+
+ {% csrf_token %} + {% bootstrap_form form layout="horizontal" %} + + Back +
+{% endblock %} +{% block js %} + +{% endblock %} \ No newline at end of file diff --git a/ietf/templates/doc/status_change/last_call.html b/ietf/templates/doc/status_change/last_call.html index c81792e82a..2f1f9666a9 100644 --- a/ietf/templates/doc/status_change/last_call.html +++ b/ietf/templates/doc/status_change/last_call.html @@ -11,6 +11,11 @@


{{ doc }}

+ {% if doc.ad is None %} +
+ A responsible AD must be set before last call can be requested. +
+ {% endif %}
{% csrf_token %} {% bootstrap_form last_call_form %} @@ -18,15 +23,17 @@

class="btn btn-primary" name="save_last_call_text" value="Save Last Call Text">Save text - - {% if user|has_role:"Secretariat" %} - Issue last call + {% if doc.ad is not None %} + + {% if user|has_role:"Secretariat" %} + Issue last call + {% endif %} {% endif %} + diff --git a/ietf/templates/nomcom/view_feedback_nominee.html b/ietf/templates/nomcom/view_feedback_nominee.html index 2a54435d92..0e8c043721 100644 --- a/ietf/templates/nomcom/view_feedback_nominee.html +++ b/ietf/templates/nomcom/view_feedback_nominee.html @@ -1,10 +1,13 @@ {% extends "nomcom/nomcom_private_base.html" %} -{# Copyright The IETF Trust 2015, All Rights Reserved #} +{# Copyright The IETF Trust 2015-2023, All Rights Reserved #} {% load origin %} {% load nomcom_tags textfilters %} {% block subtitle %}- View feedback about {{ nominee.email.person.name }}{% endblock %} {% block nomcom_content %} - {% origin %} +{% origin %} +{% if reclassify_feedback %} + {% include "nomcom/reclassify_feedback_item.html" %} +{% else %}

Feedback about {{ nominee }}