diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d1cb690dc6..6ba25ff55e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -201,8 +201,8 @@ jobs: - name: Collect + Push Statics env: DEBIAN_FRONTEND: noninteractive - AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_KEY_SECRET }} + AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_STATIC_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_STATIC_KEY_SECRET }} AWS_DEFAULT_REGION: auto AWS_ENDPOINT_URL: ${{ secrets.CF_R2_ENDPOINT }} run: | diff --git a/.gitignore b/.gitignore index 4de5e53ac3..c25e6b5bfe 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ datatracker.sublime-workspace /static /tmp-* /.testresult +*.swp *.pyc __pycache__ .yarn/* diff --git a/.pnp.cjs b/.pnp.cjs index 241319adb6..0c62d9b23c 100644 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -49,13 +49,14 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["@rollup/pluginutils", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.1.0"],\ ["@twuni/emojify", "npm:1.0.2"],\ ["@vitejs/plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:4.6.2"],\ + ["@vue/language-plugin-pug", "npm:2.0.7"],\ ["bootstrap", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.3.3"],\ ["bootstrap-icons", "npm:1.11.3"],\ ["browser-fs-access", "npm:0.35.0"],\ ["browserlist", "npm:1.0.1"],\ ["c8", "npm:9.1.0"],\ - ["caniuse-lite", "npm:1.0.30001597"],\ - ["d3", "npm:7.8.5"],\ + ["caniuse-lite", "npm:1.0.30001599"],\ + ["d3", "npm:7.9.0"],\ ["eslint", "npm:8.57.0"],\ ["eslint-config-standard", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:17.1.0"],\ ["eslint-plugin-cypress", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.15.1"],\ @@ -63,10 +64,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["eslint-plugin-n", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:16.6.2"],\ ["eslint-plugin-node", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:11.1.0"],\ ["eslint-plugin-promise", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.1"],\ - ["eslint-plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:9.22.0"],\ + ["eslint-plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:9.23.0"],\ ["file-saver", "npm:2.0.5"],\ ["highcharts", "npm:11.4.0"],\ - ["html-validate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:8.15.0"],\ + ["html-validate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:8.16.0"],\ ["ical.js", "npm:1.5.0"],\ ["jquery", "npm:3.7.1"],\ ["jquery-migrate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:3.4.1"],\ @@ -84,7 +85,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["pinia", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.1.7"],\ ["pinia-plugin-persist", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:1.0.0"],\ ["pug", "npm:3.0.2"],\ - ["sass", "npm:1.71.1"],\ + ["sass", "npm:1.72.0"],\ ["seedrandom", "npm:3.0.5"],\ ["select2", "npm:4.1.0-rc.0"],\ ["select2-bootstrap-5-theme", "npm:1.3.0"],\ @@ -2431,10 +2432,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ],\ "linkType": "SOFT"\ }],\ - ["virtual:2a2a921469e6f0bfdb6b2bd79f75a3395d47a481854507365048f3d989418f207cf814cb2ce1a012d2da774c1d130b4ca418582463ec08381da55e543b959c4c#npm:2.1.3", {\ - "packageLocation": "./.yarn/__virtual__/@sidvind-better-ajv-errors-virtual-6ac4a81dfc/0/cache/@sidvind-better-ajv-errors-npm-2.1.3-e3d1c524a8-949cb805a1.zip/node_modules/@sidvind/better-ajv-errors/",\ + ["virtual:127f44ed2d4bdd83725c8820683da6ed922142e851761151ec4911dcca098a2d4d832b774a31e7abf98185d360ff83c999b319ea3314c86d38eca853072fb0d2#npm:2.1.3", {\ + "packageLocation": "./.yarn/__virtual__/@sidvind-better-ajv-errors-virtual-ae7b5eb579/0/cache/@sidvind-better-ajv-errors-npm-2.1.3-e3d1c524a8-949cb805a1.zip/node_modules/@sidvind/better-ajv-errors/",\ "packageDependencies": [\ - ["@sidvind/better-ajv-errors", "virtual:2a2a921469e6f0bfdb6b2bd79f75a3395d47a481854507365048f3d989418f207cf814cb2ce1a012d2da774c1d130b4ca418582463ec08381da55e543b959c4c#npm:2.1.3"],\ + ["@sidvind/better-ajv-errors", "virtual:127f44ed2d4bdd83725c8820683da6ed922142e851761151ec4911dcca098a2d4d832b774a31e7abf98185d360ff83c999b319ea3314c86d38eca853072fb0d2#npm:2.1.3"],\ ["@babel/code-frame", "npm:7.16.7"],\ ["@types/ajv", null],\ ["ajv", "npm:8.11.0"],\ @@ -2721,6 +2722,48 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ + ["@volar/language-core", [\ + ["npm:2.1.4", {\ + "packageLocation": "./.yarn/cache/@volar-language-core-npm-2.1.4-18ee1a037d-7430f65143.zip/node_modules/@volar/language-core/",\ + "packageDependencies": [\ + ["@volar/language-core", "npm:2.1.4"],\ + ["@volar/source-map", "npm:2.1.4"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ + ["@volar/language-service", [\ + ["npm:2.1.4", {\ + "packageLocation": "./.yarn/cache/@volar-language-service-npm-2.1.4-2d34cb628f-06cdcfacf0.zip/node_modules/@volar/language-service/",\ + "packageDependencies": [\ + ["@volar/language-service", "npm:2.1.4"],\ + ["@volar/language-core", "npm:2.1.4"],\ + ["vscode-languageserver-protocol", "npm:3.17.5"],\ + ["vscode-languageserver-textdocument", "npm:1.0.11"],\ + ["vscode-uri", "npm:3.0.8"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ + ["@volar/source-map", [\ + ["npm:2.1.4", {\ + "packageLocation": "./.yarn/cache/@volar-source-map-npm-2.1.4-5963b1701f-e2f65bcfd6.zip/node_modules/@volar/source-map/",\ + "packageDependencies": [\ + ["@volar/source-map", "npm:2.1.4"],\ + ["muggle-string", "npm:0.4.1"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ + ["@vscode/l10n", [\ + ["npm:0.0.18", {\ + "packageLocation": "./.yarn/cache/@vscode-l10n-npm-0.0.18-8a12efe4b5-c33876cebd.zip/node_modules/@vscode/l10n/",\ + "packageDependencies": [\ + ["@vscode/l10n", "npm:0.0.18"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ ["@vue/compiler-core", [\ ["npm:3.4.21", {\ "packageLocation": "./.yarn/cache/@vue-compiler-core-npm-3.4.21-ec7f24d7f5-0d6b7732bc.zip/node_modules/@vue/compiler-core/",\ @@ -2791,6 +2834,17 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ + ["@vue/language-plugin-pug", [\ + ["npm:2.0.7", {\ + "packageLocation": "./.yarn/cache/@vue-language-plugin-pug-npm-2.0.7-547300c7e0-11cc96eb5f.zip/node_modules/@vue/language-plugin-pug/",\ + "packageDependencies": [\ + ["@vue/language-plugin-pug", "npm:2.0.7"],\ + ["@volar/source-map", "npm:2.1.4"],\ + ["volar-service-pug", "npm:0.0.34"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ ["@vue/reactivity", [\ ["npm:3.4.21", {\ "packageLocation": "./.yarn/cache/@vue-reactivity-npm-3.4.21-fd3e254d08-79c7ebe3ec.zip/node_modules/@vue/reactivity/",\ @@ -3452,10 +3506,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ],\ "linkType": "HARD"\ }],\ - ["npm:1.0.30001597", {\ - "packageLocation": "./.yarn/cache/caniuse-lite-npm-1.0.30001597-1e349680d5-ec6a2cf0fd.zip/node_modules/caniuse-lite/",\ + ["npm:1.0.30001599", {\ + "packageLocation": "./.yarn/cache/caniuse-lite-npm-1.0.30001599-834cd4cb82-d7e619e2e7.zip/node_modules/caniuse-lite/",\ "packageDependencies": [\ - ["caniuse-lite", "npm:1.0.30001597"]\ + ["caniuse-lite", "npm:1.0.30001599"]\ ],\ "linkType": "HARD"\ }]\ @@ -3764,10 +3818,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { }]\ ]],\ ["d3", [\ - ["npm:7.8.5", {\ - "packageLocation": "./.yarn/cache/d3-npm-7.8.5-5db20a5616-e407e79731.zip/node_modules/d3/",\ + ["npm:7.9.0", {\ + "packageLocation": "./.yarn/cache/d3-npm-7.9.0-d293821ce6-1c0e9135f1.zip/node_modules/d3/",\ "packageDependencies": [\ - ["d3", "npm:7.8.5"],\ + ["d3", "npm:7.9.0"],\ ["d3-array", "npm:3.1.6"],\ ["d3-axis", "npm:3.0.0"],\ ["d3-brush", "npm:3.0.0"],\ @@ -5041,17 +5095,17 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { }]\ ]],\ ["eslint-plugin-vue", [\ - ["npm:9.22.0", {\ - "packageLocation": "./.yarn/cache/eslint-plugin-vue-npm-9.22.0-2cdb92f3c1-5f1e94b412.zip/node_modules/eslint-plugin-vue/",\ + ["npm:9.23.0", {\ + "packageLocation": "./.yarn/cache/eslint-plugin-vue-npm-9.23.0-d36e581933-acb3a4dd27.zip/node_modules/eslint-plugin-vue/",\ "packageDependencies": [\ - ["eslint-plugin-vue", "npm:9.22.0"]\ + ["eslint-plugin-vue", "npm:9.23.0"]\ ],\ "linkType": "SOFT"\ }],\ - ["virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:9.22.0", {\ - "packageLocation": "./.yarn/__virtual__/eslint-plugin-vue-virtual-2da7be1523/0/cache/eslint-plugin-vue-npm-9.22.0-2cdb92f3c1-5f1e94b412.zip/node_modules/eslint-plugin-vue/",\ + ["virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:9.23.0", {\ + "packageLocation": "./.yarn/__virtual__/eslint-plugin-vue-virtual-a9cf4d7c43/0/cache/eslint-plugin-vue-npm-9.23.0-d36e581933-acb3a4dd27.zip/node_modules/eslint-plugin-vue/",\ "packageDependencies": [\ - ["eslint-plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:9.22.0"],\ + ["eslint-plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:9.23.0"],\ ["@eslint-community/eslint-utils", "virtual:4286e12a3a0f74af013bc8f16c6d8fdde823cfbf6389660266b171e551f576c805b0a7a8eb2a7087a5cee7dfe6ebb6e1ea3808d93daf915edc95656907a381bb#npm:4.4.0"],\ ["@types/eslint", null],\ ["eslint", "npm:8.57.0"],\ @@ -5059,7 +5113,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["nth-check", "npm:2.1.1"],\ ["postcss-selector-parser", "npm:6.0.15"],\ ["semver", "npm:7.6.0"],\ - ["vue-eslint-parser", "virtual:2da7be1523058e3d6960a64ca4697b767ffeb995ed69da9eb74f6f820005e744683aa6cde73ca784c556dfc97ad5b1bc884e0f3f37187c87e646cf74b01fce0e#npm:9.4.2"],\ + ["vue-eslint-parser", "virtual:a9cf4d7c437b03eeeb49b01b4b3434ca26b6f59f98831796df73ffd0744dcbe1bfe9c60f8b7e2c803ab0f29084730afdc0220af1db5d8d3d00531e0df4f49dbe#npm:9.4.2"],\ ["xml-name-validator", "npm:4.0.0"]\ ],\ "packagePeers": [\ @@ -5774,20 +5828,20 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { }]\ ]],\ ["html-validate", [\ - ["npm:8.15.0", {\ - "packageLocation": "./.yarn/cache/html-validate-npm-8.15.0-a1dfa4198d-0af7685ca1.zip/node_modules/html-validate/",\ + ["npm:8.16.0", {\ + "packageLocation": "./.yarn/cache/html-validate-npm-8.16.0-71c478330f-857b05ab87.zip/node_modules/html-validate/",\ "packageDependencies": [\ - ["html-validate", "npm:8.15.0"]\ + ["html-validate", "npm:8.16.0"]\ ],\ "linkType": "SOFT"\ }],\ - ["virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:8.15.0", {\ - "packageLocation": "./.yarn/__virtual__/html-validate-virtual-2a2a921469/0/cache/html-validate-npm-8.15.0-a1dfa4198d-0af7685ca1.zip/node_modules/html-validate/",\ + ["virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:8.16.0", {\ + "packageLocation": "./.yarn/__virtual__/html-validate-virtual-127f44ed2d/0/cache/html-validate-npm-8.16.0-71c478330f-857b05ab87.zip/node_modules/html-validate/",\ "packageDependencies": [\ - ["html-validate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:8.15.0"],\ + ["html-validate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:8.16.0"],\ ["@babel/code-frame", "npm:7.16.7"],\ ["@html-validate/stylish", "npm:4.1.0"],\ - ["@sidvind/better-ajv-errors", "virtual:2a2a921469e6f0bfdb6b2bd79f75a3395d47a481854507365048f3d989418f207cf814cb2ce1a012d2da774c1d130b4ca418582463ec08381da55e543b959c4c#npm:2.1.3"],\ + ["@sidvind/better-ajv-errors", "virtual:127f44ed2d4bdd83725c8820683da6ed922142e851761151ec4911dcca098a2d4d832b774a31e7abf98185d360ff83c999b319ea3314c86d38eca853072fb0d2#npm:2.1.3"],\ ["@types/jest", null],\ ["@types/jest-diff", null],\ ["@types/jest-snapshot", null],\ @@ -7153,6 +7207,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ + ["muggle-string", [\ + ["npm:0.4.1", {\ + "packageLocation": "./.yarn/cache/muggle-string-npm-0.4.1-fe3c825cc2-85fe1766d1.zip/node_modules/muggle-string/",\ + "packageDependencies": [\ + ["muggle-string", "npm:0.4.1"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ ["murmurhash-js", [\ ["npm:1.0.0", {\ "packageLocation": "./.yarn/cache/murmurhash-js-npm-1.0.0-b1fa804bc0-083cea92a1.zip/node_modules/murmurhash-js/",\ @@ -8269,13 +8332,14 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["@rollup/pluginutils", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.1.0"],\ ["@twuni/emojify", "npm:1.0.2"],\ ["@vitejs/plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:4.6.2"],\ + ["@vue/language-plugin-pug", "npm:2.0.7"],\ ["bootstrap", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.3.3"],\ ["bootstrap-icons", "npm:1.11.3"],\ ["browser-fs-access", "npm:0.35.0"],\ ["browserlist", "npm:1.0.1"],\ ["c8", "npm:9.1.0"],\ - ["caniuse-lite", "npm:1.0.30001597"],\ - ["d3", "npm:7.8.5"],\ + ["caniuse-lite", "npm:1.0.30001599"],\ + ["d3", "npm:7.9.0"],\ ["eslint", "npm:8.57.0"],\ ["eslint-config-standard", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:17.1.0"],\ ["eslint-plugin-cypress", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.15.1"],\ @@ -8283,10 +8347,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["eslint-plugin-n", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:16.6.2"],\ ["eslint-plugin-node", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:11.1.0"],\ ["eslint-plugin-promise", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.1"],\ - ["eslint-plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:9.22.0"],\ + ["eslint-plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:9.23.0"],\ ["file-saver", "npm:2.0.5"],\ ["highcharts", "npm:11.4.0"],\ - ["html-validate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:8.15.0"],\ + ["html-validate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:8.16.0"],\ ["ical.js", "npm:1.5.0"],\ ["jquery", "npm:3.7.1"],\ ["jquery-migrate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:3.4.1"],\ @@ -8304,7 +8368,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["pinia", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.1.7"],\ ["pinia-plugin-persist", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:1.0.0"],\ ["pug", "npm:3.0.2"],\ - ["sass", "npm:1.71.1"],\ + ["sass", "npm:1.72.0"],\ ["seedrandom", "npm:3.0.5"],\ ["select2", "npm:4.1.0-rc.0"],\ ["select2-bootstrap-5-theme", "npm:1.3.0"],\ @@ -8401,10 +8465,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ],\ "linkType": "HARD"\ }],\ - ["npm:1.71.1", {\ - "packageLocation": "./.yarn/cache/sass-npm-1.71.1-3aced13991-19c4939d30.zip/node_modules/sass/",\ + ["npm:1.72.0", {\ + "packageLocation": "./.yarn/cache/sass-npm-1.72.0-fb38bb530c-f420079c7d.zip/node_modules/sass/",\ "packageDependencies": [\ - ["sass", "npm:1.71.1"],\ + ["sass", "npm:1.72.0"],\ ["chokidar", "npm:3.5.3"],\ ["immutable", "npm:4.0.0"],\ ["source-map-js", "npm:1.0.2"]\ @@ -9227,7 +9291,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["lightningcss", null],\ ["postcss", "npm:8.4.33"],\ ["rollup", "npm:3.29.4"],\ - ["sass", "npm:1.71.1"],\ + ["sass", "npm:1.72.0"],\ ["stylus", null],\ ["sugarss", null],\ ["terser", null]\ @@ -9259,6 +9323,46 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ + ["volar-service-html", [\ + ["npm:0.0.34", {\ + "packageLocation": "./.yarn/cache/volar-service-html-npm-0.0.34-32b6d24136-83b50cd805.zip/node_modules/volar-service-html/",\ + "packageDependencies": [\ + ["volar-service-html", "npm:0.0.34"]\ + ],\ + "linkType": "SOFT"\ + }],\ + ["virtual:6f5429e17c4ecd390af605a4e97ecc7b34f2f1374a5e30c21f0a978cbdc904738a42d0d6f5d44d2e969250218b3c205853d6afefd88b87bcda877286d12bef83#npm:0.0.34", {\ + "packageLocation": "./.yarn/__virtual__/volar-service-html-virtual-5a9107a24d/0/cache/volar-service-html-npm-0.0.34-32b6d24136-83b50cd805.zip/node_modules/volar-service-html/",\ + "packageDependencies": [\ + ["volar-service-html", "virtual:6f5429e17c4ecd390af605a4e97ecc7b34f2f1374a5e30c21f0a978cbdc904738a42d0d6f5d44d2e969250218b3c205853d6afefd88b87bcda877286d12bef83#npm:0.0.34"],\ + ["@types/volar__language-service", null],\ + ["@volar/language-service", "npm:2.1.4"],\ + ["vscode-html-languageservice", "npm:5.1.2"],\ + ["vscode-languageserver-textdocument", "npm:1.0.11"],\ + ["vscode-uri", "npm:3.0.8"]\ + ],\ + "packagePeers": [\ + "@types/volar__language-service",\ + "@volar/language-service"\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ + ["volar-service-pug", [\ + ["npm:0.0.34", {\ + "packageLocation": "./.yarn/cache/volar-service-pug-npm-0.0.34-6f5429e17c-4691aa1c8e.zip/node_modules/volar-service-pug/",\ + "packageDependencies": [\ + ["volar-service-pug", "npm:0.0.34"],\ + ["@volar/language-service", "npm:2.1.4"],\ + ["pug-lexer", "npm:5.0.1"],\ + ["pug-parser", "npm:6.0.0"],\ + ["volar-service-html", "virtual:6f5429e17c4ecd390af605a4e97ecc7b34f2f1374a5e30c21f0a978cbdc904738a42d0d6f5d44d2e969250218b3c205853d6afefd88b87bcda877286d12bef83#npm:0.0.34"],\ + ["vscode-html-languageservice", "npm:5.1.2"],\ + ["vscode-languageserver-textdocument", "npm:1.0.11"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ ["vooks", [\ ["npm:0.2.12", {\ "packageLocation": "./.yarn/cache/vooks-npm-0.2.12-0d1a2d856b-e6841ec5b6.zip/node_modules/vooks/",\ @@ -9282,6 +9386,66 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ + ["vscode-html-languageservice", [\ + ["npm:5.1.2", {\ + "packageLocation": "./.yarn/cache/vscode-html-languageservice-npm-5.1.2-2ea2618bdd-3a2a5ee5ad.zip/node_modules/vscode-html-languageservice/",\ + "packageDependencies": [\ + ["vscode-html-languageservice", "npm:5.1.2"],\ + ["@vscode/l10n", "npm:0.0.18"],\ + ["vscode-languageserver-textdocument", "npm:1.0.11"],\ + ["vscode-languageserver-types", "npm:3.17.5"],\ + ["vscode-uri", "npm:3.0.8"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ + ["vscode-jsonrpc", [\ + ["npm:8.2.0", {\ + "packageLocation": "./.yarn/cache/vscode-jsonrpc-npm-8.2.0-b7d2e5b553-f302a01e59.zip/node_modules/vscode-jsonrpc/",\ + "packageDependencies": [\ + ["vscode-jsonrpc", "npm:8.2.0"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ + ["vscode-languageserver-protocol", [\ + ["npm:3.17.5", {\ + "packageLocation": "./.yarn/cache/vscode-languageserver-protocol-npm-3.17.5-2b07e16989-dfb42d276d.zip/node_modules/vscode-languageserver-protocol/",\ + "packageDependencies": [\ + ["vscode-languageserver-protocol", "npm:3.17.5"],\ + ["vscode-jsonrpc", "npm:8.2.0"],\ + ["vscode-languageserver-types", "npm:3.17.5"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ + ["vscode-languageserver-textdocument", [\ + ["npm:1.0.11", {\ + "packageLocation": "./.yarn/cache/vscode-languageserver-textdocument-npm-1.0.11-6fc94d2b7b-ea7cdc9d4f.zip/node_modules/vscode-languageserver-textdocument/",\ + "packageDependencies": [\ + ["vscode-languageserver-textdocument", "npm:1.0.11"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ + ["vscode-languageserver-types", [\ + ["npm:3.17.5", {\ + "packageLocation": "./.yarn/cache/vscode-languageserver-types-npm-3.17.5-aca3b71a5a-79b420e757.zip/node_modules/vscode-languageserver-types/",\ + "packageDependencies": [\ + ["vscode-languageserver-types", "npm:3.17.5"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ + ["vscode-uri", [\ + ["npm:3.0.8", {\ + "packageLocation": "./.yarn/cache/vscode-uri-npm-3.0.8-56f46b9d24-5142491268.zip/node_modules/vscode-uri/",\ + "packageDependencies": [\ + ["vscode-uri", "npm:3.0.8"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ ["vue", [\ ["npm:3.4.21", {\ "packageLocation": "./.yarn/cache/vue-npm-3.4.21-02110aa6d9-3c477982a0.zip/node_modules/vue/",\ @@ -9367,10 +9531,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ],\ "linkType": "SOFT"\ }],\ - ["virtual:2da7be1523058e3d6960a64ca4697b767ffeb995ed69da9eb74f6f820005e744683aa6cde73ca784c556dfc97ad5b1bc884e0f3f37187c87e646cf74b01fce0e#npm:9.4.2", {\ - "packageLocation": "./.yarn/__virtual__/vue-eslint-parser-virtual-989a31128c/0/cache/vue-eslint-parser-npm-9.4.2-3e4e696025-67f14c8ea1.zip/node_modules/vue-eslint-parser/",\ + ["virtual:a9cf4d7c437b03eeeb49b01b4b3434ca26b6f59f98831796df73ffd0744dcbe1bfe9c60f8b7e2c803ab0f29084730afdc0220af1db5d8d3d00531e0df4f49dbe#npm:9.4.2", {\ + "packageLocation": "./.yarn/__virtual__/vue-eslint-parser-virtual-6710b98248/0/cache/vue-eslint-parser-npm-9.4.2-3e4e696025-67f14c8ea1.zip/node_modules/vue-eslint-parser/",\ "packageDependencies": [\ - ["vue-eslint-parser", "virtual:2da7be1523058e3d6960a64ca4697b767ffeb995ed69da9eb74f6f820005e744683aa6cde73ca784c556dfc97ad5b1bc884e0f3f37187c87e646cf74b01fce0e#npm:9.4.2"],\ + ["vue-eslint-parser", "virtual:a9cf4d7c437b03eeeb49b01b4b3434ca26b6f59f98831796df73ffd0744dcbe1bfe9c60f8b7e2c803ab0f29084730afdc0220af1db5d8d3d00531e0df4f49dbe#npm:9.4.2"],\ ["@types/eslint", null],\ ["debug", "virtual:b86a9fb34323a98c6519528ed55faa0d9b44ca8879307c0b29aa384bde47ff59a7d0c9051b31246f14521dfb71ba3c5d6d0b35c29fffc17bf875aa6ad977d9e8#npm:4.3.4"],\ ["eslint", "npm:8.57.0"],\ diff --git a/.yarn/cache/@volar-language-core-npm-2.1.4-18ee1a037d-7430f65143.zip b/.yarn/cache/@volar-language-core-npm-2.1.4-18ee1a037d-7430f65143.zip new file mode 100644 index 0000000000..25e6d3f94d Binary files /dev/null and b/.yarn/cache/@volar-language-core-npm-2.1.4-18ee1a037d-7430f65143.zip differ diff --git a/.yarn/cache/@volar-language-service-npm-2.1.4-2d34cb628f-06cdcfacf0.zip b/.yarn/cache/@volar-language-service-npm-2.1.4-2d34cb628f-06cdcfacf0.zip new file mode 100644 index 0000000000..5f494d902e Binary files /dev/null and b/.yarn/cache/@volar-language-service-npm-2.1.4-2d34cb628f-06cdcfacf0.zip differ diff --git a/.yarn/cache/@volar-source-map-npm-2.1.4-5963b1701f-e2f65bcfd6.zip b/.yarn/cache/@volar-source-map-npm-2.1.4-5963b1701f-e2f65bcfd6.zip new file mode 100644 index 0000000000..0ea96c4d97 Binary files /dev/null and b/.yarn/cache/@volar-source-map-npm-2.1.4-5963b1701f-e2f65bcfd6.zip differ diff --git a/.yarn/cache/@vscode-l10n-npm-0.0.18-8a12efe4b5-c33876cebd.zip b/.yarn/cache/@vscode-l10n-npm-0.0.18-8a12efe4b5-c33876cebd.zip new file mode 100644 index 0000000000..2d6533a204 Binary files /dev/null and b/.yarn/cache/@vscode-l10n-npm-0.0.18-8a12efe4b5-c33876cebd.zip differ diff --git a/.yarn/cache/@vue-language-plugin-pug-npm-2.0.7-547300c7e0-11cc96eb5f.zip b/.yarn/cache/@vue-language-plugin-pug-npm-2.0.7-547300c7e0-11cc96eb5f.zip new file mode 100644 index 0000000000..e637e5f556 Binary files /dev/null and b/.yarn/cache/@vue-language-plugin-pug-npm-2.0.7-547300c7e0-11cc96eb5f.zip differ diff --git a/.yarn/cache/caniuse-lite-npm-1.0.30001597-1e349680d5-ec6a2cf0fd.zip b/.yarn/cache/caniuse-lite-npm-1.0.30001597-1e349680d5-ec6a2cf0fd.zip deleted file mode 100644 index f1545a78ff..0000000000 Binary files a/.yarn/cache/caniuse-lite-npm-1.0.30001597-1e349680d5-ec6a2cf0fd.zip and /dev/null differ diff --git a/.yarn/cache/caniuse-lite-npm-1.0.30001599-834cd4cb82-d7e619e2e7.zip b/.yarn/cache/caniuse-lite-npm-1.0.30001599-834cd4cb82-d7e619e2e7.zip new file mode 100644 index 0000000000..a87ecfaa8e Binary files /dev/null and b/.yarn/cache/caniuse-lite-npm-1.0.30001599-834cd4cb82-d7e619e2e7.zip differ diff --git a/.yarn/cache/d3-npm-7.8.5-5db20a5616-e407e79731.zip b/.yarn/cache/d3-npm-7.8.5-5db20a5616-e407e79731.zip deleted file mode 100644 index b06dd3f260..0000000000 Binary files a/.yarn/cache/d3-npm-7.8.5-5db20a5616-e407e79731.zip and /dev/null differ diff --git a/.yarn/cache/d3-npm-7.9.0-d293821ce6-1c0e9135f1.zip b/.yarn/cache/d3-npm-7.9.0-d293821ce6-1c0e9135f1.zip new file mode 100644 index 0000000000..e78ffffee5 Binary files /dev/null and b/.yarn/cache/d3-npm-7.9.0-d293821ce6-1c0e9135f1.zip differ diff --git a/.yarn/cache/eslint-plugin-vue-npm-9.22.0-2cdb92f3c1-5f1e94b412.zip b/.yarn/cache/eslint-plugin-vue-npm-9.23.0-d36e581933-acb3a4dd27.zip similarity index 83% rename from .yarn/cache/eslint-plugin-vue-npm-9.22.0-2cdb92f3c1-5f1e94b412.zip rename to .yarn/cache/eslint-plugin-vue-npm-9.23.0-d36e581933-acb3a4dd27.zip index b0eff51136..738f5c44c5 100644 Binary files a/.yarn/cache/eslint-plugin-vue-npm-9.22.0-2cdb92f3c1-5f1e94b412.zip and b/.yarn/cache/eslint-plugin-vue-npm-9.23.0-d36e581933-acb3a4dd27.zip differ diff --git a/.yarn/cache/html-validate-npm-8.15.0-a1dfa4198d-0af7685ca1.zip b/.yarn/cache/html-validate-npm-8.15.0-a1dfa4198d-0af7685ca1.zip deleted file mode 100644 index fed180abd3..0000000000 Binary files a/.yarn/cache/html-validate-npm-8.15.0-a1dfa4198d-0af7685ca1.zip and /dev/null differ diff --git a/.yarn/cache/html-validate-npm-8.16.0-71c478330f-857b05ab87.zip b/.yarn/cache/html-validate-npm-8.16.0-71c478330f-857b05ab87.zip new file mode 100644 index 0000000000..3ae560c224 Binary files /dev/null and b/.yarn/cache/html-validate-npm-8.16.0-71c478330f-857b05ab87.zip differ diff --git a/.yarn/cache/muggle-string-npm-0.4.1-fe3c825cc2-85fe1766d1.zip b/.yarn/cache/muggle-string-npm-0.4.1-fe3c825cc2-85fe1766d1.zip new file mode 100644 index 0000000000..4cec1b177d Binary files /dev/null and b/.yarn/cache/muggle-string-npm-0.4.1-fe3c825cc2-85fe1766d1.zip differ diff --git a/.yarn/cache/sass-npm-1.71.1-3aced13991-19c4939d30.zip b/.yarn/cache/sass-npm-1.71.1-3aced13991-19c4939d30.zip deleted file mode 100644 index f1ee7f94d2..0000000000 Binary files a/.yarn/cache/sass-npm-1.71.1-3aced13991-19c4939d30.zip and /dev/null differ diff --git a/.yarn/cache/sass-npm-1.72.0-fb38bb530c-f420079c7d.zip b/.yarn/cache/sass-npm-1.72.0-fb38bb530c-f420079c7d.zip new file mode 100644 index 0000000000..a3aea4e668 Binary files /dev/null and b/.yarn/cache/sass-npm-1.72.0-fb38bb530c-f420079c7d.zip differ diff --git a/.yarn/cache/volar-service-html-npm-0.0.34-32b6d24136-83b50cd805.zip b/.yarn/cache/volar-service-html-npm-0.0.34-32b6d24136-83b50cd805.zip new file mode 100644 index 0000000000..0f1e9805f7 Binary files /dev/null and b/.yarn/cache/volar-service-html-npm-0.0.34-32b6d24136-83b50cd805.zip differ diff --git a/.yarn/cache/volar-service-pug-npm-0.0.34-6f5429e17c-4691aa1c8e.zip b/.yarn/cache/volar-service-pug-npm-0.0.34-6f5429e17c-4691aa1c8e.zip new file mode 100644 index 0000000000..d53f3521ee Binary files /dev/null and b/.yarn/cache/volar-service-pug-npm-0.0.34-6f5429e17c-4691aa1c8e.zip differ diff --git a/.yarn/cache/vscode-html-languageservice-npm-5.1.2-2ea2618bdd-3a2a5ee5ad.zip b/.yarn/cache/vscode-html-languageservice-npm-5.1.2-2ea2618bdd-3a2a5ee5ad.zip new file mode 100644 index 0000000000..d83607888b Binary files /dev/null and b/.yarn/cache/vscode-html-languageservice-npm-5.1.2-2ea2618bdd-3a2a5ee5ad.zip differ diff --git a/.yarn/cache/vscode-jsonrpc-npm-8.2.0-b7d2e5b553-f302a01e59.zip b/.yarn/cache/vscode-jsonrpc-npm-8.2.0-b7d2e5b553-f302a01e59.zip new file mode 100644 index 0000000000..75e2c086b6 Binary files /dev/null and b/.yarn/cache/vscode-jsonrpc-npm-8.2.0-b7d2e5b553-f302a01e59.zip differ diff --git a/.yarn/cache/vscode-languageserver-protocol-npm-3.17.5-2b07e16989-dfb42d276d.zip b/.yarn/cache/vscode-languageserver-protocol-npm-3.17.5-2b07e16989-dfb42d276d.zip new file mode 100644 index 0000000000..bcb5ae5b4e Binary files /dev/null and b/.yarn/cache/vscode-languageserver-protocol-npm-3.17.5-2b07e16989-dfb42d276d.zip differ diff --git a/.yarn/cache/vscode-languageserver-textdocument-npm-1.0.11-6fc94d2b7b-ea7cdc9d4f.zip b/.yarn/cache/vscode-languageserver-textdocument-npm-1.0.11-6fc94d2b7b-ea7cdc9d4f.zip new file mode 100644 index 0000000000..b1edfda12d Binary files /dev/null and b/.yarn/cache/vscode-languageserver-textdocument-npm-1.0.11-6fc94d2b7b-ea7cdc9d4f.zip differ diff --git a/.yarn/cache/vscode-languageserver-types-npm-3.17.5-aca3b71a5a-79b420e757.zip b/.yarn/cache/vscode-languageserver-types-npm-3.17.5-aca3b71a5a-79b420e757.zip new file mode 100644 index 0000000000..ec214b2903 Binary files /dev/null and b/.yarn/cache/vscode-languageserver-types-npm-3.17.5-aca3b71a5a-79b420e757.zip differ diff --git a/.yarn/cache/vscode-uri-npm-3.0.8-56f46b9d24-5142491268.zip b/.yarn/cache/vscode-uri-npm-3.0.8-56f46b9d24-5142491268.zip new file mode 100644 index 0000000000..6dadd110c9 Binary files /dev/null and b/.yarn/cache/vscode-uri-npm-3.0.8-56f46b9d24-5142491268.zip differ diff --git a/bin/daily b/bin/daily index bd33ca2e0b..8211e1e237 100755 --- a/bin/daily +++ b/bin/daily @@ -47,8 +47,5 @@ $DTDIR/ietf/manage.py run_yang_model_checks -v0 # Enable when removed from /a/www/ietf-datatracker/scripts/Cron-runner: $DTDIR/ietf/bin/expire-last-calls -# Send reminders originating from the review app -$DTDIR/ietf/bin/send-review-reminders - # Purge older PersonApiKeyEvents $DTDIR/ietf/manage.py purge_old_personal_api_key_events 14 diff --git a/client/agenda/Agenda.vue b/client/agenda/Agenda.vue index 0212fc8cb6..34a3751f23 100644 --- a/client/agenda/Agenda.vue +++ b/client/agenda/Agenda.vue @@ -58,14 +58,17 @@ n-button( :type='agendaStore.isTimezoneMeeting ? `primary` : `default`' @click='setTimezone(`meeting`)' + :text-color='agendaStore.isTimezoneMeeting ? `#FFF` : null' ) Meeting n-button( :type='agendaStore.isTimezoneLocal ? `primary` : `default`' @click='setTimezone(`local`)' + :text-color='agendaStore.isTimezoneLocal ? `#FFF` : null' ) Local n-button( :type='agendaStore.timezone === `UTC` ? `primary` : `default`' @click='setTimezone(`UTC`)' + :text-color='agendaStore.timezone === `UTC` ? `#FFF` : null' ) UTC n-select.agenda-timezone-ddn( v-if='siteStore.viewport > 1250' diff --git a/client/agenda/AgendaQuickAccess.vue b/client/agenda/AgendaQuickAccess.vue index 5952e6de1c..99adc1027e 100644 --- a/client/agenda/AgendaQuickAccess.vue +++ b/client/agenda/AgendaQuickAccess.vue @@ -62,7 +62,8 @@ n-button.mt-2( id='agenda-quickaccess-calview-btn' block - color='#6c757d' + color='#6f42c1' + text-color='#FFF' size='large' strong @click='agendaStore.$patch({ calendarShown: true })' @@ -78,8 +79,8 @@ n-button.mt-2( id='agenda-quickaccess-addtocal-btn' block - secondary - color='#6c757d' + :color='siteStore.theme === `dark` ? `rgba(111, 66, 193, .3)` : `#e2d9f3`' + :text-color='siteStore.theme === `dark` ? `#e2d9f3` : `#59359a`' size='large' strong ) diff --git a/client/agenda/AgendaScheduleCalendar.vue b/client/agenda/AgendaScheduleCalendar.vue index d8a30ca4ad..9b56b7f5a7 100644 --- a/client/agenda/AgendaScheduleCalendar.vue +++ b/client/agenda/AgendaScheduleCalendar.vue @@ -11,14 +11,17 @@ n-drawer(v-model:show='isShown', placement='bottom', :height='state.drawerHeight n-button( :type='agendaStore.isTimezoneMeeting ? `primary` : `default`' @click='setTimezone(`meeting`)' + :text-color='agendaStore.isTimezoneMeeting ? `#FFF` : null' ) Meeting n-button( :type='agendaStore.isTimezoneLocal ? `primary` : `default`' @click='setTimezone(`local`)' + :text-color='agendaStore.isTimezoneLocal ? `#FFF` : null' ) Local n-button( :type='agendaStore.timezone === `UTC` ? `primary` : `default`' @click='setTimezone(`UTC`)' + :text-color='agendaStore.timezone === `UTC` ? `#FFF` : null' ) UTC n-divider(vertical) n-button.me-2( @@ -32,7 +35,7 @@ n-drawer(v-model:show='isShown', placement='bottom', :height='state.drawerHeight n-badge.ms-2(:value='agendaStore.selectedCatSubs.length', processing) n-button( ghost - color='gray' + :color='siteStore.theme === `dark` ? `#e35d6a` : `gray`' strong @click='close' ) diff --git a/client/components/Polls.vue b/client/components/Polls.vue index f5023995a3..30cc9e8f36 100644 --- a/client/components/Polls.vue +++ b/client/components/Polls.vue @@ -3,9 +3,11 @@ n-data-table( v-if='state.items.length > 0' :data='state.items' - :columns='columns' + :columns='state.columns' striped ) + span.text-danger(v-else-if='state.errMessage') + em {{ state.errMessage }} span.text-body-secondary(v-else) em No polls available. @@ -13,9 +15,8 @@ diff --git a/debug.py b/debug.py index bf34367cce..e6aed2e9bd 100644 --- a/debug.py +++ b/debug.py @@ -55,7 +55,7 @@ def fix(s,n=64): if len(s) > n+3: s = s[:n]+"..." return s - def wrap(fn, *params,**kwargs): + def wrap(*params,**kwargs): call = wrap.callcount = wrap.callcount + 1 indent = ' ' * _report_indent[0] @@ -81,8 +81,8 @@ def wrap(fn, *params,**kwargs): return ret wrap.callcount = 0 if debug: - from decorator import decorator - return decorator(wrap, fn) + from functools import update_wrapper + return update_wrapper(wrap, fn) else: return fn @@ -119,7 +119,7 @@ def clock(s): def time(fn): """Decorator to print timing information about a function call. """ - def wrap(fn, *params,**kwargs): + def wrap(*params,**kwargs): indent = ' ' * _report_indent[0] fc = "%s.%s()" % (fn.__module__, fn.__name__,) @@ -132,8 +132,8 @@ def wrap(fn, *params,**kwargs): return ret wrap.callcount = 0 if debug: - from decorator import decorator - return decorator(wrap, fn) + from functools import update_wrapper + return update_wrapper(wrap, fn) else: return fn @@ -190,7 +190,7 @@ def type(name): value = eval(name, frame.f_globals, frame.f_locals) indent = ' ' * (_report_indent[0]) sys.stderr.write("%s%s: %s\n" % (indent, name, value)) - + def say(s): if debug: indent = ' ' * (_report_indent[0]) @@ -205,11 +205,11 @@ def wrapper(*args, **kwargs): prof.dump_stats(datafn) return retval if debug: - from decorator import decorator - return decorator(wrapper, fn) + from functools import update_wrapper + return update_wrapper(wrapper, fn) else: return fn - + def traceback(levels=None): if debug: indent = ' ' * (_report_indent[0]) diff --git a/dev/coverage-action/package-lock.json b/dev/coverage-action/package-lock.json index 835f1a6cc8..f89bd58386 100644 --- a/dev/coverage-action/package-lock.json +++ b/dev/coverage-action/package-lock.json @@ -22,7 +22,7 @@ "eslint-plugin-import": "2.29.1", "eslint-plugin-node": "11.1.0", "eslint-plugin-promise": "6.1.1", - "npm-check-updates": "16.14.15" + "npm-check-updates": "16.14.17" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -4079,9 +4079,9 @@ } }, "node_modules/npm-check-updates": { - "version": "16.14.15", - "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-16.14.15.tgz", - "integrity": "sha512-WH0wJ9j6CP7Azl+LLCxWAYqroT2IX02kRIzgK/fg0rPpMbETgHITWBdOPtrv521xmA3JMgeNsQ62zvVtS/nCmQ==", + "version": "16.14.17", + "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-16.14.17.tgz", + "integrity": "sha512-ElnDdXKe60f8S6RhzFeaGuH2TFJmt2cU2HjLdowldabdm27nWFCxV2ebeP3xGbQkzp2+RPDQNdW9HqU1lcY8ag==", "dev": true, "dependencies": { "chalk": "^5.3.0", @@ -9249,9 +9249,9 @@ } }, "npm-check-updates": { - "version": "16.14.15", - "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-16.14.15.tgz", - "integrity": "sha512-WH0wJ9j6CP7Azl+LLCxWAYqroT2IX02kRIzgK/fg0rPpMbETgHITWBdOPtrv521xmA3JMgeNsQ62zvVtS/nCmQ==", + "version": "16.14.17", + "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-16.14.17.tgz", + "integrity": "sha512-ElnDdXKe60f8S6RhzFeaGuH2TFJmt2cU2HjLdowldabdm27nWFCxV2ebeP3xGbQkzp2+RPDQNdW9HqU1lcY8ag==", "dev": true, "requires": { "chalk": "^5.3.0", diff --git a/dev/coverage-action/package.json b/dev/coverage-action/package.json index e758561e44..4738139600 100644 --- a/dev/coverage-action/package.json +++ b/dev/coverage-action/package.json @@ -19,6 +19,6 @@ "eslint-plugin-import": "2.29.1", "eslint-plugin-node": "11.1.0", "eslint-plugin-promise": "6.1.1", - "npm-check-updates": "16.14.15" + "npm-check-updates": "16.14.17" } } diff --git a/ietf/checks.py b/ietf/checks.py index f9ad87db70..f66182a027 100644 --- a/ietf/checks.py +++ b/ietf/checks.py @@ -42,14 +42,14 @@ def check_group_email_aliases_exists(app_configs, **kwargs): if not ok: errors.append(checks.Error( "Found no aliases in the group email aliases file\n'%s'."%settings.GROUP_ALIASES_PATH, - hint="Please run the generate_group_aliases management command to generate them.", + hint="These should be created by the infrastructure using ietf/bin/aliases-from-json.py.", obj=None, id="datatracker.E0002", )) except IOError as e: errors.append(checks.Error( "Could not read group email aliases:\n %s" % e, - hint="Please run the generate_group_aliases management command to generate them.", + hint="These should be created by the infrastructure using ietf/bin/aliases-from-json.py.", obj=None, id="datatracker.E0003", )) @@ -69,14 +69,14 @@ def check_doc_email_aliases_exists(app_configs, **kwargs): if not ok: errors.append(checks.Error( "Found no aliases in the document email aliases file\n'%s'."%settings.DRAFT_VIRTUAL_PATH, - hint="Please run the generate_draft_aliases management command to generate them.", + hint="These should be created by the infrastructure using ietf/bin/aliases-from-json.py.", obj=None, id="datatracker.E0004", )) except IOError as e: errors.append(checks.Error( "Could not read document email aliases:\n %s" % e, - hint="Please run the generate_draft_aliases management command to generate them.", + hint="These should be created by the infrastructure using ietf/bin/aliases-from-json.py.", obj=None, id="datatracker.E0005", )) diff --git a/ietf/doc/management/commands/generate_draft_aliases.py b/ietf/doc/management/commands/generate_draft_aliases.py deleted file mode 100755 index 6d42a66a18..0000000000 --- a/ietf/doc/management/commands/generate_draft_aliases.py +++ /dev/null @@ -1,183 +0,0 @@ -# Copyright The IETF Trust 2012-2021, All Rights Reserved -# -*- coding: utf-8 -*- - -# This was written as a script by Markus Stenberg . -# It was turned into a management command by Russ Housley . - -import datetime -import io -import os -import re -import shutil -import stat -import time - -from tempfile import mkstemp - -from django.conf import settings -from django.core.management.base import BaseCommand -from django.utils import timezone - -import debug # pyflakes:ignore - -from ietf.doc.models import Document -from ietf.group.utils import get_group_role_emails, get_group_ad_emails -from ietf.utils.aliases import dump_sublist -from utils.mail import parseaddr -from ietf.utils import log - -DEFAULT_YEARS = 2 - - -def get_draft_ad_emails(doc): - """Get AD email addresses for the given draft, if any.""" - ad_emails = set() - # If working group document, return current WG ADs - if doc.group and doc.group.acronym != 'none': - ad_emails.update(get_group_ad_emails(doc.group)) - # Document may have an explicit AD set - if doc.ad: - ad_emails.add(doc.ad.email_address()) - return ad_emails - - -def get_draft_chair_emails(doc): - """Get chair email addresses for the given draft, if any.""" - chair_emails = set() - if doc.group: - chair_emails.update(get_group_role_emails(doc.group, ['chair', 'secr'])) - return chair_emails - - -def get_draft_shepherd_email(doc): - """Get shepherd email addresses for the given draft, if any.""" - shepherd_email = set() - if doc.shepherd: - shepherd_email.add(doc.shepherd.email_address()) - return shepherd_email - - -def get_draft_authors_emails(doc): - """Get list of authors for the given draft.""" - author_emails = set() - for author in doc.documentauthor_set.all(): - if author.email and author.email.email_address(): - author_emails.add(author.email.email_address()) - return author_emails - - -def get_draft_notify_emails(doc): - """Get list of email addresses to notify for the given draft.""" - ad_email_alias_regex = r"^%s.ad@(%s|%s)$" % (doc.name, settings.DRAFT_ALIAS_DOMAIN, settings.TOOLS_SERVER) - all_email_alias_regex = r"^%s.all@(%s|%s)$" % (doc.name, settings.DRAFT_ALIAS_DOMAIN, settings.TOOLS_SERVER) - author_email_alias_regex = r"^%s@(%s|%s)$" % (doc.name, settings.DRAFT_ALIAS_DOMAIN, settings.TOOLS_SERVER) - notify_email_alias_regex = r"^%s.notify@(%s|%s)$" % (doc.name, settings.DRAFT_ALIAS_DOMAIN, settings.TOOLS_SERVER) - shepherd_email_alias_regex = r"^%s.shepherd@(%s|%s)$" % (doc.name, settings.DRAFT_ALIAS_DOMAIN, settings.TOOLS_SERVER) - notify_emails = set() - if doc.notify: - for e in doc.notify.split(','): - e = e.strip() - if re.search(ad_email_alias_regex, e): - notify_emails.update(get_draft_ad_emails(doc)) - elif re.search(author_email_alias_regex, e): - notify_emails.update(get_draft_authors_emails(doc)) - elif re.search(shepherd_email_alias_regex, e): - notify_emails.update(get_draft_shepherd_email(doc)) - elif re.search(all_email_alias_regex, e): - notify_emails.update(get_draft_ad_emails(doc)) - notify_emails.update(get_draft_authors_emails(doc)) - notify_emails.update(get_draft_shepherd_email(doc)) - elif re.search(notify_email_alias_regex, e): - pass - else: - (name, email) = parseaddr(e) - notify_emails.add(email) - return notify_emails - - -class Command(BaseCommand): - help = ('Generate the draft-aliases and draft-virtual files for Internet-Draft ' - 'mail aliases, placing them in the files configured in ' - 'settings.DRAFT_ALIASES_PATH and settings.DRAFT_VIRTUAL_PATH, ' - 'respectively. The generation includes aliases for Internet-Drafts ' - 'that have seen activity in the last %s years.' % (DEFAULT_YEARS)) - - def handle(self, *args, **options): - show_since = timezone.now() - datetime.timedelta(DEFAULT_YEARS*365) - - date = time.strftime("%Y-%m-%d_%H:%M:%S") - signature = '# Generated by %s at %s\n' % (os.path.abspath(__file__), date) - - ahandle, aname = mkstemp() - os.close(ahandle) - afile = io.open(aname,"w") - - vhandle, vname = mkstemp() - os.close(vhandle) - vfile = io.open(vname,"w") - - afile.write(signature) - vfile.write(signature) - vfile.write("%s anything\n" % settings.DRAFT_VIRTUAL_DOMAIN) - - # Internet-Drafts with active status or expired within DEFAULT_YEARS - drafts = Document.objects.filter(type_id="draft") - active_drafts = drafts.filter(states__slug='active') - inactive_recent_drafts = drafts.exclude(states__slug='active').filter(expires__gte=show_since) - interesting_drafts = active_drafts | inactive_recent_drafts - - alias_domains = ['ietf.org', ] - for draft in interesting_drafts.distinct().iterator(): - # Omit drafts that became RFCs, unless they were published in the last DEFAULT_YEARS - if draft.get_state_slug()=="rfc": - rfc = draft.became_rfc() - log.assertion("rfc is not None") - if rfc.latest_event(type='published_rfc').time < show_since: - continue - - alias = draft.name - all = set() - - # no suffix and .authors are the same list - emails = get_draft_authors_emails(draft) - all.update(emails) - dump_sublist(afile, vfile, alias, alias_domains, settings.DRAFT_VIRTUAL_DOMAIN, emails) - dump_sublist(afile, vfile, alias+'.authors', alias_domains, settings.DRAFT_VIRTUAL_DOMAIN, emails) - - # .chairs = group chairs - emails = get_draft_chair_emails(draft) - if emails: - all.update(emails) - dump_sublist(afile, vfile, alias+'.chairs', alias_domains, settings.DRAFT_VIRTUAL_DOMAIN, emails) - - # .ad = sponsoring AD / WG AD (WG document) - emails = get_draft_ad_emails(draft) - if emails: - all.update(emails) - dump_sublist(afile, vfile, alias+'.ad', alias_domains, settings.DRAFT_VIRTUAL_DOMAIN, emails) - - # .notify = notify email list from the Document - emails = get_draft_notify_emails(draft) - if emails: - all.update(emails) - dump_sublist(afile, vfile, alias+'.notify', alias_domains, settings.DRAFT_VIRTUAL_DOMAIN, emails) - - # .shepherd = shepherd email from the Document - emails = get_draft_shepherd_email(draft) - if emails: - all.update(emails) - dump_sublist(afile, vfile, alias+'.shepherd', alias_domains, settings.DRAFT_VIRTUAL_DOMAIN, emails) - - # .all = everything from above - dump_sublist(afile, vfile, alias+'.all', alias_domains, settings.DRAFT_VIRTUAL_DOMAIN, all) - - afile.close() - vfile.close() - - os.chmod(aname, stat.S_IWUSR|stat.S_IRUSR|stat.S_IRGRP|stat.S_IROTH) - os.chmod(vname, stat.S_IWUSR|stat.S_IRUSR|stat.S_IRGRP|stat.S_IROTH) - - shutil.move(aname, settings.DRAFT_ALIASES_PATH) - shutil.move(vname, settings.DRAFT_VIRTUAL_PATH) - - \ No newline at end of file diff --git a/ietf/doc/templatetags/ietf_filters.py b/ietf/doc/templatetags/ietf_filters.py index cfed7aa1db..a791aad383 100644 --- a/ietf/doc/templatetags/ietf_filters.py +++ b/ietf/doc/templatetags/ietf_filters.py @@ -881,3 +881,21 @@ def badgeify(blob): ) return text + +@register.filter +def simple_history_delta_changes(history): + """Returns diff between given history and previous entry.""" + prev = history.prev_record + if prev: + delta = history.diff_against(prev) + return delta.changes + return [] + +@register.filter +def simple_history_delta_change_cnt(history): + """Returns number of changes between given history and previous entry.""" + prev = history.prev_record + if prev: + delta = history.diff_against(prev) + return len(delta.changes) + return 0 diff --git a/ietf/doc/tests.py b/ietf/doc/tests.py index 0ad26b7adc..d4a6504213 100644 --- a/ietf/doc/tests.py +++ b/ietf/doc/tests.py @@ -37,7 +37,7 @@ from ietf.doc.models import ( Document, DocRelationshipName, RelatedDocument, State, DocEvent, BallotPositionDocEvent, LastCallDocEvent, WriteupDocEvent, NewRevisionDocEvent, BallotType, - EditedAuthorsDocEvent ) + EditedAuthorsDocEvent, StateType) from ietf.doc.factories import ( DocumentFactory, DocEventFactory, CharterFactory, ConflictReviewFactory, WgDraftFactory, IndividualDraftFactory, WgRfcFactory, IndividualRfcFactory, StateDocEventFactory, BallotPositionDocEventFactory, @@ -2181,152 +2181,6 @@ def tearDown(self): os.unlink(self.doc_virtual_file.name) super().tearDown() - def testManagementCommand(self): - a_month_ago = (timezone.now() - datetime.timedelta(30)).astimezone(RPC_TZINFO) - a_month_ago = a_month_ago.replace(hour=0, minute=0, second=0, microsecond=0) - ad = RoleFactory( - name_id="ad", group__type_id="area", group__state_id="active" - ).person - shepherd = PersonFactory() - author1 = PersonFactory() - author2 = PersonFactory() - author3 = PersonFactory() - author4 = PersonFactory() - author5 = PersonFactory() - author6 = PersonFactory() - mars = GroupFactory(type_id="wg", acronym="mars") - marschairman = PersonFactory(user__username="marschairman") - mars.role_set.create( - name_id="chair", person=marschairman, email=marschairman.email() - ) - doc1 = IndividualDraftFactory( - authors=[author1], shepherd=shepherd.email(), ad=ad - ) - doc2 = WgDraftFactory( - name="draft-ietf-mars-test", group__acronym="mars", authors=[author2], ad=ad - ) - doc3 = WgDraftFactory.create( - name="draft-ietf-mars-finished", - group__acronym="mars", - authors=[author3], - ad=ad, - std_level_id="ps", - states=[("draft", "rfc"), ("draft-iesg", "pub")], - time=a_month_ago, - ) - rfc3 = WgRfcFactory() - DocEventFactory.create(doc=rfc3, type="published_rfc", time=a_month_ago) - doc3.relateddocument_set.create( - relationship_id="became_rfc", target=rfc3 - ) - doc4 = WgDraftFactory.create( - authors=[author4, author5], - ad=ad, - std_level_id="ps", - states=[("draft", "rfc"), ("draft-iesg", "pub")], - time=datetime.datetime(2010, 10, 10, tzinfo=ZoneInfo(settings.TIME_ZONE)), - ) - rfc4 = WgRfcFactory() - DocEventFactory.create( - doc=rfc4, - type="published_rfc", - time=datetime.datetime(2010, 10, 10, tzinfo=RPC_TZINFO), - ) - doc4.relateddocument_set.create( - relationship_id="became_rfc", target=rfc4 - ) - doc5 = IndividualDraftFactory(authors=[author6]) - - args = [] - kwargs = {} - out = io.StringIO() - call_command("generate_draft_aliases", *args, **kwargs, stdout=out, stderr=out) - self.assertFalse(out.getvalue()) - - with open(settings.DRAFT_ALIASES_PATH) as afile: - acontent = afile.read() - for x in [ - "xfilter-" + doc1.name, - "xfilter-" + doc1.name + ".ad", - "xfilter-" + doc1.name + ".authors", - "xfilter-" + doc1.name + ".shepherd", - "xfilter-" + doc1.name + ".all", - "xfilter-" + doc2.name, - "xfilter-" + doc2.name + ".ad", - "xfilter-" + doc2.name + ".authors", - "xfilter-" + doc2.name + ".chairs", - "xfilter-" + doc2.name + ".all", - "xfilter-" + doc3.name, - "xfilter-" + doc3.name + ".ad", - "xfilter-" + doc3.name + ".authors", - "xfilter-" + doc3.name + ".chairs", - "xfilter-" + doc5.name, - "xfilter-" + doc5.name + ".authors", - "xfilter-" + doc5.name + ".all", - ]: - self.assertIn(x, acontent) - - for x in [ - "xfilter-" + doc1.name + ".chairs", - "xfilter-" + doc2.name + ".shepherd", - "xfilter-" + doc3.name + ".shepherd", - "xfilter-" + doc4.name, - "xfilter-" + doc5.name + ".shepherd", - "xfilter-" + doc5.name + ".ad", - ]: - self.assertNotIn(x, acontent) - - with open(settings.DRAFT_VIRTUAL_PATH) as vfile: - vcontent = vfile.read() - for x in [ - ad.email_address(), - shepherd.email_address(), - marschairman.email_address(), - author1.email_address(), - author2.email_address(), - author3.email_address(), - author6.email_address(), - ]: - self.assertIn(x, vcontent) - - for x in [ - author4.email_address(), - author5.email_address(), - ]: - self.assertNotIn(x, vcontent) - - for x in [ - "xfilter-" + doc1.name, - "xfilter-" + doc1.name + ".ad", - "xfilter-" + doc1.name + ".authors", - "xfilter-" + doc1.name + ".shepherd", - "xfilter-" + doc1.name + ".all", - "xfilter-" + doc2.name, - "xfilter-" + doc2.name + ".ad", - "xfilter-" + doc2.name + ".authors", - "xfilter-" + doc2.name + ".chairs", - "xfilter-" + doc2.name + ".all", - "xfilter-" + doc3.name, - "xfilter-" + doc3.name + ".ad", - "xfilter-" + doc3.name + ".authors", - "xfilter-" + doc3.name + ".chairs", - "xfilter-" + doc3.name + ".all", - "xfilter-" + doc5.name, - "xfilter-" + doc5.name + ".authors", - "xfilter-" + doc5.name + ".all", - ]: - self.assertIn(x, vcontent) - - for x in [ - "xfilter-" + doc1.name + ".chairs", - "xfilter-" + doc2.name + ".shepherd", - "xfilter-" + doc3.name + ".shepherd", - "xfilter-" + doc4.name, - "xfilter-" + doc5.name + ".shepherd", - "xfilter-" + doc5.name + ".ad", - ]: - self.assertNotIn(x, vcontent) - @override_settings(TOOLS_SERVER="tools.example.org", DRAFT_ALIAS_DOMAIN="draft.example.org") def test_generator_class(self): """The DraftAliasGenerator should generate the same lists as the old mgmt cmd""" @@ -3273,3 +3127,17 @@ def test_referenced_by_rfcs_as_rfc_or_draft(self): rfc.referenced_by_rfcs_as_rfc_or_draft(), draft.targets_related.filter(source__type="rfc") | rfc.targets_related.filter(source__type="rfc"), ) + +class StateIndexTests(TestCase): + + def test_state_index(self): + url = urlreverse('ietf.doc.views_help.state_index') + r = self.client.get(url) + q = PyQuery(r.content) + content = [ e.text for e in q('#content table td a ') ] + names = StateType.objects.values_list('slug', flat=True) + # The following doesn't cover all doc types, only a selection + for name in names: + if not '-' in name: + self.assertIn(name, content) + diff --git a/ietf/doc/tests_draft.py b/ietf/doc/tests_draft.py index 045fdc7f46..cc22e22139 100644 --- a/ietf/doc/tests_draft.py +++ b/ietf/doc/tests_draft.py @@ -20,7 +20,7 @@ import debug # pyflakes:ignore from ietf.doc.expire import get_expired_drafts, send_expire_notice_for_draft, expire_draft -from ietf.doc.factories import IndividualDraftFactory, WgDraftFactory, RgDraftFactory, DocEventFactory +from ietf.doc.factories import EditorialDraftFactory, IndividualDraftFactory, WgDraftFactory, RgDraftFactory, DocEventFactory from ietf.doc.models import ( Document, DocReminder, DocEvent, ConsensusDocEvent, LastCallDocEvent, RelatedDocument, State, TelechatDocEvent, WriteupDocEvent, DocRelationshipName, IanaExpertDocEvent ) @@ -2161,3 +2161,13 @@ def test_shepherd_writeup_generation(self): self.assertContains(r, "for Group Documents", status_code=200) r = self.client.post(url,dict(reset_text='')) self.assertContains(r, "for Group Documents", status_code=200) + +class EditorialDraftMetadataTests(TestCase): + def test_editorial_metadata(self): + draft = EditorialDraftFactory() + url = urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=draft.name)) + r = self.client.get(url) + q = PyQuery(r.content) + top_level_metadata_headings = q("tbody>tr>th:first-child").text() + self.assertNotIn("IESG", top_level_metadata_headings) + self.assertNotIn("IANA", top_level_metadata_headings) diff --git a/ietf/doc/urls.py b/ietf/doc/urls.py index 496b2d8f3a..d29fd9da14 100644 --- a/ietf/doc/urls.py +++ b/ietf/doc/urls.py @@ -163,6 +163,7 @@ url(r'^%(name)s/edit/issueballot/rsab/$' % settings.URL_REGEXPS, views_ballot.issue_rsab_ballot), url(r'^%(name)s/edit/closeballot/rsab/$' % settings.URL_REGEXPS, views_ballot.close_rsab_ballot), + url(r'^help/state/?$', views_help.state_index), url(r'^help/state/(?P[\w-]+)/$', views_help.state_help), url(r'^help/relationships/$', views_help.relationship_help), url(r'^help/relationships/(?P\w+)/$', views_help.relationship_help), diff --git a/ietf/doc/utils.py b/ietf/doc/utils.py index ad1c2af223..4872f41fc4 100644 --- a/ietf/doc/utils.py +++ b/ietf/doc/utils.py @@ -1062,6 +1062,8 @@ def build_file_urls(doc: Union[Document, DocHistory]): base = settings.IETF_ID_ARCHIVE_URL file_urls = [] for t in found_types: + if t == "ps": # Postscript might have been submitted but should not be displayed in the list of URLs + continue label = "plain text" if t == "txt" else t file_urls.append((label, base + doc.name + "-" + doc.rev + "." + t)) diff --git a/ietf/doc/views_help.py b/ietf/doc/views_help.py index e8e63ed8b7..34d29aaccb 100644 --- a/ietf/doc/views_help.py +++ b/ietf/doc/views_help.py @@ -9,6 +9,18 @@ from ietf.name.models import DocRelationshipName, DocTagName from ietf.doc.utils import get_tags_for_stream_id +def state_index(request): + types = StateType.objects.all() + names = [ type.slug for type in types ] + for type in types: + if "-" in type.slug and type.slug.split('-',1)[0] in names: + type.stategroups = None + else: + groups = StateType.objects.filter(slug__startswith=type.slug) + type.stategroups = [ g.slug[len(type.slug)+1:] for g in groups if not g == type ] or "" + + return render(request, 'doc/state_index.html', {"types": types}) + def state_help(request, type=None): slug, title = { "draft-iesg": ("draft-iesg", "IESG States for Internet-Drafts"), @@ -26,7 +38,30 @@ def state_help(request, type=None): "status-change": ("statchg", "RFC Status Change States"), "bofreq": ("bofreq", "BOF Request States"), "procmaterials": ("procmaterials", "Proceedings Materials States"), - "statement": {"statement", "Statement States"} + "statement": ("statement", "Statement States"), + "slides": ("slides", "Slides States"), + "minutes": ("minutes", "Minutes States"), + "liai-att": ("liai-att", "Liaison Attachment States"), + "recording": ("recording", "Recording States"), + "bluesheets": ("bluesheets", "Bluesheets States"), + "reuse_policy": ("reuse_policy", "Reuse Policy States"), + "review": ("review", "Review States"), + "liaison": ("liaison", "Liaison States"), + "shepwrit": ("shepwrit", "Shapherd Writeup States"), + "bofreq": ("bofreq", "BOF Request States"), + "procmaterials": ("procmaterials", "Proceedings Materials States"), + "chatlog": ("chatlog", "Chat Log States"), + "polls": ("polls", "Polls States"), + "statement": ("statement", "Statement States"), + "rfc": ("rfc", "RFC States"), + "bcp": ("bcp", "BCP States"), + "std": ("std", "STD States"), + "fyi": ("fyi", "FYI States"), + "narrativeminutes": ("narrativeminutes", "Narrative Minutes States"), + "draft": ("draft", "Draft States"), + "statchg": ("statchg", "Status Change States"), + "agenda": ("agenda", "Agenda States"), + "conflrev": ("conflrev", "Conflict Review States") }.get(type, (None, None)) state_type = get_object_or_404(StateType, slug=slug) diff --git a/ietf/doc/views_review.py b/ietf/doc/views_review.py index f1f9d7be4e..04c558ce3e 100644 --- a/ietf/doc/views_review.py +++ b/ietf/doc/views_review.py @@ -1053,7 +1053,11 @@ def edit_deadline(request, name, request_id): if form.is_valid(): if form.cleaned_data['deadline'] != old_deadline: form.save() - subject = "Deadline changed: {} {} review of {}-{}".format(review_req.team.acronym.capitalize(),review_req.type.name.lower(), review_req.doc.name, review_req.requested_rev) + subject = f"Deadline changed: {review_req.team.acronym.capitalize()} {review_req.type.name.lower()} review of {review_req.doc.name}" + if review_req.requested_rev: + subject += f"-{review_req.requested_rev}" + descr = "Deadine changed from {} to {}".format(old_deadline, review_req.deadline) + update_change_reason(review_req, descr) msg = render_to_string("review/deadline_changed.txt", { "review_req": review_req, "old_deadline": old_deadline, diff --git a/ietf/group/management/commands/generate_group_aliases.py b/ietf/group/management/commands/generate_group_aliases.py deleted file mode 100755 index 630f35c441..0000000000 --- a/ietf/group/management/commands/generate_group_aliases.py +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright The IETF Trust 2012-2021, All Rights Reserved -# -*- coding: utf-8 -*- - -# This was written as a script by Markus Stenberg . -# It was turned into a management command by Russ Housley . - -import datetime -import io -import os -import shutil -import stat -import time - -from tempfile import mkstemp - -from django.conf import settings -from django.core.management.base import BaseCommand -from django.utils import timezone - -import debug # pyflakes:ignore - -from ietf.group.models import Group -from ietf.group.utils import get_group_ad_emails, get_group_role_emails, get_child_group_role_emails -from ietf.name.models import GroupTypeName -from ietf.utils.aliases import dump_sublist - -DEFAULT_YEARS = 5 -ACTIVE_STATES=['active', 'bof', 'proposed'] -GROUP_TYPES=['wg', 'rg', 'rag', 'dir', 'team', 'review', 'program', 'rfcedtyp', 'edappr', 'edwg'] # This should become groupfeature driven... -NO_AD_GROUP_TYPES=['rg', 'rag', 'team', 'program', 'rfcedtyp', 'edappr', 'edwg'] -IETF_DOMAIN=['ietf.org', ] -IRTF_DOMAIN=['irtf.org', ] -IAB_DOMAIN=['iab.org', ] - -class Command(BaseCommand): - help = ('Generate the group-aliases and group-virtual files for Internet-Draft ' - 'mail aliases, placing them in the file configured in ' - 'settings.GROUP_ALIASES_PATH and settings.GROUP_VIRTUAL_PATH, ' - 'respectively. The generation includes aliases for groups that ' - 'have seen activity in the last %s years.' % (DEFAULT_YEARS)) - - def handle(self, *args, **options): - show_since = timezone.now() - datetime.timedelta(DEFAULT_YEARS*365) - - date = time.strftime("%Y-%m-%d_%H:%M:%S") - signature = '# Generated by %s at %s\n' % (os.path.abspath(__file__), date) - - ahandle, aname = mkstemp() - os.close(ahandle) - afile = io.open(aname,"w") - - vhandle, vname = mkstemp() - os.close(vhandle) - vfile = io.open(vname,"w") - - afile.write(signature) - vfile.write(signature) - vfile.write("%s anything\n" % settings.GROUP_VIRTUAL_DOMAIN) - - # Loop through each group type and build -ads and -chairs entries - for g in GROUP_TYPES: - domains = [] - domains += IETF_DOMAIN - if g in ('rg', 'rag'): - domains += IRTF_DOMAIN - if g == 'program': - domains += IAB_DOMAIN - - entries = Group.objects.filter(type=g).all() - active_entries = entries.filter(state__in=ACTIVE_STATES) - inactive_recent_entries = entries.exclude(state__in=ACTIVE_STATES).filter(time__gte=show_since) - interesting_entries = active_entries | inactive_recent_entries - - for e in interesting_entries.distinct().iterator(): - name = e.acronym - - # Research groups, teams, and programs do not have -ads lists - if not g in NO_AD_GROUP_TYPES: - dump_sublist(afile, vfile, name+'-ads', domains, settings.GROUP_VIRTUAL_DOMAIN, get_group_ad_emails(e)) - # All group types have -chairs lists - dump_sublist(afile, vfile, name+'-chairs', domains, settings.GROUP_VIRTUAL_DOMAIN, get_group_role_emails(e, ['chair', 'secr'])) - - # The area lists include every chair in active working groups in the area - areas = Group.objects.filter(type='area').all() - active_areas = areas.filter(state__in=ACTIVE_STATES) - for area in active_areas: - name = area.acronym - area_ad_emails = get_group_role_emails(area, ['pre-ad', 'ad', 'chair']) - dump_sublist(afile, vfile, name+'-ads', IETF_DOMAIN, settings.GROUP_VIRTUAL_DOMAIN, area_ad_emails) - dump_sublist(afile, vfile, name+'-chairs', IETF_DOMAIN, settings.GROUP_VIRTUAL_DOMAIN, (get_child_group_role_emails(area, ['chair', 'secr']) | area_ad_emails)) - - # Other groups with chairs that require Internet-Draft submission approval - gtypes = GroupTypeName.objects.values_list('slug', flat=True) - special_groups = Group.objects.filter(type__features__req_subm_approval=True, acronym__in=gtypes, state='active') - for group in special_groups: - dump_sublist(afile, vfile, group.acronym+'-chairs', IETF_DOMAIN, settings.GROUP_VIRTUAL_DOMAIN, get_group_role_emails(group, ['chair', 'delegate'])) - - afile.close() - vfile.close() - - os.chmod(aname, stat.S_IWUSR|stat.S_IRUSR|stat.S_IRGRP|stat.S_IROTH) - os.chmod(vname, stat.S_IWUSR|stat.S_IRUSR|stat.S_IRGRP|stat.S_IROTH) - - shutil.move(aname, settings.GROUP_ALIASES_PATH) - shutil.move(vname, settings.GROUP_VIRTUAL_PATH) diff --git a/ietf/group/tests.py b/ietf/group/tests.py index 66a854000d..8ae6a626b2 100644 --- a/ietf/group/tests.py +++ b/ietf/group/tests.py @@ -1,14 +1,12 @@ # Copyright The IETF Trust 2013-2020, All Rights Reserved # -*- coding: utf-8 -*- -import io import os import datetime import json from tempfile import NamedTemporaryFile -from django.core.management import call_command from django.conf import settings from django.urls import reverse as urlreverse from django.db.models import Q @@ -146,108 +144,6 @@ def tearDown(self): os.unlink(self.doc_virtual_file.name) super().tearDown() - def testManagementCommand(self): - a_month_ago = timezone.now() - datetime.timedelta(30) - a_decade_ago = timezone.now() - datetime.timedelta(3650) - role1 = RoleFactory(name_id='ad', group__type_id='area', group__acronym='myth', group__state_id='active') - area = role1.group - ad = role1.person - mars = GroupFactory(type_id='wg', acronym='mars', parent=area) - marschair = PersonFactory(user__username='marschair') - mars.role_set.create(name_id='chair', person=marschair, email=marschair.email()) - marssecr = PersonFactory(user__username='marssecr') - mars.role_set.create(name_id='secr', person=marssecr, email=marssecr.email()) - ames = GroupFactory(type_id='wg', acronym='ames', parent=area) - ameschair = PersonFactory(user__username='ameschair') - ames.role_set.create(name_id='chair', person=ameschair, email=ameschair.email()) - recent = GroupFactory(type_id='wg', acronym='recent', parent=area, state_id='conclude', time=a_month_ago) - recentchair = PersonFactory(user__username='recentchair') - recent.role_set.create(name_id='chair', person=recentchair, email=recentchair.email()) - wayold = GroupFactory(type_id='wg', acronym='wayold', parent=area, state_id='conclude', time=a_decade_ago) - wayoldchair = PersonFactory(user__username='wayoldchair') - wayold.role_set.create(name_id='chair', person=wayoldchair, email=wayoldchair.email()) - role2 = RoleFactory(name_id='ad', group__type_id='area', group__acronym='done', group__state_id='conclude') - done = role2.group - done_ad = role2.person - irtf = Group.objects.get(acronym='irtf') - testrg = GroupFactory(type_id='rg', acronym='testrg', parent=irtf) - testrgchair = PersonFactory(user__username='testrgchair') - testrg.role_set.create(name_id='chair', person=testrgchair, email=testrgchair.email()) - testrag = GroupFactory(type_id='rg', acronym='testrag', parent=irtf) - testragchair = PersonFactory(user__username='testragchair') - testrag.role_set.create(name_id='chair', person=testragchair, email=testragchair.email()) - individual = PersonFactory() - - args = [ ] - kwargs = { } - out = io.StringIO() - call_command("generate_group_aliases", *args, **kwargs, stdout=out, stderr=out) - self.assertFalse(out.getvalue()) - - with open(settings.GROUP_ALIASES_PATH) as afile: - acontent = afile.read() - self.assertTrue('xfilter-' + area.acronym + '-ads' in acontent) - self.assertTrue('xfilter-' + area.acronym + '-chairs' in acontent) - self.assertTrue('xfilter-' + mars.acronym + '-ads' in acontent) - self.assertTrue('xfilter-' + mars.acronym + '-chairs' in acontent) - self.assertTrue('xfilter-' + ames.acronym + '-ads' in acontent) - self.assertTrue('xfilter-' + ames.acronym + '-chairs' in acontent) - self.assertTrue(all([x in acontent for x in [ - 'xfilter-' + area.acronym + '-ads', - 'xfilter-' + area.acronym + '-chairs', - 'xfilter-' + mars.acronym + '-ads', - 'xfilter-' + mars.acronym + '-chairs', - 'xfilter-' + ames.acronym + '-ads', - 'xfilter-' + ames.acronym + '-chairs', - 'xfilter-' + recent.acronym + '-ads', - 'xfilter-' + recent.acronym + '-chairs', - ]])) - self.assertFalse(all([x in acontent for x in [ - 'xfilter-' + done.acronym + '-ads', - 'xfilter-' + done.acronym + '-chairs', - 'xfilter-' + wayold.acronym + '-ads', - 'xfilter-' + wayold.acronym + '-chairs', - ]])) - - with open(settings.GROUP_VIRTUAL_PATH) as vfile: - vcontent = vfile.read() - self.assertTrue(all([x in vcontent for x in [ - ad.email_address(), - marschair.email_address(), - marssecr.email_address(), - ameschair.email_address(), - recentchair.email_address(), - testrgchair.email_address(), - testragchair.email_address(), - ]])) - self.assertFalse(any([x in vcontent for x in [ - done_ad.email_address(), - wayoldchair.email_address(), - individual.email_address(), - ]])) - self.assertTrue(all([x in vcontent for x in [ - 'xfilter-' + area.acronym + '-ads', - 'xfilter-' + area.acronym + '-chairs', - 'xfilter-' + mars.acronym + '-ads', - 'xfilter-' + mars.acronym + '-chairs', - 'xfilter-' + ames.acronym + '-ads', - 'xfilter-' + ames.acronym + '-chairs', - 'xfilter-' + recent.acronym + '-ads', - 'xfilter-' + recent.acronym + '-chairs', - 'xfilter-' + testrg.acronym + '-chairs', - 'xfilter-' + testrag.acronym + '-chairs', - testrg.acronym + '-chairs@ietf.org', - testrg.acronym + '-chairs@irtf.org', - testrag.acronym + '-chairs@ietf.org', - testrag.acronym + '-chairs@irtf.org', - ]])) - self.assertFalse(all([x in vcontent for x in [ - 'xfilter-' + done.acronym + '-ads', - 'xfilter-' + done.acronym + '-chairs', - 'xfilter-' + wayold.acronym + '-ads', - 'xfilter-' + wayold.acronym + '-chairs', - ]])) - def test_generator_class(self): """The GroupAliasGenerator should generate the same lists as the old mgmt cmd""" # clean out test fixture group roles we don't need for this test diff --git a/ietf/help/tests_views.py b/ietf/help/tests_views.py deleted file mode 100644 index ee80dad865..0000000000 --- a/ietf/help/tests_views.py +++ /dev/null @@ -1,21 +0,0 @@ -from pyquery import PyQuery - -from django.urls import reverse - -import debug # pyflakes:ignore - -from ietf.utils.test_utils import TestCase -from ietf.doc.models import StateType - -class HelpPageTests(TestCase): - - def test_state_index(self): - url = reverse('ietf.help.views.state_index') - r = self.client.get(url) - q = PyQuery(r.content) - content = [ e.text for e in q('#content table td a ') ] - names = StateType.objects.values_list('slug', flat=True) - # The following doesn't cover all doc types, only a selection - for name in names: - if not '-' in name: - self.assertIn(name, content) diff --git a/ietf/help/urls.py b/ietf/help/urls.py index f1cc625fa7..90ce7e12e9 100644 --- a/ietf/help/urls.py +++ b/ietf/help/urls.py @@ -2,10 +2,10 @@ from ietf.help import views from ietf.utils.urls import url +from django.views.generic import RedirectView urlpatterns = [ url(r'^state/(?P[-\w]+)/(?P[-\w]+)/?$', views.state), url(r'^state/(?P[-\w]+)/?$', views.state), - url(r'^state/?$', views.state_index), + url(r'^state/?$', RedirectView.as_view(url='/doc/help/state/', permanent=True)), ] - diff --git a/ietf/help/views.py b/ietf/help/views.py index 6b10f9f6c3..493bf0dcf1 100644 --- a/ietf/help/views.py +++ b/ietf/help/views.py @@ -1,23 +1,11 @@ # Copyright The IETF Trust 2007, All Rights Reserved -from django.shortcuts import get_object_or_404, render - import debug # pyflakes:ignore -from ietf.doc.models import State, StateType from ietf.name.models import StreamName +from django.shortcuts import redirect -def state_index(request): - types = StateType.objects.all() - names = [ type.slug for type in types ] - for type in types: - if "-" in type.slug and type.slug.split('-',1)[0] in names: - type.stategroups = None - else: - groups = StateType.objects.filter(slug__startswith=type.slug) - type.stategroups = [ g.slug[len(type.slug)+1:] for g in groups if not g == type ] or "" - - return render(request, 'help/state_index.html', {"types": types}) +# This is just a redirect to the new URL under /doc; can probably go away eventually. def state(request, doc, type=None): if type: @@ -25,6 +13,5 @@ def state(request, doc, type=None): if type in streams: type = "stream-%s" % type slug = "%s-%s" % (doc,type) if type else doc - statetype = get_object_or_404(StateType, slug=slug) - states = State.objects.filter(used=True, type=statetype).order_by('order') - return render(request, 'help/states.html', {"doc": doc, "type": statetype, "states":states} ) + return redirect('/doc/help/state/%s' % slug, permanent = True) + \ No newline at end of file diff --git a/ietf/mailtrigger/utils.py b/ietf/mailtrigger/utils.py index d8b23ff056..9915eae3fd 100644 --- a/ietf/mailtrigger/utils.py +++ b/ietf/mailtrigger/utils.py @@ -149,9 +149,5 @@ def starts_with(prefix): return sorted(rule_list) -def get_base_submission_message_address(): - return Recipient.objects.get(slug="submission_manualpost_handling").gather()[0] - - def get_base_ipr_request_address(): return Recipient.objects.get(slug="ipr_requests").gather()[0] diff --git a/ietf/meeting/tests_views.py b/ietf/meeting/tests_views.py index 8d355d97e0..75babd86c2 100644 --- a/ietf/meeting/tests_views.py +++ b/ietf/meeting/tests_views.py @@ -8598,7 +8598,7 @@ def test_session_attendance(self): self.assertEqual(r.status_code, 200) self.assertContains(r, '3 attendees') for person in persons: - self.assertContains(r, person.name) + self.assertContains(r, person.plain_name()) # Test for the "I was there" button. def _test_button(person, expected): @@ -8618,14 +8618,14 @@ def _test_button(person, expected): # attempt to POST anyway is ignored r = self.client.post(attendance_url) self.assertEqual(r.status_code, 200) - self.assertNotContains(r, persons[3].name) + self.assertNotContains(r, persons[3].plain_name()) self.assertEqual(session.attended_set.count(), 3) # button is shown, and POST is accepted meeting.importantdate_set.update(name_id='revsub',date=date_today() + datetime.timedelta(days=20)) _test_button(persons[3], True) r = self.client.post(attendance_url) self.assertEqual(r.status_code, 200) - self.assertContains(r, persons[3].name) + self.assertContains(r, persons[3].plain_name()) self.assertEqual(session.attended_set.count(), 4) # When the meeting is finalized, a bluesheet file is generated, @@ -8639,7 +8639,7 @@ def _test_button(person, expected): text = doc.text() self.assertIn('4 attendees', text) for person in persons: - self.assertIn(person.name, text) + self.assertIn(person.plain_name(), text) r = self.client.get(session_url) self.assertContains(r, doc.get_href()) self.assertNotContains(r, attendance_url) diff --git a/ietf/name/fixtures/names.json b/ietf/name/fixtures/names.json index e54233eda0..35679dcaa1 100644 --- a/ietf/name/fixtures/names.json +++ b/ietf/name/fixtures/names.json @@ -2604,6 +2604,19 @@ "model": "doc.state", "pk": 179 }, + { + "fields": { + "desc": "The editorial stream processing of this document is complete and it has been sent to the RFC Editor for publication. The document may be in the RFC Editor's queue, or it may have been published as an RFC; this state doesn't distinguish between different states occurring after the document has left the RSAB.", + "name": "Sent to the RFC Editor", + "next_states": [], + "order": 10, + "slug": "rfc-edit", + "type": "draft-stream-editorial", + "used": true + }, + "model": "doc.state", + "pk": 180 + }, { "fields": { "label": "State" @@ -2660,13 +2673,6 @@ "model": "doc.statetype", "pk": "draft" }, - { - "fields": { - "label": "IANA state" - }, - "model": "doc.statetype", - "pk": "draft-iana" - }, { "fields": { "label": "IANA Action state" @@ -11286,8 +11292,8 @@ }, { "fields": { - "desc": "Issuer Tracker", - "name": "Issuer Tracker", + "desc": "Issue Tracker", + "name": "Issue Tracker", "order": 0, "type": "url", "used": true @@ -13368,6 +13374,16 @@ "model": "name.rolename", "pk": "lead" }, + { + "fields": { + "desc": "", + "name": "Lead Maintainer", + "order": 0, + "used": true + }, + "model": "name.rolename", + "pk": "leadmaintainer" + }, { "fields": { "desc": "", @@ -16778,7 +16794,7 @@ "fields": { "command": "xym", "switch": "--version", - "time": "2024-02-21T08:06:28.313Z", + "time": "2024-03-21T07:06:23.405Z", "used": true, "version": "xym 0.7.0" }, @@ -16789,7 +16805,7 @@ "fields": { "command": "pyang", "switch": "--version", - "time": "2024-02-21T08:06:28.663Z", + "time": "2024-03-21T07:06:23.755Z", "used": true, "version": "pyang 2.6.0" }, @@ -16800,7 +16816,7 @@ "fields": { "command": "yanglint", "switch": "--version", - "time": "2024-02-21T08:06:28.685Z", + "time": "2024-03-21T07:06:23.773Z", "used": true, "version": "yanglint SO 1.9.2" }, @@ -16811,9 +16827,9 @@ "fields": { "command": "xml2rfc", "switch": "--version", - "time": "2024-02-21T08:06:29.492Z", + "time": "2024-03-21T07:06:24.609Z", "used": true, - "version": "xml2rfc 3.19.4" + "version": "xml2rfc 3.20.1" }, "model": "utils.versioninfo", "pk": 4 diff --git a/ietf/review/policies.py b/ietf/review/policies.py index 6738db95ff..91398a1b24 100644 --- a/ietf/review/policies.py +++ b/ietf/review/policies.py @@ -131,12 +131,15 @@ def _update_skip_next(self, rotation_pks, assignee_person): assignee_index = rotation_pks.index(assignee_person.pk) skipped = rotation_pks[0:assignee_index] skipped_settings = self.team.reviewersettings_set.filter(person__in=skipped) # list of PKs is valid here + changed = [] for ss in skipped_settings: - ss.skip_next = max(0, ss.skip_next - 1) # ensure we don't go negative - bulk_update_with_history(skipped_settings, + if ss.skip_next > 0: + ss.skip_next = max(0, ss.skip_next - 1) # ensure we don't go negative + ss._change_reason = "Skip count decremented" + changed.append(ss) + bulk_update_with_history(changed, ReviewerSettings, - ['skip_next'], - default_change_reason='skipped') + ['skip_next']) def _assignment_in_order(self, rotation_pks, assignee_person): """Is this an in-order assignment?""" @@ -262,12 +265,15 @@ def _filter_unavailable_reviewers(self, reviewers, review_req=None): def _clear_request_next_assignment(self, person): s = self._reviewer_settings_for(person) - s.request_assignment_next = False - s.save() + if s.request_assignment_next: + s.request_assignment_next = False + s._change_reason = "Clearing request next assignment" + s.save() def _add_skip(self, person): s = self._reviewer_settings_for(person) s.skip_next += 1 + s._change_reason = "Incrementing skip count" s.save() def _reviewer_settings_for(self, person): @@ -484,6 +490,7 @@ def set_wants_to_be_next(self, reviewer_person): # Instead, the "assign me next" flag is set. settings = self._reviewer_settings_for(reviewer_person) settings.request_assignment_next = True + settings._change_reason = "Setting request next assignment" settings.save() def _update_skip_next(self, rotation_pks, assignee_person): @@ -523,20 +530,22 @@ def _update_skip_next(self, rotation_pks, assignee_person): min_skip_next = min([rs.skip_next for rs in rotation_settings.values()]) next_reviewer_index = None + changed = [] for index, pk in enumerate(unfolded_rotation_pks): rs = rotation_settings.get(pk) if (rs is None) or (rs.skip_next == min_skip_next): next_reviewer_index = index break else: - rs.skip_next = max(0, rs.skip_next - 1) # ensure never negative + if rs.skip_next > 0: + rs.skip_next = max(0, rs.skip_next - 1) # ensure never negative + rs._change_reason = "Skip count decremented" + changed.append(rs) log.assertion('next_reviewer_index is not None') # some entry in the list must have the minimum value - - bulk_update_with_history(rotation_settings.values(), + bulk_update_with_history(changed, ReviewerSettings, - ['skip_next'], - default_change_reason='skipped') + ['skip_next']) next_reviewer_pk = unfolded_rotation_pks[next_reviewer_index] NextReviewerInTeam.objects.update_or_create( @@ -578,6 +587,7 @@ def set_wants_to_be_next(self, reviewer_person): # who rejected a review and no further action is needed. settings = self._reviewer_settings_for(reviewer_person) settings.request_assignment_next = True + settings._change_reason = "Setting request next assignment" settings.save() diff --git a/ietf/secr/templates/includes/activities.html b/ietf/secr/templates/includes/activities.html index 3e79c9aed4..1304b7c48d 100644 --- a/ietf/secr/templates/includes/activities.html +++ b/ietf/secr/templates/includes/activities.html @@ -1,4 +1,4 @@ -

Activies Log

+

Activities Log