Merge remote-tracking branch 'upstream/main' into feat/postgres
This commit is contained in:
commit
15569771ff
3
.github/workflows/build.yml
vendored
3
.github/workflows/build.yml
vendored
|
@ -1,4 +1,5 @@
|
|||
name: Build and Release
|
||||
run-name: ${{ github.event.inputs.publish == 'true' && '[Prod]' || '[Dev]' }} Build ${{ github.run_number }} of branch ${{ github.ref_name }} by @${{ github.actor }}
|
||||
|
||||
on:
|
||||
push:
|
||||
|
@ -453,7 +454,7 @@ jobs:
|
|||
npm ci
|
||||
cd ../..
|
||||
echo "Start Deploy..."
|
||||
node ./dev/deploy-to-container/cli.js --branch ${{ github.ref_name }} --domain dev.ietf.org
|
||||
node ./dev/deploy-to-container/cli.js --branch ${{ github.ref_name }} --domain dev.ietf.org --appversion ${{ env.PKG_VERSION }} --commit ${{ github.sha }} --ghrunid ${{ github.run_id }}
|
||||
|
||||
- name: Cleanup old docker resources
|
||||
env:
|
||||
|
|
61
.github/workflows/dev-assets-sync-nightly.yml
vendored
Normal file
61
.github/workflows/dev-assets-sync-nightly.yml
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
# GITHUB ACTIONS - WORKFLOW
|
||||
|
||||
# RSync the assets in the shared assets volume
|
||||
|
||||
name: Nightly Dev Shared Assets Sync
|
||||
|
||||
# Controls when the workflow will run
|
||||
on:
|
||||
# Run every night
|
||||
schedule:
|
||||
- cron: '0 1 * * *'
|
||||
|
||||
# Run on app-rsync-extras.sh changes
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'docker/scripts/app-rsync-extras.sh'
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build Docker Image
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name != 'schedule' }}
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Docker Build & Push
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
context: .
|
||||
file: dev/shared-assets-sync/Dockerfile
|
||||
push: true
|
||||
tags: ghcr.io/ietf-tools/datatracker-rsync-assets:latest
|
||||
|
||||
sync:
|
||||
name: Run assets rsync
|
||||
if: ${{ always() }}
|
||||
runs-on: dev-server
|
||||
needs: [build]
|
||||
steps:
|
||||
- name: Run rsync
|
||||
env:
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
run: |
|
||||
docker pull ghcr.io/ietf-tools/datatracker-rsync-assets:latest
|
||||
docker run --rm -v dt-assets:/assets ghcr.io/ietf-tools/datatracker-rsync-assets:latest
|
||||
docker image prune -a -f
|
177
.pnp.cjs
generated
177
.pnp.cjs
generated
|
@ -42,6 +42,8 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["@fullcalendar/luxon2", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.11.3"],\
|
||||
["@fullcalendar/timegrid", "npm:5.11.3"],\
|
||||
["@fullcalendar/vue3", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.11.3"],\
|
||||
["@parcel/optimizer-data-url", "npm:2.8.0"],\
|
||||
["@parcel/transformer-inline-string", "npm:2.8.0"],\
|
||||
["@parcel/transformer-sass", "npm:2.8.0"],\
|
||||
["@popperjs/core", "npm:2.11.6"],\
|
||||
["@rollup/pluginutils", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.0.2"],\
|
||||
|
@ -52,7 +54,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["browser-fs-access", "npm:0.31.1"],\
|
||||
["browserlist", "npm:1.0.1"],\
|
||||
["c8", "npm:7.12.0"],\
|
||||
["caniuse-lite", "npm:1.0.30001434"],\
|
||||
["caniuse-lite", "npm:1.0.30001435"],\
|
||||
["d3", "npm:7.6.1"],\
|
||||
["eslint", "npm:8.28.0"],\
|
||||
["eslint-config-standard", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:17.0.0"],\
|
||||
|
@ -63,7 +65,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["eslint-plugin-promise", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.1"],\
|
||||
["eslint-plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:9.8.0"],\
|
||||
["file-saver", "npm:2.0.5"],\
|
||||
["highcharts", "npm:10.3.1"],\
|
||||
["highcharts", "npm:10.3.2"],\
|
||||
["html-validate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:7.10.0"],\
|
||||
["jquery", "npm:3.6.1"],\
|
||||
["jquery-migrate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:3.4.0"],\
|
||||
|
@ -72,14 +74,14 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["list.js", "npm:2.3.1"],\
|
||||
["lodash", "npm:4.17.21"],\
|
||||
["lodash-es", "npm:4.17.21"],\
|
||||
["luxon", "npm:3.1.0"],\
|
||||
["luxon", "npm:3.1.1"],\
|
||||
["moment", "npm:2.29.4"],\
|
||||
["moment-timezone", "npm:0.5.39"],\
|
||||
["ms", "npm:2.1.3"],\
|
||||
["murmurhash-js", "npm:1.0.0"],\
|
||||
["naive-ui", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.34.2"],\
|
||||
["parcel", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.8.0"],\
|
||||
["pinia", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.0.26"],\
|
||||
["pinia", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.0.27"],\
|
||||
["pinia-plugin-persist", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:1.0.0"],\
|
||||
["pug", "npm:3.0.2"],\
|
||||
["sass", "npm:1.56.1"],\
|
||||
|
@ -337,7 +339,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["@fullcalendar/luxon2", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.11.3"],\
|
||||
["@fullcalendar/common", "npm:5.11.3"],\
|
||||
["@types/luxon", null],\
|
||||
["luxon", "npm:3.1.0"],\
|
||||
["luxon", "npm:3.1.1"],\
|
||||
["tslib", "npm:2.4.0"]\
|
||||
],\
|
||||
"packagePeers": [\
|
||||
|
@ -1130,12 +1132,25 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["@parcel/source-map", "npm:2.1.1"],\
|
||||
["@parcel/utils", "npm:2.8.0"],\
|
||||
["browserslist", "npm:4.20.3"],\
|
||||
["lightningcss", "npm:1.16.1"],\
|
||||
["lightningcss", "npm:1.17.1"],\
|
||||
["nullthrows", "npm:1.1.1"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@parcel/optimizer-data-url", [\
|
||||
["npm:2.8.0", {\
|
||||
"packageLocation": "./.yarn/cache/@parcel-optimizer-data-url-npm-2.8.0-89a39d906e-998fb94cee.zip/node_modules/@parcel/optimizer-data-url/",\
|
||||
"packageDependencies": [\
|
||||
["@parcel/optimizer-data-url", "npm:2.8.0"],\
|
||||
["@parcel/plugin", "npm:2.8.0"],\
|
||||
["@parcel/utils", "npm:2.8.0"],\
|
||||
["isbinaryfile", "npm:4.0.10"],\
|
||||
["mime", "npm:2.6.0"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@parcel/optimizer-htmlnano", [\
|
||||
["npm:2.8.0", {\
|
||||
"packageLocation": "./.yarn/cache/@parcel-optimizer-htmlnano-npm-2.8.0-d2ead43d0c-68010e586b.zip/node_modules/@parcel/optimizer-htmlnano/",\
|
||||
|
@ -1480,7 +1495,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["@parcel/source-map", "npm:2.1.1"],\
|
||||
["@parcel/utils", "npm:2.8.0"],\
|
||||
["browserslist", "npm:4.20.3"],\
|
||||
["lightningcss", "npm:1.16.1"],\
|
||||
["lightningcss", "npm:1.17.1"],\
|
||||
["nullthrows", "npm:1.1.1"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
|
@ -1529,6 +1544,16 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@parcel/transformer-inline-string", [\
|
||||
["npm:2.8.0", {\
|
||||
"packageLocation": "./.yarn/cache/@parcel-transformer-inline-string-npm-2.8.0-5fce2c90b8-e40616c55b.zip/node_modules/@parcel/transformer-inline-string/",\
|
||||
"packageDependencies": [\
|
||||
["@parcel/transformer-inline-string", "npm:2.8.0"],\
|
||||
["@parcel/plugin", "npm:2.8.0"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["@parcel/transformer-js", [\
|
||||
["npm:2.8.0", {\
|
||||
"packageLocation": "./.yarn/unplugged/@parcel-transformer-js-virtual-0a5c0b53bd/node_modules/@parcel/transformer-js/",\
|
||||
|
@ -2690,10 +2715,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:1.0.30001434", {\
|
||||
"packageLocation": "./.yarn/cache/caniuse-lite-npm-1.0.30001434-9c6ea57daf-7c9d2641e8.zip/node_modules/caniuse-lite/",\
|
||||
["npm:1.0.30001435", {\
|
||||
"packageLocation": "./.yarn/cache/caniuse-lite-npm-1.0.30001435-7cebb35f0a-ec88b9c37f.zip/node_modules/caniuse-lite/",\
|
||||
"packageDependencies": [\
|
||||
["caniuse-lite", "npm:1.0.30001434"]\
|
||||
["caniuse-lite", "npm:1.0.30001435"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
|
@ -4910,10 +4935,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
}]\
|
||||
]],\
|
||||
["highcharts", [\
|
||||
["npm:10.3.1", {\
|
||||
"packageLocation": "./.yarn/cache/highcharts-npm-10.3.1-e67a887ff6-8a1cf9a363.zip/node_modules/highcharts/",\
|
||||
["npm:10.3.2", {\
|
||||
"packageLocation": "./.yarn/cache/highcharts-npm-10.3.2-1672942f09-43cb42b24c.zip/node_modules/highcharts/",\
|
||||
"packageDependencies": [\
|
||||
["highcharts", "npm:10.3.1"]\
|
||||
["highcharts", "npm:10.3.2"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
|
@ -5456,6 +5481,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["isbinaryfile", [\
|
||||
["npm:4.0.10", {\
|
||||
"packageLocation": "./.yarn/cache/isbinaryfile-npm-4.0.10-91d1251522-a6b28db7e2.zip/node_modules/isbinaryfile/",\
|
||||
"packageDependencies": [\
|
||||
["isbinaryfile", "npm:4.0.10"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["isexe", [\
|
||||
["npm:2.0.0", {\
|
||||
"packageLocation": "./.yarn/cache/isexe-npm-2.0.0-b58870bd2e-26bf6c5480.zip/node_modules/isexe/",\
|
||||
|
@ -5716,91 +5750,91 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
}]\
|
||||
]],\
|
||||
["lightningcss", [\
|
||||
["npm:1.16.1", {\
|
||||
"packageLocation": "./.yarn/cache/lightningcss-npm-1.16.1-dc51de6ab1-78ec1fa158.zip/node_modules/lightningcss/",\
|
||||
["npm:1.17.1", {\
|
||||
"packageLocation": "./.yarn/cache/lightningcss-npm-1.17.1-7428f2d516-0bf9d5c932.zip/node_modules/lightningcss/",\
|
||||
"packageDependencies": [\
|
||||
["lightningcss", "npm:1.16.1"],\
|
||||
["lightningcss", "npm:1.17.1"],\
|
||||
["detect-libc", "npm:1.0.3"],\
|
||||
["lightningcss-darwin-arm64", "npm:1.16.1"],\
|
||||
["lightningcss-darwin-x64", "npm:1.16.1"],\
|
||||
["lightningcss-linux-arm-gnueabihf", "npm:1.16.1"],\
|
||||
["lightningcss-linux-arm64-gnu", "npm:1.16.1"],\
|
||||
["lightningcss-linux-arm64-musl", "npm:1.16.1"],\
|
||||
["lightningcss-linux-x64-gnu", "npm:1.16.1"],\
|
||||
["lightningcss-linux-x64-musl", "npm:1.16.1"],\
|
||||
["lightningcss-win32-x64-msvc", "npm:1.16.1"]\
|
||||
["lightningcss-darwin-arm64", "npm:1.17.1"],\
|
||||
["lightningcss-darwin-x64", "npm:1.17.1"],\
|
||||
["lightningcss-linux-arm-gnueabihf", "npm:1.17.1"],\
|
||||
["lightningcss-linux-arm64-gnu", "npm:1.17.1"],\
|
||||
["lightningcss-linux-arm64-musl", "npm:1.17.1"],\
|
||||
["lightningcss-linux-x64-gnu", "npm:1.17.1"],\
|
||||
["lightningcss-linux-x64-musl", "npm:1.17.1"],\
|
||||
["lightningcss-win32-x64-msvc", "npm:1.17.1"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["lightningcss-darwin-arm64", [\
|
||||
["npm:1.16.1", {\
|
||||
"packageLocation": "./.yarn/unplugged/lightningcss-darwin-arm64-npm-1.16.1-0a412810bd/node_modules/lightningcss-darwin-arm64/",\
|
||||
["npm:1.17.1", {\
|
||||
"packageLocation": "./.yarn/unplugged/lightningcss-darwin-arm64-npm-1.17.1-a84f0d052c/node_modules/lightningcss-darwin-arm64/",\
|
||||
"packageDependencies": [\
|
||||
["lightningcss-darwin-arm64", "npm:1.16.1"]\
|
||||
["lightningcss-darwin-arm64", "npm:1.17.1"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["lightningcss-darwin-x64", [\
|
||||
["npm:1.16.1", {\
|
||||
"packageLocation": "./.yarn/unplugged/lightningcss-darwin-x64-npm-1.16.1-3f7b1b3519/node_modules/lightningcss-darwin-x64/",\
|
||||
["npm:1.17.1", {\
|
||||
"packageLocation": "./.yarn/unplugged/lightningcss-darwin-x64-npm-1.17.1-131957b733/node_modules/lightningcss-darwin-x64/",\
|
||||
"packageDependencies": [\
|
||||
["lightningcss-darwin-x64", "npm:1.16.1"]\
|
||||
["lightningcss-darwin-x64", "npm:1.17.1"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["lightningcss-linux-arm-gnueabihf", [\
|
||||
["npm:1.16.1", {\
|
||||
"packageLocation": "./.yarn/unplugged/lightningcss-linux-arm-gnueabihf-npm-1.16.1-628363ec64/node_modules/lightningcss-linux-arm-gnueabihf/",\
|
||||
["npm:1.17.1", {\
|
||||
"packageLocation": "./.yarn/unplugged/lightningcss-linux-arm-gnueabihf-npm-1.17.1-bbf7f4f213/node_modules/lightningcss-linux-arm-gnueabihf/",\
|
||||
"packageDependencies": [\
|
||||
["lightningcss-linux-arm-gnueabihf", "npm:1.16.1"]\
|
||||
["lightningcss-linux-arm-gnueabihf", "npm:1.17.1"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["lightningcss-linux-arm64-gnu", [\
|
||||
["npm:1.16.1", {\
|
||||
"packageLocation": "./.yarn/unplugged/lightningcss-linux-arm64-gnu-npm-1.16.1-3ca4dc231b/node_modules/lightningcss-linux-arm64-gnu/",\
|
||||
["npm:1.17.1", {\
|
||||
"packageLocation": "./.yarn/unplugged/lightningcss-linux-arm64-gnu-npm-1.17.1-5b0e0aecb4/node_modules/lightningcss-linux-arm64-gnu/",\
|
||||
"packageDependencies": [\
|
||||
["lightningcss-linux-arm64-gnu", "npm:1.16.1"]\
|
||||
["lightningcss-linux-arm64-gnu", "npm:1.17.1"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["lightningcss-linux-arm64-musl", [\
|
||||
["npm:1.16.1", {\
|
||||
"packageLocation": "./.yarn/unplugged/lightningcss-linux-arm64-musl-npm-1.16.1-94c93845ed/node_modules/lightningcss-linux-arm64-musl/",\
|
||||
["npm:1.17.1", {\
|
||||
"packageLocation": "./.yarn/unplugged/lightningcss-linux-arm64-musl-npm-1.17.1-4da73a58bf/node_modules/lightningcss-linux-arm64-musl/",\
|
||||
"packageDependencies": [\
|
||||
["lightningcss-linux-arm64-musl", "npm:1.16.1"]\
|
||||
["lightningcss-linux-arm64-musl", "npm:1.17.1"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["lightningcss-linux-x64-gnu", [\
|
||||
["npm:1.16.1", {\
|
||||
"packageLocation": "./.yarn/unplugged/lightningcss-linux-x64-gnu-npm-1.16.1-04529113fe/node_modules/lightningcss-linux-x64-gnu/",\
|
||||
["npm:1.17.1", {\
|
||||
"packageLocation": "./.yarn/unplugged/lightningcss-linux-x64-gnu-npm-1.17.1-39d6988913/node_modules/lightningcss-linux-x64-gnu/",\
|
||||
"packageDependencies": [\
|
||||
["lightningcss-linux-x64-gnu", "npm:1.16.1"]\
|
||||
["lightningcss-linux-x64-gnu", "npm:1.17.1"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["lightningcss-linux-x64-musl", [\
|
||||
["npm:1.16.1", {\
|
||||
"packageLocation": "./.yarn/unplugged/lightningcss-linux-x64-musl-npm-1.16.1-01c07ec3c0/node_modules/lightningcss-linux-x64-musl/",\
|
||||
["npm:1.17.1", {\
|
||||
"packageLocation": "./.yarn/unplugged/lightningcss-linux-x64-musl-npm-1.17.1-84311b8bf8/node_modules/lightningcss-linux-x64-musl/",\
|
||||
"packageDependencies": [\
|
||||
["lightningcss-linux-x64-musl", "npm:1.16.1"]\
|
||||
["lightningcss-linux-x64-musl", "npm:1.17.1"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["lightningcss-win32-x64-msvc", [\
|
||||
["npm:1.16.1", {\
|
||||
"packageLocation": "./.yarn/unplugged/lightningcss-win32-x64-msvc-npm-1.16.1-40af4d14b2/node_modules/lightningcss-win32-x64-msvc/",\
|
||||
["npm:1.17.1", {\
|
||||
"packageLocation": "./.yarn/unplugged/lightningcss-win32-x64-msvc-npm-1.17.1-849d8d151b/node_modules/lightningcss-win32-x64-msvc/",\
|
||||
"packageDependencies": [\
|
||||
["lightningcss-win32-x64-msvc", "npm:1.16.1"]\
|
||||
["lightningcss-win32-x64-msvc", "npm:1.17.1"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
|
@ -5918,10 +5952,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
}]\
|
||||
]],\
|
||||
["luxon", [\
|
||||
["npm:3.1.0", {\
|
||||
"packageLocation": "./.yarn/cache/luxon-npm-3.1.0-16e2508500-f8a850b759.zip/node_modules/luxon/",\
|
||||
["npm:3.1.1", {\
|
||||
"packageLocation": "./.yarn/cache/luxon-npm-3.1.1-64fe977c1d-388fb35d3c.zip/node_modules/luxon/",\
|
||||
"packageDependencies": [\
|
||||
["luxon", "npm:3.1.0"]\
|
||||
["luxon", "npm:3.1.1"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
|
@ -5987,6 +6021,13 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["mime", "npm:1.6.0"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}],\
|
||||
["npm:2.6.0", {\
|
||||
"packageLocation": "./.yarn/cache/mime-npm-2.6.0-88b89d8de0-1497ba7b9f.zip/node_modules/mime/",\
|
||||
"packageDependencies": [\
|
||||
["mime", "npm:2.6.0"]\
|
||||
],\
|
||||
"linkType": "HARD"\
|
||||
}]\
|
||||
]],\
|
||||
["minimatch", [\
|
||||
|
@ -6659,17 +6700,17 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
}]\
|
||||
]],\
|
||||
["pinia", [\
|
||||
["npm:2.0.26", {\
|
||||
"packageLocation": "./.yarn/cache/pinia-npm-2.0.26-0d96417fac-0d38cc0efc.zip/node_modules/pinia/",\
|
||||
["npm:2.0.27", {\
|
||||
"packageLocation": "./.yarn/cache/pinia-npm-2.0.27-3e0154e702-29c862ea43.zip/node_modules/pinia/",\
|
||||
"packageDependencies": [\
|
||||
["pinia", "npm:2.0.26"]\
|
||||
["pinia", "npm:2.0.27"]\
|
||||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.0.26", {\
|
||||
"packageLocation": "./.yarn/__virtual__/pinia-virtual-3c74e5a139/0/cache/pinia-npm-2.0.26-0d96417fac-0d38cc0efc.zip/node_modules/pinia/",\
|
||||
["virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.0.27", {\
|
||||
"packageLocation": "./.yarn/__virtual__/pinia-virtual-0b7bfddb52/0/cache/pinia-npm-2.0.27-3e0154e702-29c862ea43.zip/node_modules/pinia/",\
|
||||
"packageDependencies": [\
|
||||
["pinia", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.0.26"],\
|
||||
["pinia", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.0.27"],\
|
||||
["@types/typescript", null],\
|
||||
["@types/vue", null],\
|
||||
["@types/vue__composition-api", null],\
|
||||
|
@ -6677,7 +6718,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["@vue/devtools-api", "npm:6.4.5"],\
|
||||
["typescript", null],\
|
||||
["vue", "npm:3.2.45"],\
|
||||
["vue-demi", "virtual:3c74e5a1392a9d26efc27d5867a5220b1ab24b8bfb7c76fe2dac826f7e9d478b9c8eb69cc87331bb2ba20521466999017a02e9dca572946a787e2b4314602fca#npm:0.13.1"]\
|
||||
["vue-demi", "virtual:0b7bfddb52b3cb488814806546397e52c62caef1815758033c8eac7ce386779ac52132e251ad567a19dde858cd2ed318ab2b52e9e258efd261b951e0d2160c16#npm:0.13.1"]\
|
||||
],\
|
||||
"packagePeers": [\
|
||||
"@types/typescript",\
|
||||
|
@ -6706,7 +6747,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["@types/vue", null],\
|
||||
["@types/vue__composition-api", null],\
|
||||
["@vue/composition-api", null],\
|
||||
["pinia", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.0.26"],\
|
||||
["pinia", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.0.27"],\
|
||||
["vue", "npm:3.2.45"],\
|
||||
["vue-demi", "virtual:f56fcf19bbebc2ada1b28955da8cc216b1e9a569a1a7337d2d1926c1ebd1bc7a5bd91aedae1d05c15c8562f33caf7c59bd3020a667340f6bdc6a7b13fc2ba847#npm:0.12.5"]\
|
||||
],\
|
||||
|
@ -7232,6 +7273,8 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["@fullcalendar/luxon2", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.11.3"],\
|
||||
["@fullcalendar/timegrid", "npm:5.11.3"],\
|
||||
["@fullcalendar/vue3", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.11.3"],\
|
||||
["@parcel/optimizer-data-url", "npm:2.8.0"],\
|
||||
["@parcel/transformer-inline-string", "npm:2.8.0"],\
|
||||
["@parcel/transformer-sass", "npm:2.8.0"],\
|
||||
["@popperjs/core", "npm:2.11.6"],\
|
||||
["@rollup/pluginutils", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:5.0.2"],\
|
||||
|
@ -7242,7 +7285,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["browser-fs-access", "npm:0.31.1"],\
|
||||
["browserlist", "npm:1.0.1"],\
|
||||
["c8", "npm:7.12.0"],\
|
||||
["caniuse-lite", "npm:1.0.30001434"],\
|
||||
["caniuse-lite", "npm:1.0.30001435"],\
|
||||
["d3", "npm:7.6.1"],\
|
||||
["eslint", "npm:8.28.0"],\
|
||||
["eslint-config-standard", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:17.0.0"],\
|
||||
|
@ -7253,7 +7296,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["eslint-plugin-promise", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.1"],\
|
||||
["eslint-plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:9.8.0"],\
|
||||
["file-saver", "npm:2.0.5"],\
|
||||
["highcharts", "npm:10.3.1"],\
|
||||
["highcharts", "npm:10.3.2"],\
|
||||
["html-validate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:7.10.0"],\
|
||||
["jquery", "npm:3.6.1"],\
|
||||
["jquery-migrate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:3.4.0"],\
|
||||
|
@ -7262,14 +7305,14 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
["list.js", "npm:2.3.1"],\
|
||||
["lodash", "npm:4.17.21"],\
|
||||
["lodash-es", "npm:4.17.21"],\
|
||||
["luxon", "npm:3.1.0"],\
|
||||
["luxon", "npm:3.1.1"],\
|
||||
["moment", "npm:2.29.4"],\
|
||||
["moment-timezone", "npm:0.5.39"],\
|
||||
["ms", "npm:2.1.3"],\
|
||||
["murmurhash-js", "npm:1.0.0"],\
|
||||
["naive-ui", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.34.2"],\
|
||||
["parcel", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.8.0"],\
|
||||
["pinia", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.0.26"],\
|
||||
["pinia", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.0.27"],\
|
||||
["pinia-plugin-persist", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:1.0.0"],\
|
||||
["pug", "npm:3.0.2"],\
|
||||
["sass", "npm:1.56.1"],\
|
||||
|
@ -8159,16 +8202,16 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
|||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["npm:0.13.1", {\
|
||||
"packageLocation": "./.yarn/unplugged/vue-demi-virtual-cfef5ecd67/node_modules/vue-demi/",\
|
||||
"packageLocation": "./.yarn/unplugged/vue-demi-virtual-615072ef29/node_modules/vue-demi/",\
|
||||
"packageDependencies": [\
|
||||
["vue-demi", "npm:0.13.1"]\
|
||||
],\
|
||||
"linkType": "SOFT"\
|
||||
}],\
|
||||
["virtual:3c74e5a1392a9d26efc27d5867a5220b1ab24b8bfb7c76fe2dac826f7e9d478b9c8eb69cc87331bb2ba20521466999017a02e9dca572946a787e2b4314602fca#npm:0.13.1", {\
|
||||
"packageLocation": "./.yarn/unplugged/vue-demi-virtual-cfef5ecd67/node_modules/vue-demi/",\
|
||||
["virtual:0b7bfddb52b3cb488814806546397e52c62caef1815758033c8eac7ce386779ac52132e251ad567a19dde858cd2ed318ab2b52e9e258efd261b951e0d2160c16#npm:0.13.1", {\
|
||||
"packageLocation": "./.yarn/unplugged/vue-demi-virtual-615072ef29/node_modules/vue-demi/",\
|
||||
"packageDependencies": [\
|
||||
["vue-demi", "virtual:3c74e5a1392a9d26efc27d5867a5220b1ab24b8bfb7c76fe2dac826f7e9d478b9c8eb69cc87331bb2ba20521466999017a02e9dca572946a787e2b4314602fca#npm:0.13.1"],\
|
||||
["vue-demi", "virtual:0b7bfddb52b3cb488814806546397e52c62caef1815758033c8eac7ce386779ac52132e251ad567a19dde858cd2ed318ab2b52e9e258efd261b951e0d2160c16#npm:0.13.1"],\
|
||||
["@types/vue", null],\
|
||||
["@types/vue__composition-api", null],\
|
||||
["@vue/composition-api", null],\
|
||||
|
|
BIN
.yarn/cache/@parcel-optimizer-data-url-npm-2.8.0-89a39d906e-998fb94cee.zip
vendored
Normal file
BIN
.yarn/cache/@parcel-optimizer-data-url-npm-2.8.0-89a39d906e-998fb94cee.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@parcel-transformer-inline-string-npm-2.8.0-5fce2c90b8-e40616c55b.zip
vendored
Normal file
BIN
.yarn/cache/@parcel-transformer-inline-string-npm-2.8.0-5fce2c90b8-e40616c55b.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/caniuse-lite-npm-1.0.30001435-7cebb35f0a-ec88b9c37f.zip
vendored
Normal file
BIN
.yarn/cache/caniuse-lite-npm-1.0.30001435-7cebb35f0a-ec88b9c37f.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/isbinaryfile-npm-4.0.10-91d1251522-a6b28db7e2.zip
vendored
Normal file
BIN
.yarn/cache/isbinaryfile-npm-4.0.10-91d1251522-a6b28db7e2.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/lightningcss-darwin-arm64-npm-1.17.1-a84f0d052c-8.zip
vendored
Normal file
BIN
.yarn/cache/lightningcss-darwin-arm64-npm-1.17.1-a84f0d052c-8.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/lightningcss-darwin-x64-npm-1.17.1-131957b733-8.zip
vendored
Normal file
BIN
.yarn/cache/lightningcss-darwin-x64-npm-1.17.1-131957b733-8.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/lightningcss-linux-arm64-gnu-npm-1.17.1-5b0e0aecb4-8.zip
vendored
Normal file
BIN
.yarn/cache/lightningcss-linux-arm64-gnu-npm-1.17.1-5b0e0aecb4-8.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/lightningcss-linux-x64-gnu-npm-1.17.1-39d6988913-8.zip
vendored
Normal file
BIN
.yarn/cache/lightningcss-linux-x64-gnu-npm-1.17.1-39d6988913-8.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/lightningcss-win32-x64-msvc-npm-1.17.1-849d8d151b-8.zip
vendored
Normal file
BIN
.yarn/cache/lightningcss-win32-x64-msvc-npm-1.17.1-849d8d151b-8.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/luxon-npm-3.1.1-64fe977c1d-388fb35d3c.zip
vendored
Normal file
BIN
.yarn/cache/luxon-npm-3.1.1-64fe977c1d-388fb35d3c.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/mime-npm-2.6.0-88b89d8de0-1497ba7b9f.zip
vendored
Normal file
BIN
.yarn/cache/mime-npm-2.6.0-88b89d8de0-1497ba7b9f.zip
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/pinia-npm-2.0.27-3e0154e702-29c862ea43.zip
vendored
Normal file
BIN
.yarn/cache/pinia-npm-2.0.27-3e0154e702-29c862ea43.zip
vendored
Normal file
Binary file not shown.
|
@ -235,6 +235,12 @@ async function main () {
|
|||
`VIRTUAL_HOST=${hostname}`,
|
||||
`VIRTUAL_PORT=8000`
|
||||
],
|
||||
Labels: {
|
||||
appversion: `${argv.appversion}` ?? '0.0.0',
|
||||
commit: `${argv.commit}` ?? 'unknown',
|
||||
ghrunid: `${argv.ghrunid}` ?? '0',
|
||||
hostname
|
||||
},
|
||||
HostConfig: {
|
||||
Binds: [
|
||||
'dt-assets:/assets'
|
||||
|
|
9
dev/shared-assets-sync/Dockerfile
Normal file
9
dev/shared-assets-sync/Dockerfile
Normal file
|
@ -0,0 +1,9 @@
|
|||
FROM alpine:3
|
||||
|
||||
RUN apk add --no-cache wget rsync
|
||||
COPY docker/scripts/app-rsync-extras.sh /workspace/app-rsync-extras.sh
|
||||
RUN chmod +x /workspace/app-rsync-extras.sh
|
||||
|
||||
WORKDIR /workspace
|
||||
|
||||
CMD ["sh", "app-rsync-extras.sh"]
|
26
dev/tests/debug.sh
Normal file
26
dev/tests/debug.sh
Normal file
|
@ -0,0 +1,26 @@
|
|||
#!/bin/bash
|
||||
|
||||
# This script recreate the same environment used during tests on GitHub Actions
|
||||
# and drops you into a terminal at the point where the actual tests would be run.
|
||||
#
|
||||
# Refer to https://github.com/ietf-tools/datatracker/blob/main/.github/workflows/build.yml#L141-L155
|
||||
# for the commands to run next.
|
||||
#
|
||||
# Simply type "exit" + ENTER to exit and shutdown this test environment.
|
||||
|
||||
echo "Fetching latest images..."
|
||||
docker pull ghcr.io/ietf-tools/datatracker-app-base:latest
|
||||
docker pull ghcr.io/ietf-tools/datatracker-db:latest
|
||||
echo "Starting containers..."
|
||||
docker compose -f docker-compose.debug.yml -p dtdebug up -d
|
||||
echo "Copying working directory into container..."
|
||||
docker compose -p dtdebug cp ../../. app:/__w/datatracker/datatracker/
|
||||
echo "Run prepare script..."
|
||||
docker compose -p dtdebug exec app chmod +x ./dev/tests/prepare.sh
|
||||
docker compose -p dtdebug exec app sh ./dev/tests/prepare.sh
|
||||
docker compose -p dtdebug exec app /usr/local/bin/wait-for db:3306 -- echo "DB ready"
|
||||
echo "================================================================="
|
||||
echo "Launching zsh terminal:"
|
||||
docker compose -p dtdebug exec app /bin/zsh
|
||||
echo "Shutting down containers..."
|
||||
docker compose -p dtdebug down -v
|
33
dev/tests/docker-compose.debug.yml
Normal file
33
dev/tests/docker-compose.debug.yml
Normal file
|
@ -0,0 +1,33 @@
|
|||
# This docker-compose replicates the test workflow happening on GitHub during a PR / build check.
|
||||
# To be used from the debug.sh script.
|
||||
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
app:
|
||||
image: ghcr.io/ietf-tools/datatracker-app-base:latest
|
||||
command: -f /dev/null
|
||||
working_dir: /__w/datatracker/datatracker
|
||||
entrypoint: tail
|
||||
hostname: app
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
environment:
|
||||
CI: 'true'
|
||||
GITHUB_ACTIONS: 'true'
|
||||
HOME: /github/home
|
||||
db:
|
||||
image: ghcr.io/ietf-tools/datatracker-db:latest
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- mariadb-data:/var/lib/mysql
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: RkTkDPFnKpko
|
||||
MYSQL_DATABASE: ietf_utf8
|
||||
MYSQL_USER: django
|
||||
MYSQL_PASSWORD: RkTkDPFnKpko
|
||||
CI: 'true'
|
||||
GITHUB_ACTIONS: 'true'
|
||||
|
||||
volumes:
|
||||
mariadb-data:
|
|
@ -54,7 +54,7 @@ SUBMIT_YANG_RFC_MODEL_DIR = '/assets/ietf-ftp/yang/rfcmod/'
|
|||
# Set INTERNAL_IPS for use within Docker. See https://knasmueller.net/fix-djangos-debug-toolbar-not-showing-inside-docker
|
||||
import socket
|
||||
hostname, _, ips = socket.gethostbyname_ex(socket.gethostname())
|
||||
INTERNAL_IPS = [".".join(ip.split(".")[:-1] + ["1"]) for ip in ips]
|
||||
INTERNAL_IPS = [".".join(ip.split(".")[:-1] + ["1"]) for ip in ips] + ['127.0.0.1']
|
||||
|
||||
# DEV_TEMPLATE_CONTEXT_PROCESSORS = [
|
||||
# 'ietf.context_processors.sql_debug',
|
||||
|
|
|
@ -42,7 +42,6 @@ cat << EOF > "$EXCLUDE"
|
|||
*.diff
|
||||
*.doc
|
||||
*.exe
|
||||
*.html
|
||||
*.mib
|
||||
*.new
|
||||
*.p7s
|
||||
|
|
|
@ -80,7 +80,7 @@ class PersonalInformationExportView(DetailView, JsonExportMixin):
|
|||
person = get_object_or_404(self.model, user=request.user)
|
||||
expand = ['searchrule', 'documentauthor', 'ad_document_set', 'ad_dochistory_set', 'docevent',
|
||||
'ballotpositiondocevent', 'deletedevent', 'email_set', 'groupevent', 'role', 'rolehistory', 'iprdisclosurebase',
|
||||
'iprevent', 'liaisonstatementevent', 'whitelisted', 'schedule', 'constraint', 'schedulingevent', 'message',
|
||||
'iprevent', 'liaisonstatementevent', 'allowlisted', 'schedule', 'constraint', 'schedulingevent', 'message',
|
||||
'sendqueue', 'nominee', 'topicfeedbacklastseen', 'alias', 'email', 'apikeys', 'personevent',
|
||||
'reviewersettings', 'reviewsecretarysettings', 'unavailableperiod', 'reviewwish',
|
||||
'nextreviewerinteam', 'reviewrequest', 'meetingregistration', 'submissionevent', 'preapproval',
|
||||
|
|
|
@ -166,7 +166,7 @@ Thank you,</field>
|
|||
Thank you for accepting your nomination for the position of $position.
|
||||
|
||||
Please remember to complete and return the questionnaire for this position at your earliest opportunity.
|
||||
The questionaire is repeated below for your convenience.
|
||||
The questionnaire is repeated below for your convenience.
|
||||
|
||||
--------</field>
|
||||
<field to="group.group" name="group" rel="ManyToOneRel"><None></None></field>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<dd>{{ template.type.name }}
|
||||
{% if template.type.slug == "rst" %}
|
||||
<p class="help-block">This template uses the syntax of reStructuredText. Get a quick reference at <a href="http://docutils.sourceforge.net/docs/user/rst/quickref.html">http://docutils.sourceforge.net/docs/user/rst/quickref.html</a>.</p>
|
||||
<p class="help-block">You can do variable interpolation with $varialbe if the template allows any variable.</p>
|
||||
<p class="help-block">You can do variable interpolation with $variable if the template allows any variable.</p>
|
||||
{% endif %}
|
||||
{% if template.type.slug == "django" %}
|
||||
<p class="help-block">This template uses the syntax of the default django template framework. Get more info at <a href="https://docs.djangoproject.com/en/dev/topics/templates/">https://docs.djangoproject.com/en/dev/topics/templates/</a>.</p>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<dd>{{ template.type.name }}
|
||||
{% if template.type.slug == "rst" %}
|
||||
<p class="help-block">This template uses the syntax of reStructuredText. Get a quick reference at <a href="http://docutils.sourceforge.net/docs/user/rst/quickref.html">http://docutils.sourceforge.net/docs/user/rst/quickref.html</a>.</p>
|
||||
<p class="help-block">You can do variable interpolation with $varialbe if the template allows any variable.</p>
|
||||
<p class="help-block">You can do variable interpolation with $variable if the template allows any variable.</p>
|
||||
{% endif %}
|
||||
{% if template.type.slug == "django" %}
|
||||
<p class="help-block">This template uses the syntax of the default django template framework. Get more info at <a href="https://docs.djangoproject.com/en/dev/topics/templates/">https://docs.djangoproject.com/en/dev/topics/templates/</a>.</p>
|
||||
|
|
|
@ -75,7 +75,13 @@ class AdForm(forms.Form):
|
|||
self.fields['ad'].choices = list(choices) + [("", "-------"), (ad_pk, Person.objects.get(pk=ad_pk).plain_name())]
|
||||
|
||||
class NotifyForm(forms.Form):
|
||||
notify = forms.CharField(max_length=255, help_text="List of email addresses to receive state notifications, separated by comma.", label="Notification list", required=False)
|
||||
notify = forms.CharField(
|
||||
widget=forms.Textarea,
|
||||
max_length=1023,
|
||||
help_text="List of email addresses to receive state notifications, separated by comma.",
|
||||
label="Notification list",
|
||||
required=False,
|
||||
)
|
||||
|
||||
def clean_notify(self):
|
||||
addrspecs = [x.strip() for x in self.cleaned_data["notify"].split(',')]
|
||||
|
|
23
ietf/doc/migrations/0048_send_notices.py
Normal file
23
ietf/doc/migrations/0048_send_notices.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 2.2.28 on 2022-12-05 17:53
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('doc', '0047_tzaware_deletedevents'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='dochistory',
|
||||
name='notify',
|
||||
field=models.TextField(blank=True, max_length=1023),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='document',
|
||||
name='notify',
|
||||
field=models.TextField(blank=True, max_length=1023),
|
||||
),
|
||||
]
|
|
@ -8,6 +8,8 @@ import io
|
|||
import os
|
||||
import rfc2html
|
||||
|
||||
from pathlib import Path
|
||||
from lxml import etree
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
from weasyprint import HTML as wpHTML
|
||||
|
||||
|
@ -21,6 +23,7 @@ from django.conf import settings
|
|||
from django.utils import timezone
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.html import mark_safe # type:ignore
|
||||
from django.contrib.staticfiles import finders
|
||||
|
||||
import debug # pyflakes:ignore
|
||||
|
||||
|
@ -108,7 +111,7 @@ class DocumentInfo(models.Model):
|
|||
ad = ForeignKey(Person, verbose_name="area director", related_name='ad_%(class)s_set', blank=True, null=True)
|
||||
shepherd = ForeignKey(Email, related_name='shepherd_%(class)s_set', blank=True, null=True)
|
||||
expires = models.DateTimeField(blank=True, null=True)
|
||||
notify = models.CharField(max_length=255, blank=True)
|
||||
notify = models.TextField(max_length=1023, blank=True)
|
||||
external_url = models.URLField(blank=True)
|
||||
uploaded_filename = models.TextField(blank=True)
|
||||
note = models.TextField(blank=True)
|
||||
|
@ -541,6 +544,49 @@ class DocumentInfo(models.Model):
|
|||
def text_or_error(self):
|
||||
return self.text() or "Error; cannot read '%s'"%self.get_base_name()
|
||||
|
||||
def html_body(self, classes=""):
|
||||
if self.get_state_slug() == "rfc":
|
||||
try:
|
||||
html = Path(
|
||||
os.path.join(settings.RFC_PATH, self.canonical_name() + ".html")
|
||||
).read_text()
|
||||
except (IOError, UnicodeDecodeError):
|
||||
return None
|
||||
else:
|
||||
try:
|
||||
html = Path(
|
||||
os.path.join(
|
||||
settings.INTERNET_ALL_DRAFTS_ARCHIVE_DIR,
|
||||
self.name + "-" + self.rev + ".html",
|
||||
)
|
||||
).read_text()
|
||||
except (IOError, UnicodeDecodeError):
|
||||
return None
|
||||
|
||||
# If HTML was generated by rfc2html, do not return it. Caller
|
||||
# will use htmlize() to use a more current rfc2html to
|
||||
# generate an HTMLized version. TODO: There should be a
|
||||
# better way to determine how an HTML format was generated.
|
||||
if html.startswith("<pre>"):
|
||||
return None
|
||||
|
||||
# get body
|
||||
etree_html = etree.HTML(html)
|
||||
if etree_html is None:
|
||||
return None
|
||||
body = etree_html.xpath("//body")[0]
|
||||
body.tag = "div"
|
||||
if classes:
|
||||
body.attrib["class"] = classes
|
||||
|
||||
# remove things
|
||||
for tag in ["script"]:
|
||||
for t in body.xpath(f"//{tag}"):
|
||||
t.getparent().remove(t)
|
||||
html = etree.tostring(body, encoding=str, method="html")
|
||||
|
||||
return html
|
||||
|
||||
def htmlized(self):
|
||||
name = self.get_base_name()
|
||||
text = self.text()
|
||||
|
@ -566,17 +612,29 @@ class DocumentInfo(models.Model):
|
|||
|
||||
def pdfized(self):
|
||||
name = self.get_base_name()
|
||||
text = self.text()
|
||||
cache = caches['pdfized']
|
||||
cache_key = name.split('.')[0]
|
||||
text = self.html_body(classes="rfchtml")
|
||||
stylesheets = [finders.find("ietf/css/document_html_referenced.css")]
|
||||
if text:
|
||||
stylesheets.append(finders.find("ietf/css/document_html_txt.css"))
|
||||
else:
|
||||
text = self.htmlized()
|
||||
stylesheets.append(io.BytesIO(b"body { font-size: 9.2pt; }"))
|
||||
|
||||
cache = caches["pdfized"]
|
||||
cache_key = name.split(".")[0]
|
||||
try:
|
||||
pdf = cache.get(cache_key)
|
||||
except EOFError:
|
||||
pdf = None
|
||||
if not pdf:
|
||||
html = rfc2html.markup(text, path=settings.PDFIZER_URL_PREFIX)
|
||||
try:
|
||||
pdf = wpHTML(string=html.replace('\xad','')).write_pdf(stylesheets=[io.BytesIO(b'html { font-size: 94%;}')])
|
||||
pdf = wpHTML(
|
||||
string=text, base_url=settings.IDTRACKER_BASE_URL
|
||||
).write_pdf(
|
||||
stylesheets=stylesheets,
|
||||
presentational_hints=True,
|
||||
optimize_size=("fonts", "images"),
|
||||
)
|
||||
except AssertionError:
|
||||
pdf = None
|
||||
if pdf:
|
||||
|
|
|
@ -260,8 +260,8 @@ def urlize_ietf_docs(string, autoescape=None):
|
|||
|
||||
urlize_ietf_docs = stringfilter(urlize_ietf_docs)
|
||||
|
||||
@register.filter(name='urlize_related_source_list', is_safe=True, needs_autoescape=True)
|
||||
def urlize_related_source_list(related, autoescape=None):
|
||||
@register.filter(name='urlize_related_source_list', is_safe=True, document_html=False)
|
||||
def urlize_related_source_list(related, document_html=False):
|
||||
"""Convert a list of RelatedDocuments into list of links using the source document's canonical name"""
|
||||
links = []
|
||||
names = set()
|
||||
|
@ -273,8 +273,7 @@ def urlize_related_source_list(related, autoescape=None):
|
|||
continue
|
||||
names.add(name)
|
||||
titles.add(title)
|
||||
url = urlreverse('ietf.doc.views_doc.document_main', kwargs=dict(name=name))
|
||||
if autoescape:
|
||||
url = urlreverse('ietf.doc.views_doc.document_main' if document_html is False else 'ietf.doc.views_doc.document_html', kwargs=dict(name=name))
|
||||
name = escape(name)
|
||||
title = escape(title)
|
||||
links.append(mark_safe(
|
||||
|
@ -284,15 +283,14 @@ def urlize_related_source_list(related, autoescape=None):
|
|||
))
|
||||
return links
|
||||
|
||||
@register.filter(name='urlize_related_target_list', is_safe=True, needs_autoescape=True)
|
||||
def urlize_related_target_list(related, autoescape=None):
|
||||
@register.filter(name='urlize_related_target_list', is_safe=True, document_html=False)
|
||||
def urlize_related_target_list(related, document_html=False):
|
||||
"""Convert a list of RelatedDocuments into list of links using the target document's canonical name"""
|
||||
links = []
|
||||
for rel in related:
|
||||
name=rel.target.document.canonical_name()
|
||||
title = rel.target.document.title
|
||||
url = urlreverse('ietf.doc.views_doc.document_main', kwargs=dict(name=name))
|
||||
if autoescape:
|
||||
url = urlreverse('ietf.doc.views_doc.document_main' if document_html is False else 'ietf.doc.views_doc.document_html', kwargs=dict(name=name))
|
||||
name = escape(name)
|
||||
title = escape(title)
|
||||
links.append(mark_safe(
|
||||
|
@ -554,6 +552,19 @@ def consensus(doc):
|
|||
else:
|
||||
return "Unknown"
|
||||
|
||||
|
||||
@register.filter
|
||||
def std_level_to_label_format(doc):
|
||||
"""Returns valid Bootstrap classes to label a status level badge."""
|
||||
if doc.is_rfc():
|
||||
if doc.related_that("obs"):
|
||||
return "obs"
|
||||
else:
|
||||
return doc.std_level_id
|
||||
else:
|
||||
return "draft"
|
||||
|
||||
|
||||
@register.filter
|
||||
def pos_to_label_format(text):
|
||||
"""Returns valid Bootstrap classes to label a ballot position."""
|
||||
|
|
|
@ -489,7 +489,7 @@ Table of Contents
|
|||
1. Introduction
|
||||
|
||||
This document describes how to make the Martian networks work. The
|
||||
methods used in Earth do not directly translate to the efficent
|
||||
methods used in Earth do not directly translate to the efficient
|
||||
networks on Mars, as the topographical differences caused by planets.
|
||||
For example the avian carriers, cannot be used in the Mars, thus
|
||||
RFC1149 ([RFC1149]) cannot be used in Mars.
|
||||
|
@ -730,13 +730,13 @@ Man Expires September 22, 2015 [Page 3]
|
|||
|
||||
r = self.client.get(urlreverse("ietf.doc.views_doc.document_html", kwargs=dict(name=draft.name)))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertContains(r, "Versions:")
|
||||
self.assertContains(r, "Select version")
|
||||
self.assertContains(r, "Deimos street")
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(q('title').text(), 'draft-ietf-mars-test-01')
|
||||
self.assertEqual(len(q('.rfcmarkup pre')), 4)
|
||||
self.assertEqual(len(q('.rfcmarkup span.h1')), 2)
|
||||
self.assertEqual(len(q('.rfcmarkup a[href]')), 41)
|
||||
self.assertEqual(len(q('.rfcmarkup pre')), 3)
|
||||
self.assertEqual(len(q('.rfcmarkup span.h1, .rfcmarkup h1')), 2)
|
||||
self.assertEqual(len(q('.rfcmarkup a[href]')), 28)
|
||||
|
||||
r = self.client.get(urlreverse("ietf.doc.views_doc.document_html", kwargs=dict(name=draft.name, rev=draft.rev)))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
|
|
@ -448,8 +448,8 @@ class EditCharterTests(TestCase):
|
|||
# Regenerate does not save!
|
||||
self.assertEqual(charter.notify,newlist)
|
||||
q = PyQuery(r.content)
|
||||
formlist = q('form input[name=notify]')[0].value
|
||||
self.assertEqual(formlist, None)
|
||||
formlist = q('form textarea[name=notify]')[0].value.strip()
|
||||
self.assertEqual(formlist, "")
|
||||
|
||||
def test_edit_ad(self):
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ class ConflictReviewTests(TestCase):
|
|||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(len(q('form input[name=notify]')),1)
|
||||
self.assertEqual(len(q('form textarea[name=notify]')), 1)
|
||||
self.assertEqual(len(q('form select[name=ad]')),0)
|
||||
|
||||
# successfully starts a review, and notifies the secretariat
|
||||
|
@ -179,8 +179,8 @@ class ConflictReviewTests(TestCase):
|
|||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(len(q('form input[name=notify]')),1)
|
||||
self.assertEqual(doc.notify,q('form input[name=notify]')[0].value)
|
||||
self.assertEqual(len(q('form textarea[name=notify]')), 1)
|
||||
self.assertEqual(doc.notify, q('form textarea[name=notify]')[0].value.strip())
|
||||
|
||||
# change notice list
|
||||
newlist = '"Foo Bar" <foo@bar.baz.com>'
|
||||
|
@ -197,7 +197,7 @@ class ConflictReviewTests(TestCase):
|
|||
# Regenerate does not save!
|
||||
self.assertEqual(doc.notify,newlist)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(None,q('form input[name=notify]')[0].value)
|
||||
self.assertEqual("", q('form textarea[name=notify]')[0].value.strip())
|
||||
|
||||
def test_edit_ad(self):
|
||||
doc = Document.objects.get(name='conflict-review-imaginary-irtf-submission')
|
||||
|
|
|
@ -456,7 +456,7 @@ class EditInfoTests(TestCase):
|
|||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(len(q('form select[name=intended_std_level]')), 1)
|
||||
self.assertEqual(None,q('form input[name=notify]')[0].value)
|
||||
self.assertEqual("", q('form textarea[name=notify]')[0].value.strip())
|
||||
|
||||
# add
|
||||
events_before = draft.docevent_set.count()
|
||||
|
@ -947,7 +947,7 @@ class IndividualInfoFormsTests(TestCase):
|
|||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code,200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(len(q('form input[name=notify]')),1)
|
||||
self.assertEqual(len(q('form textarea[name=notify]')), 1)
|
||||
|
||||
# Provide a list
|
||||
r = self.client.post(url,dict(notify="TJ2APh2P@ietf.org",save_addresses="1"))
|
||||
|
@ -962,7 +962,7 @@ class IndividualInfoFormsTests(TestCase):
|
|||
# Regenerate does not save!
|
||||
self.assertEqual(doc.notify,'TJ2APh2P@ietf.org')
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(None,q('form input[name=notify]')[0].value)
|
||||
self.assertEqual("", q('form textarea[name=notify]')[0].value.strip())
|
||||
|
||||
def test_doc_change_intended_status(self):
|
||||
url = urlreverse('ietf.doc.views_draft.change_intention', kwargs=dict(name=self.docname))
|
||||
|
|
|
@ -147,8 +147,8 @@ class StatusChangeTests(TestCase):
|
|||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(len(q('form input[name=notify]')),1)
|
||||
self.assertEqual(doc.notify,q('form input[name=notify]')[0].value)
|
||||
self.assertEqual(len(q('form textarea[name=notify]')), 1)
|
||||
self.assertEqual(doc.notify, q('form textarea[name=notify]')[0].value.strip())
|
||||
|
||||
# change notice list
|
||||
newlist = '"Foo Bar" <foo@bar.baz.com>'
|
||||
|
@ -169,8 +169,8 @@ class StatusChangeTests(TestCase):
|
|||
# Regenerate does not save!
|
||||
self.assertEqual(doc.notify,newlist)
|
||||
q = PyQuery(r.content)
|
||||
formlist = q('form input[name=notify]')[0].value
|
||||
self.assertEqual(None,formlist)
|
||||
formlist = q('form textarea[name=notify]')[0].value.strip()
|
||||
self.assertEqual("", formlist)
|
||||
|
||||
def test_edit_title(self):
|
||||
doc = Document.objects.get(name='status-change-imaginary-mid-review')
|
||||
|
|
|
@ -995,41 +995,6 @@ def get_search_cache_key(params):
|
|||
key = "doc:document:search:" + hashlib.sha512(json.dumps(kwargs, sort_keys=True).encode('utf-8')).hexdigest()
|
||||
return key
|
||||
|
||||
def label_wrap(label, items, joiner=',', max=50):
|
||||
lines = []
|
||||
if not items:
|
||||
return lines
|
||||
line = '%s: %s' % (label, items[0])
|
||||
for item in items[1:]:
|
||||
if len(line)+len(joiner+' ')+len(item) > max:
|
||||
lines.append(line+joiner)
|
||||
line = ' '*(len(label)+len(': ')) + item
|
||||
else:
|
||||
line += joiner+' '+item
|
||||
if line:
|
||||
lines.append(line)
|
||||
return lines
|
||||
|
||||
def join_justified(left, right, width=72):
|
||||
count = max(len(left), len(right))
|
||||
left = left + ['']*(count-len(left))
|
||||
right = right + ['']*(count-len(right))
|
||||
lines = []
|
||||
i = 0
|
||||
while True:
|
||||
l = left[i]
|
||||
r = right[i]
|
||||
if len(l)+1+len(r) > width:
|
||||
left = left + ['']
|
||||
right = right[:i] + [''] + right[i:]
|
||||
r = right[i]
|
||||
count += 1
|
||||
lines.append( l + ' ' + r.rjust(width-len(l)-1) )
|
||||
i += 1
|
||||
if i >= count:
|
||||
break
|
||||
return lines
|
||||
|
||||
def build_file_urls(doc):
|
||||
if isinstance(doc,Document) and doc.get_state_slug() == "rfc":
|
||||
name = doc.canonical_name()
|
||||
|
@ -1069,135 +1034,6 @@ def build_file_urls(doc):
|
|||
|
||||
return file_urls, found_types
|
||||
|
||||
def build_doc_supermeta_block(doc):
|
||||
items = []
|
||||
items.append(f'[<a href="{ settings.IDTRACKER_BASE_URL }" title="Document search and retrieval page">Search</a>]')
|
||||
|
||||
file_urls, found_types = build_file_urls(doc)
|
||||
file_urls = [('txt',url) if label=='plain text' else (label,url) for label,url in file_urls]
|
||||
|
||||
if file_urls:
|
||||
file_labels = {
|
||||
'txt' : 'Plaintext version of this document',
|
||||
'xml' : 'XML source for this document',
|
||||
'pdf' : 'PDF version of this document',
|
||||
'html' : 'HTML version of this document, from XML2RFC',
|
||||
'bibtex' : 'BibTex entry for this document',
|
||||
}
|
||||
parts=[]
|
||||
for label,url in file_urls:
|
||||
if 'htmlized' not in label:
|
||||
file_label=file_labels.get(label,'')
|
||||
title_attribute = f' title="{file_label}"' if file_label else ''
|
||||
partstring = f'<a href="{url}"{title_attribute}>{label}</a>'
|
||||
parts.append(partstring)
|
||||
items.append('[' + '|'.join(parts) + ']')
|
||||
|
||||
items.append(f'[<a href="{ urlreverse("ietf.doc.views_doc.document_main",kwargs=dict(name=doc.canonical_name())) }" title="Datatracker information for this document">Tracker</a>]')
|
||||
if doc.group.acronym != 'none':
|
||||
items.append(f'[<a href="{urlreverse("ietf.group.views.group_home",kwargs=dict(acronym=doc.group.acronym))}" title="The working group handling this document">WG</a>]')
|
||||
items.append(f'[<a href="mailto:{doc.name}@ietf.org?subject={doc.name}" title="Send email to the document authors">Email</a>]')
|
||||
if doc.rev != "00":
|
||||
items.append(f'[<a href="{settings.RFCDIFF_BASE_URL}?difftype=--hwdiff&url2={doc.name}-{doc.rev}.txt" title="Inline diff (wdiff)">Diff1</a>]')
|
||||
items.append(f'[<a href="{settings.RFCDIFF_BASE_URL}?url2={doc.name}-{doc.rev}.txt" title="Side-by-side diff">Diff2</a>]')
|
||||
items.append(f'[<a href="{settings.IDNITS_BASE_URL}?url={settings.IETF_ID_ARCHIVE_URL}{doc.name}-{doc.rev}.txt" title="Run an idnits check of this document">Nits</a>]')
|
||||
|
||||
return ' '.join(items)
|
||||
|
||||
def build_doc_meta_block(doc, path):
|
||||
def add_markup(path, doc, lines):
|
||||
is_hst = doc.is_dochistory()
|
||||
rev = doc.rev
|
||||
if is_hst:
|
||||
doc = doc.doc
|
||||
name = doc.name
|
||||
rfcnum = doc.rfc_number()
|
||||
errata_url = settings.RFC_EDITOR_ERRATA_URL.format(rfc_number=rfcnum) if not is_hst else ""
|
||||
ipr_url = "%s?submit=draft&id=%s" % (urlreverse('ietf.ipr.views.search'), name)
|
||||
for i, line in enumerate(lines):
|
||||
# add draft links
|
||||
line = re.sub(r'\b(draft-[-a-z0-9]+)\b', r'<a href="%s/\g<1>">\g<1></a>'%(path, ), line)
|
||||
# add rfcXXXX to RFC links
|
||||
line = re.sub(r' (rfc[0-9]+)\b', r' <a href="%s/\g<1>">\g<1></a>'%(path, ), line)
|
||||
# add XXXX to RFC links
|
||||
line = re.sub(r' ([0-9]{3,5})\b', r' <a href="%s/rfc\g<1>">\g<1></a>'%(path, ), line)
|
||||
# add draft revision links
|
||||
line = re.sub(r' ([0-9]{2})\b', r' <a href="%s/%s-\g<1>">\g<1></a>'%(path, name, ), line)
|
||||
if rfcnum:
|
||||
# add errata link
|
||||
line = re.sub(r'Errata exist', r'<a class="text-warning" href="%s">Errata exist</a>'%(errata_url, ), line)
|
||||
if is_hst or not rfcnum:
|
||||
# make current draft rev bold
|
||||
line = re.sub(r'>(%s)<'%rev, r'><b>\g<1></b><', line)
|
||||
line = re.sub(r'IPR declarations', r'<a class="text-warning" href="%s">IPR declarations</a>'%(ipr_url, ), line)
|
||||
line = line.replace(r'[txt]', r'[<a href="%s">txt</a>]' % doc.get_href())
|
||||
lines[i] = line
|
||||
return lines
|
||||
#
|
||||
now = timezone.now()
|
||||
draft_state = doc.get_state('draft')
|
||||
block = ''
|
||||
meta = {}
|
||||
if doc.type_id == 'draft':
|
||||
revisions = []
|
||||
ipr = doc.related_ipr()
|
||||
if ipr:
|
||||
meta['ipr'] = [ "IPR declarations" ]
|
||||
if doc.is_rfc() and not doc.is_dochistory():
|
||||
if not doc.name.startswith('rfc'):
|
||||
meta['from'] = [ "%s-%s"%(doc.name, doc.rev) ]
|
||||
meta['errata'] = [ "Errata exist" ] if doc.tags.filter(slug='errata').exists() else []
|
||||
|
||||
meta['obsoletedby'] = [ document.rfc_number() for alias in doc.related_that('obs') for document in alias.docs.all() ]
|
||||
meta['obsoletedby'].sort()
|
||||
meta['updatedby'] = [ document.rfc_number() for alias in doc.related_that('updates') for document in alias.docs.all() ]
|
||||
meta['updatedby'].sort()
|
||||
meta['stdstatus'] = [ doc.std_level.name ]
|
||||
else:
|
||||
dd = doc.doc if doc.is_dochistory() else doc
|
||||
revisions += [ '(%s)%s'%(d.name, ' '*(2-((len(d.name)-1)%3))) for d in dd.replaces() ]
|
||||
revisions += doc.revisions()
|
||||
if doc.is_dochistory() and doc.doc.is_rfc():
|
||||
revisions += [ doc.doc.canonical_name() ]
|
||||
else:
|
||||
revisions += [ d.name for d in doc.replaced_by() ]
|
||||
meta['versions'] = revisions
|
||||
if not doc.is_dochistory and draft_state.slug == 'active' and now > doc.expires:
|
||||
# Active past expiration date
|
||||
meta['active'] = [ 'Document is active' ]
|
||||
meta['state' ] = [ doc.friendly_state() ]
|
||||
intended_std = doc.intended_std_level if doc.intended_std_level else None
|
||||
if intended_std:
|
||||
if intended_std.slug in ['ps', 'ds', 'std']:
|
||||
meta['stdstatus'] = [ "Standards Track" ]
|
||||
else:
|
||||
meta['stdstatus'] = [ intended_std.name ]
|
||||
elif doc.type_id == 'charter':
|
||||
meta['versions'] = doc.revisions()
|
||||
#
|
||||
# Add markup to items that needs it.
|
||||
if 'versions' in meta:
|
||||
meta['versions'] = label_wrap('Versions', meta['versions'], joiner="")
|
||||
for label in ['Obsoleted by', 'Updated by', 'From' ]:
|
||||
item = label.replace(' ','').lower()
|
||||
if item in meta and meta[item]:
|
||||
meta[item] = label_wrap(label, meta[item])
|
||||
#
|
||||
left = []
|
||||
right = []
|
||||
#right = [ '[txt]']
|
||||
for item in [ 'from', 'versions', 'obsoletedby', 'updatedby', ]:
|
||||
if item in meta and meta[item]:
|
||||
left += meta[item]
|
||||
for item in ['stdstatus', 'active', 'state', 'ipr', 'errata', ]:
|
||||
if item in meta and meta[item]:
|
||||
right += meta[item]
|
||||
lines = join_justified(left, right)
|
||||
block = '\n'.join(add_markup(path, doc, lines))
|
||||
#
|
||||
return block
|
||||
|
||||
|
||||
def augment_docs_and_user_with_user_info(docs, user):
|
||||
"""Add attribute to each document with whether the document is tracked
|
||||
or has a review wish by the user or not, and the review teams the user is on."""
|
||||
|
@ -1362,5 +1198,9 @@ def bibxml_for_draft(doc, rev=None):
|
|||
else:
|
||||
doc.date = doc.time.astimezone(tzinfo).date() # Even if this may be incorrect, what would be better?
|
||||
|
||||
return render_to_string('doc/bibxml.xml', {'name':doc.name, 'doc': doc, 'doc_bibtype':'I-D'})
|
||||
name = doc.name if isinstance(doc, Document) else doc.doc.name
|
||||
if name.startswith('rfc'): # bibxml3 does not speak of RFCs
|
||||
raise Http404()
|
||||
|
||||
return render_to_string('doc/bibxml.xml', {'name':name, 'doc':doc, 'doc_bibtype':'I-D'})
|
||||
|
||||
|
|
|
@ -370,13 +370,25 @@ def approve_conflict_review(request, name):
|
|||
))
|
||||
|
||||
class SimpleStartReviewForm(forms.Form):
|
||||
notify = forms.CharField(max_length=255, label="Notice emails", help_text="Separate email addresses with commas.", required=False)
|
||||
notify = forms.CharField(
|
||||
widget=forms.Textarea,
|
||||
max_length=1023,
|
||||
label="Notice emails",
|
||||
help_text="Separate email addresses with commas.",
|
||||
required=False,
|
||||
)
|
||||
|
||||
class StartReviewForm(forms.Form):
|
||||
ad = forms.ModelChoiceField(Person.objects.filter(role__name="ad", role__group__state="active",role__group__type='area').order_by('name'),
|
||||
label="Shepherding AD", empty_label="(None)", required=True)
|
||||
create_in_state = forms.ModelChoiceField(State.objects.filter(used=True, type="conflrev", slug__in=("needshep", "adrev")), empty_label=None, required=False)
|
||||
notify = forms.CharField(max_length=255, label="Notice emails", help_text="Separate email addresses with commas.", required=False)
|
||||
notify = forms.CharField(
|
||||
widget=forms.Textarea,
|
||||
max_length=1023,
|
||||
label="Notice emails",
|
||||
help_text="Separate email addresses with commas.",
|
||||
required=False,
|
||||
)
|
||||
telechat_date = forms.TypedChoiceField(coerce=lambda x: datetime.datetime.strptime(x, '%Y-%m-%d').date(), empty_value=None, required=False, widget=forms.Select(attrs={'onchange':'make_bold()'}))
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
|
|
@ -49,6 +49,7 @@ from django.template.loader import render_to_string
|
|||
from django.urls import reverse as urlreverse
|
||||
from django.conf import settings
|
||||
from django import forms
|
||||
from django.contrib.staticfiles import finders
|
||||
|
||||
|
||||
import debug # pyflakes:ignore
|
||||
|
@ -61,9 +62,9 @@ from ietf.doc.utils import (add_links_in_new_revision_events, augment_events_wit
|
|||
can_adopt_draft, can_unadopt_draft, get_chartering_type, get_tags_for_stream_id,
|
||||
needed_ballot_positions, nice_consensus, prettify_std_name, update_telechat, has_same_ballot,
|
||||
get_initial_notify, make_notify_changed_event, make_rev_history, default_consensus,
|
||||
add_events_message_info, get_unicode_document_content, build_doc_meta_block,
|
||||
add_events_message_info, get_unicode_document_content,
|
||||
augment_docs_and_user_with_user_info, irsg_needed_ballot_positions, add_action_holder_change_event,
|
||||
build_doc_supermeta_block, build_file_urls, update_documentauthors, fuzzy_find_documents,
|
||||
build_file_urls, update_documentauthors, fuzzy_find_documents,
|
||||
bibxml_for_draft)
|
||||
from ietf.doc.utils_bofreq import bofreq_editors, bofreq_responsible
|
||||
from ietf.group.models import Role, Group
|
||||
|
@ -140,12 +141,12 @@ def interesting_doc_relations(doc):
|
|||
|
||||
return interesting_relations_that, interesting_relations_that_doc
|
||||
|
||||
def document_main(request, name, rev=None):
|
||||
def document_main(request, name, rev=None, document_html=False):
|
||||
doc = get_object_or_404(Document.objects.select_related(), docalias__name=name)
|
||||
|
||||
# take care of possible redirections
|
||||
aliases = DocAlias.objects.filter(docs=doc).values_list("name", flat=True)
|
||||
if rev==None and doc.type_id == "draft" and not name.startswith("rfc"):
|
||||
if document_html is False and rev==None and doc.type_id == "draft" and not name.startswith("rfc"):
|
||||
for a in aliases:
|
||||
if a.startswith("rfc"):
|
||||
return redirect("ietf.doc.views_doc.document_main", name=a)
|
||||
|
@ -169,7 +170,7 @@ def document_main(request, name, rev=None):
|
|||
doc = h
|
||||
break
|
||||
|
||||
if not snapshot:
|
||||
if not snapshot and document_html is False:
|
||||
return redirect('ietf.doc.views_doc.document_main', name=name)
|
||||
|
||||
if doc.type_id == "charter":
|
||||
|
@ -184,7 +185,6 @@ def document_main(request, name, rev=None):
|
|||
|
||||
top = render_document_top(request, doc, "status", name)
|
||||
|
||||
|
||||
telechat = doc.latest_event(TelechatDocEvent, type="scheduled_for_telechat")
|
||||
if telechat and (not telechat.telechat_date or telechat.telechat_date < date_today(settings.TIME_ZONE)):
|
||||
telechat = None
|
||||
|
@ -446,8 +446,22 @@ def document_main(request, name, rev=None):
|
|||
else:
|
||||
stream_desc = "(None)"
|
||||
|
||||
return render(request, "doc/document_draft.html",
|
||||
html = None
|
||||
js = None
|
||||
css = None
|
||||
if document_html:
|
||||
html = doc.html_body()
|
||||
if request.COOKIES.get("pagedeps") == "inline":
|
||||
js = Path(finders.find("ietf/js/document_html.js")).read_text()
|
||||
css = Path(finders.find("ietf/css/document_html_inline.css")).read_text()
|
||||
if html:
|
||||
css += Path(finders.find("ietf/css/document_html_txt.css")).read_text()
|
||||
return render(request, "doc/document_draft.html" if document_html is False else "doc/document_html.html",
|
||||
dict(doc=doc,
|
||||
document_html=document_html,
|
||||
css=css,
|
||||
js=js,
|
||||
html=html,
|
||||
group=group,
|
||||
top=top,
|
||||
name=name,
|
||||
|
@ -787,7 +801,6 @@ def document_raw_id(request, name, rev=None, ext=None):
|
|||
except:
|
||||
raise Http404
|
||||
|
||||
|
||||
def document_html(request, name, rev=None):
|
||||
found = fuzzy_find_documents(name, rev)
|
||||
num_found = found.documents.count()
|
||||
|
@ -811,30 +824,7 @@ def document_html(request, name, rev=None):
|
|||
if not os.path.exists(doc.get_file_name()):
|
||||
raise Http404("File not found: %s" % doc.get_file_name())
|
||||
|
||||
if doc.type_id in ['draft',]:
|
||||
doc.supermeta = build_doc_supermeta_block(doc)
|
||||
doc.meta = build_doc_meta_block(doc, settings.HTMLIZER_URL_PREFIX)
|
||||
|
||||
doccolor = 'bgwhite' # Unknown
|
||||
if doc.type_id=='draft':
|
||||
if doc.is_rfc():
|
||||
if doc.related_that('obs'):
|
||||
doccolor = 'bgbrown'
|
||||
else:
|
||||
doccolor = {
|
||||
'ps' : 'bgblue',
|
||||
'exp' : 'bgyellow',
|
||||
'inf' : 'bgorange',
|
||||
'ds' : 'bgcyan',
|
||||
'hist' : 'bggrey',
|
||||
'std' : 'bggreen',
|
||||
'bcp' : 'bgmagenta',
|
||||
'unkn' : 'bgwhite',
|
||||
}.get(doc.std_level_id, 'bgwhite')
|
||||
else:
|
||||
doccolor = 'bgred' # Draft
|
||||
|
||||
return render(request, "doc/document_html.html", {"doc":doc, "doccolor":doccolor })
|
||||
return document_main(request, name, rev=rev, document_html=True)
|
||||
|
||||
def document_pdfized(request, name, rev=None, ext=None):
|
||||
|
||||
|
|
|
@ -515,7 +515,13 @@ class EditInfoForm(forms.Form):
|
|||
area = forms.ModelChoiceField(Group.objects.filter(type="area", state="active"), empty_label="(None - individual submission)", required=False, label="Assigned to area")
|
||||
ad = forms.ModelChoiceField(Person.objects.filter(role__name="ad", role__group__state="active",role__group__type='area').order_by('name'), label="Responsible AD", empty_label="(None)", required=True)
|
||||
create_in_state = forms.ModelChoiceField(State.objects.filter(used=True, type="draft-iesg", slug__in=("pub-req", "watching")), empty_label=None, required=False)
|
||||
notify = forms.CharField(max_length=255, label="Notice emails", help_text="Separate email addresses with commas.", required=False)
|
||||
notify = forms.CharField(
|
||||
widget=forms.Textarea,
|
||||
max_length=1023,
|
||||
label="Notice emails",
|
||||
help_text="Separate email addresses with commas.",
|
||||
required=False,
|
||||
)
|
||||
note = forms.CharField(widget=forms.Textarea, label="IESG note", required=False, strip=False)
|
||||
telechat_date = forms.TypedChoiceField(coerce=lambda x: datetime.datetime.strptime(x, '%Y-%m-%d').date(), empty_value=None, required=False, widget=forms.Select(attrs={'onchange':'make_bold()'}))
|
||||
returning_item = forms.BooleanField(required=False)
|
||||
|
|
|
@ -468,7 +468,13 @@ class StartStatusChangeForm(forms.Form):
|
|||
ad = forms.ModelChoiceField(Person.objects.filter(role__name="ad", role__group__state="active",role__group__type='area').order_by('name'),
|
||||
label="Shepherding AD", empty_label="(None)", required=False)
|
||||
create_in_state = forms.ModelChoiceField(State.objects.filter(type="statchg", slug__in=("needshep", "adrev")), empty_label=None, required=False)
|
||||
notify = forms.CharField(max_length=255, label="Notice emails", help_text="Separate email addresses with commas.", required=False)
|
||||
notify = forms.CharField(
|
||||
widget=forms.Textarea,
|
||||
max_length=1023,
|
||||
label="Notice emails",
|
||||
help_text="Separate email addresses with commas.",
|
||||
required=False,
|
||||
)
|
||||
telechat_date = forms.TypedChoiceField(coerce=lambda x: datetime.datetime.strptime(x, '%Y-%m-%d').date(), empty_value=None, required=False, widget=forms.Select(attrs={'onchange':'make_bold()'}))
|
||||
relations={} # type: Dict[str, str]
|
||||
|
||||
|
|
|
@ -133,15 +133,15 @@ class Group(GroupInfo):
|
|||
role_names = [role_names]
|
||||
return user.is_authenticated and self.role_set.filter(name__in=role_names, person__user=user).exists()
|
||||
|
||||
def is_decendant_of(self, sought_parent):
|
||||
def is_descendant_of(self, sought_parent):
|
||||
parent = self.parent
|
||||
decendants = [ self, ]
|
||||
while (parent != None) and (parent not in decendants):
|
||||
decendants = [ parent ] + decendants
|
||||
descendants = [ self, ]
|
||||
while (parent != None) and (parent not in descendants):
|
||||
descendants = [ parent ] + descendants
|
||||
if parent.acronym == sought_parent:
|
||||
return True
|
||||
parent = parent.parent
|
||||
log.assertion('parent not in decendants')
|
||||
log.assertion('parent not in descendants')
|
||||
return False
|
||||
|
||||
def get_chair(self):
|
||||
|
|
|
@ -1937,12 +1937,12 @@ class GroupParentLoopTests(TestCase):
|
|||
import signal
|
||||
|
||||
def timeout_handler(signum, frame):
|
||||
raise Exception("Infinite loop in parent links is not handeled properly.")
|
||||
raise Exception("Infinite loop in parent links is not handled properly.")
|
||||
|
||||
signal.signal(signal.SIGALRM, timeout_handler)
|
||||
signal.alarm(1) # One second
|
||||
try:
|
||||
test2.is_decendant_of("ietf")
|
||||
test2.is_descendant_of("ietf")
|
||||
except AssertionError:
|
||||
pass
|
||||
except Exception:
|
||||
|
|
|
@ -18,7 +18,7 @@ from django_password_strength.widgets import PasswordStrengthInput, PasswordConf
|
|||
import debug # pyflakes:ignore
|
||||
|
||||
from ietf.person.models import Person, Email
|
||||
from ietf.mailinglists.models import Whitelisted
|
||||
from ietf.mailinglists.models import Allowlisted
|
||||
from ietf.utils.text import isascii
|
||||
|
||||
class RegistrationForm(forms.Form):
|
||||
|
@ -203,9 +203,9 @@ class ResetPasswordForm(forms.Form):
|
|||
class TestEmailForm(forms.Form):
|
||||
email = forms.EmailField(required=False)
|
||||
|
||||
class WhitelistForm(forms.ModelForm):
|
||||
class AllowlistForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Whitelisted
|
||||
model = Allowlisted
|
||||
exclude = ['by', 'time' ]
|
||||
|
||||
|
||||
|
|
|
@ -194,7 +194,7 @@ class IetfAuthTests(TestCase):
|
|||
|
||||
self.assertTrue(self.username_in_htpasswd_file(email))
|
||||
|
||||
def test_create_whitelisted_account(self):
|
||||
def test_create_allowlisted_account(self):
|
||||
email = "new-account@example.com"
|
||||
|
||||
# add allowlist entry
|
||||
|
@ -202,13 +202,13 @@ class IetfAuthTests(TestCase):
|
|||
self.assertEqual(r.status_code, 302)
|
||||
self.assertEqual(urlsplit(r["Location"])[2], urlreverse(ietf.ietfauth.views.profile))
|
||||
|
||||
r = self.client.get(urlreverse(ietf.ietfauth.views.add_account_whitelist))
|
||||
r = self.client.get(urlreverse(ietf.ietfauth.views.add_account_allowlist))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertContains(r, "Add a whitelist entry")
|
||||
self.assertContains(r, "Add an allowlist entry")
|
||||
|
||||
r = self.client.post(urlreverse(ietf.ietfauth.views.add_account_whitelist), {"email": email})
|
||||
r = self.client.post(urlreverse(ietf.ietfauth.views.add_account_allowlist), {"email": email})
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertContains(r, "Whitelist entry creation successful")
|
||||
self.assertContains(r, "Allowlist entry creation successful")
|
||||
|
||||
# log out
|
||||
r = self.client.get(urlreverse('django.contrib.auth.views.logout'))
|
||||
|
|
|
@ -24,5 +24,5 @@ urlpatterns = [
|
|||
url(r'^review/$', views.review_overview),
|
||||
url(r'^testemail/$', views.test_email),
|
||||
url(r'^username/$', views.change_username),
|
||||
url(r'^whitelist/add/?$', views.add_account_whitelist),
|
||||
url(r'^allowlist/add/?$', views.add_account_allowlist),
|
||||
]
|
||||
|
|
|
@ -62,13 +62,11 @@ import debug # pyflakes:ignore
|
|||
|
||||
from ietf.group.models import Role, Group
|
||||
from ietf.ietfauth.forms import ( RegistrationForm, PasswordForm, ResetPasswordForm, TestEmailForm,
|
||||
WhitelistForm, ChangePasswordForm, get_person_form, RoleEmailForm,
|
||||
AllowlistForm, ChangePasswordForm, get_person_form, RoleEmailForm,
|
||||
NewEmailForm, ChangeUsernameForm, PersonPasswordForm)
|
||||
from ietf.ietfauth.htpasswd import update_htpasswd_file
|
||||
from ietf.ietfauth.utils import role_required, has_role
|
||||
from ietf.mailinglists.models import Whitelisted
|
||||
# needed if we revert to higher barrier for account creation
|
||||
#from ietf.mailinglists.models import Subscribed, Whitelisted
|
||||
from ietf.mailinglists.models import Allowlisted
|
||||
from ietf.name.models import ExtResourceName
|
||||
from ietf.nomcom.models import NomCom
|
||||
from ietf.person.models import Person, Email, Alias, PersonalApiKey, PERSON_API_KEY_VALUES
|
||||
|
@ -128,7 +126,7 @@ def create_account(request):
|
|||
|
||||
# The following is what to revert to should that lowered barrier prove problematic
|
||||
# existing = Subscribed.objects.filter(email=to_email).first()
|
||||
# ok_to_create = ( Whitelisted.objects.filter(email=to_email).exists()
|
||||
# ok_to_create = ( Allowlisted.objects.filter(email=to_email).exists()
|
||||
# or existing and (existing.time + TimeDelta(seconds=settings.LIST_ACCOUNT_DELAY)) < DateTime.now() )
|
||||
# if ok_to_create:
|
||||
# send_account_creation_email(request, to_email)
|
||||
|
@ -522,19 +520,19 @@ def test_email(request):
|
|||
return r
|
||||
|
||||
@role_required('Secretariat')
|
||||
def add_account_whitelist(request):
|
||||
def add_account_allowlist(request):
|
||||
success = False
|
||||
if request.method == 'POST':
|
||||
form = WhitelistForm(request.POST)
|
||||
form = AllowlistForm(request.POST)
|
||||
if form.is_valid():
|
||||
email = form.cleaned_data['email']
|
||||
entry = Whitelisted(email=email, by=request.user.person)
|
||||
entry = Allowlisted(email=email, by=request.user.person)
|
||||
entry.save()
|
||||
success = True
|
||||
else:
|
||||
form = WhitelistForm()
|
||||
form = AllowlistForm()
|
||||
|
||||
return render(request, 'ietfauth/whitelist_form.html', {
|
||||
return render(request, 'ietfauth/allowlist_form.html', {
|
||||
'form': form,
|
||||
'success': success,
|
||||
})
|
||||
|
|
|
@ -134,7 +134,7 @@ class IprTests(TestCase):
|
|||
def test_search(self):
|
||||
WgDraftFactory() # The test matching the prefix "draft" needs more than one thing to find
|
||||
draft = WgDraftFactory()
|
||||
ipr = HolderIprDisclosureFactory(docs=[draft,],patent_info='Number: US12345\nTitle: A method of transfering bits\nInventor: A. Nonymous\nDate: 2000-01-01')
|
||||
ipr = HolderIprDisclosureFactory(docs=[draft,],patent_info='Number: US12345\nTitle: A method of transferring bits\nInventor: A. Nonymous\nDate: 2000-01-01')
|
||||
|
||||
url = urlreverse("ietf.ipr.views.search")
|
||||
|
||||
|
@ -262,7 +262,7 @@ class IprTests(TestCase):
|
|||
"iprdocrel_set-1-document": DocAlias.objects.filter(name__startswith="rfc").first().pk,
|
||||
"patent_number": "SE12345678901",
|
||||
"patent_inventor": "A. Nonymous",
|
||||
"patent_title": "A method of transfering bits",
|
||||
"patent_title": "A method of transferring bits",
|
||||
"patent_date": "2000-01-01",
|
||||
"has_patent_pending": False,
|
||||
"licensing": "royalty-free",
|
||||
|
@ -277,7 +277,7 @@ class IprTests(TestCase):
|
|||
ipr = iprs[0]
|
||||
self.assertEqual(ipr.holder_legal_name, "Test Legal")
|
||||
self.assertEqual(ipr.state.slug, 'pending')
|
||||
for item in ['SE12345678901','A method of transfering bits','2000-01-01']:
|
||||
for item in ['SE12345678901','A method of transferring bits','2000-01-01']:
|
||||
self.assertIn(item, ipr.get_child().patent_info)
|
||||
self.assertTrue(isinstance(ipr.get_child(),HolderIprDisclosure))
|
||||
self.assertEqual(len(outbox),1)
|
||||
|
@ -318,7 +318,7 @@ class IprTests(TestCase):
|
|||
"iprdocrel_set-1-document": DocAlias.objects.filter(name__startswith="rfc").first().pk,
|
||||
"patent_number": "SE12345678901",
|
||||
"patent_inventor": "A. Nonymous",
|
||||
"patent_title": "A method of transfering bits",
|
||||
"patent_title": "A method of transferring bits",
|
||||
"patent_date": "2000-01-01",
|
||||
"has_patent_pending": False,
|
||||
"licensing": "royalty-free",
|
||||
|
@ -332,7 +332,7 @@ class IprTests(TestCase):
|
|||
ipr = iprs[0]
|
||||
self.assertEqual(ipr.holder_legal_name, "Test Legal")
|
||||
self.assertEqual(ipr.state.slug, "pending")
|
||||
for item in ['SE12345678901','A method of transfering bits','2000-01-01' ]:
|
||||
for item in ['SE12345678901','A method of transferring bits','2000-01-01' ]:
|
||||
self.assertIn(item, ipr.get_child().patent_info)
|
||||
self.assertTrue(isinstance(ipr.get_child(),ThirdPartyIprDisclosure))
|
||||
self.assertEqual(len(outbox),1)
|
||||
|
@ -368,7 +368,7 @@ class IprTests(TestCase):
|
|||
"patent_date": "2000-01-01",
|
||||
"patent_inventor": "A. Nonymous",
|
||||
"patent_number": "SE12345678901",
|
||||
"patent_title": "A method of transfering bits",
|
||||
"patent_title": "A method of transferring bits",
|
||||
"submitter_email": "test@holder.com",
|
||||
"submitter_name": "Test Holder",
|
||||
"updates": [],
|
||||
|
@ -414,7 +414,7 @@ class IprTests(TestCase):
|
|||
"iprdocrel_set-1-document": DocAlias.objects.filter(name__startswith="rfc").first().pk,
|
||||
"patent_number": "SE12345678901",
|
||||
"patent_inventor": "A. Nonymous",
|
||||
"patent_title": "A method of transfering bits",
|
||||
"patent_title": "A method of transferring bits",
|
||||
"patent_date": "2000-01-01",
|
||||
"has_patent_pending": False,
|
||||
"licensing": "royalty-free",
|
||||
|
@ -450,7 +450,7 @@ class IprTests(TestCase):
|
|||
"iprdocrel_set-0-revisions": '00',
|
||||
"patent_number": "SE12345678901",
|
||||
"patent_inventor": "A. Nonymous",
|
||||
"patent_title": "A method of transfering bits",
|
||||
"patent_title": "A method of transferring bits",
|
||||
"patent_date": "2000-01-01",
|
||||
"has_patent_pending": False,
|
||||
"licensing": "royalty-free",
|
||||
|
|
|
@ -471,7 +471,6 @@ class IncomingLiaisonForm(LiaisonModelForm):
|
|||
|
||||
|
||||
class OutgoingLiaisonForm(LiaisonModelForm):
|
||||
from_contact = SearchableEmailField(only_users=True)
|
||||
approved = forms.BooleanField(label="Obtained prior approval", required=False)
|
||||
|
||||
class Meta:
|
||||
|
@ -501,6 +500,7 @@ class OutgoingLiaisonForm(LiaisonModelForm):
|
|||
self.fields['from_groups'].initial = [flat_choices[0][0]]
|
||||
|
||||
if has_role(self.user, "Secretariat"):
|
||||
self.fields['from_contact'] = SearchableEmailField(only_users=True) # secretariat can edit this field!
|
||||
return
|
||||
|
||||
if self.person.role_set.filter(name='liaiman',group__state='active'):
|
||||
|
@ -509,8 +509,10 @@ class OutgoingLiaisonForm(LiaisonModelForm):
|
|||
email = self.person.role_set.filter(name__in=('ad','chair'),group__state='active').first().email.address
|
||||
else:
|
||||
email = self.person.email_address()
|
||||
|
||||
# Non-secretariat user cannot change the from_contact field. Fill in its value.
|
||||
self.fields['from_contact'].disabled = True
|
||||
self.fields['from_contact'].initial = email
|
||||
self.fields['from_contact'].widget.attrs['readonly'] = True
|
||||
|
||||
def set_to_fields(self):
|
||||
'''Set to_groups and to_contacts options and initial value based on user
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
from django.contrib import admin
|
||||
|
||||
from ietf.mailinglists.models import List, Subscribed, Whitelisted
|
||||
from ietf.mailinglists.models import List, Subscribed, Allowlisted
|
||||
|
||||
|
||||
class ListAdmin(admin.ModelAdmin):
|
||||
|
@ -18,6 +18,6 @@ class SubscribedAdmin(admin.ModelAdmin):
|
|||
admin.site.register(Subscribed, SubscribedAdmin)
|
||||
|
||||
|
||||
class WhitelistedAdmin(admin.ModelAdmin):
|
||||
class AllowlistedAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'time', 'email', 'by')
|
||||
admin.site.register(Whitelisted, WhitelistedAdmin)
|
||||
admin.site.register(Allowlisted, AllowlistedAdmin)
|
||||
|
|
22
ietf/mailinglists/migrations/0003_allowlisted.py
Normal file
22
ietf/mailinglists/migrations/0003_allowlisted.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
# Generated by Django 2.2.28 on 2022-12-05 14:26
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('person', '0029_use_timezone_now_for_person_models'),
|
||||
('mailinglists', '0002_auto_20190703_1344'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameModel(
|
||||
old_name='Whitelisted',
|
||||
new_name='Allowlisted',
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='allowlisted',
|
||||
options={'verbose_name_plural': 'Allowlisted'},
|
||||
),
|
||||
]
|
|
@ -28,12 +28,12 @@ class Subscribed(models.Model):
|
|||
class Meta:
|
||||
verbose_name_plural = "Subscribed"
|
||||
|
||||
class Whitelisted(models.Model):
|
||||
class Allowlisted(models.Model):
|
||||
time = models.DateTimeField(auto_now_add=True)
|
||||
email = models.CharField("Email address", max_length=64, validators=[validate_email])
|
||||
by = ForeignKey(Person)
|
||||
def __str__(self):
|
||||
return "<Whitelisted: %s at %s>" % (self.email, self.time)
|
||||
return "<Allowlisted: %s at %s>" % (self.email, self.time)
|
||||
class Meta:
|
||||
verbose_name_plural = "Whitelisted"
|
||||
verbose_name_plural = "Allowlisted"
|
||||
|
||||
|
|
|
@ -11,17 +11,17 @@ from tastypie.cache import SimpleCache
|
|||
from ietf import api
|
||||
from ietf.api import ToOneField # pyflakes:ignore
|
||||
|
||||
from ietf.mailinglists.models import Whitelisted, List, Subscribed
|
||||
from ietf.mailinglists.models import Allowlisted, List, Subscribed
|
||||
|
||||
|
||||
from ietf.person.resources import PersonResource
|
||||
class WhitelistedResource(ModelResource):
|
||||
class AllowlistedResource(ModelResource):
|
||||
by = ToOneField(PersonResource, 'by')
|
||||
class Meta:
|
||||
queryset = Whitelisted.objects.all()
|
||||
queryset = Allowlisted.objects.all()
|
||||
serializer = api.Serializer()
|
||||
cache = SimpleCache()
|
||||
#resource_name = 'whitelisted'
|
||||
#resource_name = 'allowlisted'
|
||||
ordering = ['id', ]
|
||||
filtering = {
|
||||
"id": ALL,
|
||||
|
@ -29,7 +29,7 @@ class WhitelistedResource(ModelResource):
|
|||
"email": ALL,
|
||||
"by": ALL_WITH_RELATIONS,
|
||||
}
|
||||
api.mailinglists.register(WhitelistedResource())
|
||||
api.mailinglists.register(AllowlistedResource())
|
||||
|
||||
class ListResource(ModelResource):
|
||||
class Meta:
|
||||
|
|
|
@ -223,10 +223,10 @@ class InterimMeetingModelForm(forms.ModelForm):
|
|||
|
||||
class InterimSessionModelForm(forms.ModelForm):
|
||||
date = DatepickerDateField(date_format="yyyy-mm-dd", picker_settings={"autoclose": "1"}, label='Date', required=False)
|
||||
time = forms.TimeField(widget=forms.TimeInput(format='%H:%M'), required=True, help_text="Local time")
|
||||
time = forms.TimeField(widget=forms.TimeInput(format='%H:%M'), required=True, help_text="Start time in meeting time zone")
|
||||
time.widget.attrs['placeholder'] = "HH:MM"
|
||||
requested_duration = CustomDurationField(required=True)
|
||||
end_time = forms.TimeField(required=False, help_text="Local time")
|
||||
end_time = forms.TimeField(required=False, help_text="End time in meeting time zone")
|
||||
end_time.widget.attrs['placeholder'] = "HH:MM"
|
||||
remote_participation = forms.ChoiceField(choices=(), required=False)
|
||||
remote_instructions = forms.CharField(
|
||||
|
@ -258,8 +258,8 @@ class InterimSessionModelForm(forms.ModelForm):
|
|||
self.is_edit = bool(self.instance.pk)
|
||||
# setup fields that aren't intrinsic to the Session object
|
||||
if self.is_edit:
|
||||
self.initial['date'] = self.instance.official_timeslotassignment().timeslot.time
|
||||
self.initial['time'] = self.instance.official_timeslotassignment().timeslot.time
|
||||
self.initial['date'] = self.instance.official_timeslotassignment().timeslot.local_start_time().date()
|
||||
self.initial['time'] = self.instance.official_timeslotassignment().timeslot.local_start_time().time()
|
||||
if self.instance.agenda():
|
||||
doc = self.instance.agenda()
|
||||
content = doc.text_or_error()
|
||||
|
|
|
@ -256,6 +256,10 @@ class AgendaFilterOrganizer(AgendaKeywordTool):
|
|||
self.special_filters = None
|
||||
if self._use_legacy_keywords():
|
||||
self.extra_labels += ('Plenary',) # need this when not using session purpose
|
||||
self.manual_extra_labels = set()
|
||||
|
||||
def add_extra_filter(self, kw):
|
||||
self.manual_extra_labels.add(kw)
|
||||
|
||||
def get_non_area_keywords(self):
|
||||
"""Get list of any 'non-area' (aka 'special') keywords
|
||||
|
@ -436,13 +440,13 @@ class AgendaFilterOrganizer(AgendaKeywordTool):
|
|||
def _extra_filters(self):
|
||||
"""Get list of filters corresponding to self.extra_labels"""
|
||||
item_source = self.assignments or self.sessions or []
|
||||
candidates = set(self.extra_labels)
|
||||
candidates = set(self.extra_labels).union(self.manual_extra_labels)
|
||||
return self._filter_column(
|
||||
label=None,
|
||||
keyword=None,
|
||||
children=[
|
||||
self._filter_entry(label=label, keyword=xslugify(label), toggled_by=[], is_bof=False)
|
||||
for label in candidates if any(
|
||||
for label in candidates if label in self.manual_extra_labels or any(
|
||||
# Keep only those that will affect at least one session
|
||||
[label.lower() in item.filter_keywords for item in item_source]
|
||||
)]
|
||||
|
@ -1056,7 +1060,6 @@ def sessions_post_save(request, forms):
|
|||
by=request.user.person,
|
||||
)
|
||||
|
||||
if ('date' in form.changed_data) or ('time' in form.changed_data):
|
||||
update_interim_session_assignment(form)
|
||||
if 'agenda' in form.changed_data:
|
||||
form.save_agenda()
|
||||
|
@ -1136,6 +1139,8 @@ def update_interim_session_assignment(form):
|
|||
"""Helper function to create / update timeslot assigned to interim session
|
||||
|
||||
form is an InterimSessionModelForm
|
||||
|
||||
Only updates timeslot time (a datetime) and duration
|
||||
"""
|
||||
session = form.instance
|
||||
meeting = session.meeting
|
||||
|
@ -1144,6 +1149,7 @@ def update_interim_session_assignment(form):
|
|||
)
|
||||
if session.official_timeslotassignment():
|
||||
slot = session.official_timeslotassignment().timeslot
|
||||
if slot.time != time or slot.duration != session.requested_duration:
|
||||
slot.time = time
|
||||
slot.duration = session.requested_duration
|
||||
slot.save()
|
||||
|
|
|
@ -39,7 +39,7 @@ from ietf.name.models import (
|
|||
)
|
||||
from ietf.person.models import Person
|
||||
from ietf.utils.decorators import memoize
|
||||
from ietf.utils.history import find_history_replacements_active_at
|
||||
from ietf.utils.history import find_history_replacements_active_at, find_history_active_at
|
||||
from ietf.utils.storage import NoLocationMigrationFileSystemStorage
|
||||
from ietf.utils.text import xslugify
|
||||
from ietf.utils.timezone import datetime_from_date, date_today
|
||||
|
@ -409,18 +409,36 @@ class Meeting(models.Model):
|
|||
def uses_notes(self):
|
||||
return self.date>=datetime.date(2020,7,6)
|
||||
|
||||
def groups_at_the_time(self):
|
||||
def meeting_start(self):
|
||||
"""Meeting-local midnight at the start of the meeting date"""
|
||||
return self.tz().localize(datetime.datetime.combine(self.date, datetime.time()))
|
||||
|
||||
def _groups_at_the_time(self):
|
||||
"""Get dict mapping Group PK to appropriate Group or GroupHistory at meeting time
|
||||
|
||||
Known issue: only looks up Groups and their *current* parents when called. If a Group's
|
||||
parent was different at meeting time, that parent will not be in the cache. Use
|
||||
group_at_the_time() to look up values - that will fill in missing groups for you.
|
||||
"""
|
||||
if not hasattr(self,'cached_groups_at_the_time'):
|
||||
all_group_pks = set(self.session_set.values_list('group__pk', flat=True))
|
||||
all_group_pks.update(self.session_set.values_list('group__parent__pk', flat=True))
|
||||
all_group_pks.discard(None)
|
||||
# meeting_time is meeting-local midnight at the start of the meeting date
|
||||
meeting_start = self.tz().localize(
|
||||
datetime.datetime.combine(self.date, datetime.time())
|
||||
self.cached_groups_at_the_time = find_history_replacements_active_at(
|
||||
Group.objects.filter(pk__in=all_group_pks),
|
||||
self.meeting_start(),
|
||||
)
|
||||
self.cached_groups_at_the_time = find_history_replacements_active_at(Group.objects.filter(pk__in=all_group_pks), meeting_start)
|
||||
return self.cached_groups_at_the_time
|
||||
|
||||
def group_at_the_time(self, group):
|
||||
# MUST call self._groups_at_the_time() before assuming cached_groups_at_the_time exists
|
||||
gatt = self._groups_at_the_time()
|
||||
if group.pk in gatt:
|
||||
return gatt[group.pk]
|
||||
# Cache miss - look up the missing historical group and add it to the cache.
|
||||
new_item = find_history_active_at(group, self.meeting_start()) or group # fall back to original if no history
|
||||
self.cached_groups_at_the_time[group.pk] = new_item
|
||||
return new_item
|
||||
|
||||
class Meta:
|
||||
ordering = ["-date", "-id"]
|
||||
|
@ -1301,11 +1319,12 @@ class Session(models.Model):
|
|||
return urljoin(settings.IETF_NOTES_URL, self.notes_id())
|
||||
|
||||
def group_at_the_time(self):
|
||||
return self.meeting.groups_at_the_time()[self.group.pk]
|
||||
return self.meeting.group_at_the_time(self.group)
|
||||
|
||||
def group_parent_at_the_time(self):
|
||||
if self.group_at_the_time().parent:
|
||||
return self.meeting.groups_at_the_time()[self.group_at_the_time().parent.pk]
|
||||
return self.meeting.group_at_the_time(self.group_at_the_time().parent)
|
||||
|
||||
|
||||
class SchedulingEvent(models.Model):
|
||||
session = ForeignKey(Session)
|
||||
|
|
|
@ -6,6 +6,7 @@ from django.core.files.uploadedfile import SimpleUploadedFile
|
|||
from django.test import override_settings, RequestFactory
|
||||
|
||||
from ietf.group.factories import GroupFactory
|
||||
from ietf.meeting.factories import SessionFactory
|
||||
from ietf.meeting.forms import (FileUploadForm, ApplyToAllFileUploadForm, InterimSessionModelForm,
|
||||
InterimMeetingModelForm)
|
||||
from ietf.person.factories import PersonFactory
|
||||
|
@ -123,6 +124,15 @@ class InterimSessionModelFormTests(TestCase):
|
|||
self.assertNotIn('meetecho', choice_vals)
|
||||
self.assertIn('manual', choice_vals)
|
||||
|
||||
def test_edits_in_meeting_time_zone(self):
|
||||
# use a time zone that never has a UTC offset of 0, even with DST
|
||||
session = SessionFactory(meeting__type_id='interim', meeting__time_zone='America/Halifax')
|
||||
form = InterimSessionModelForm(instance=session)
|
||||
self.assertEqual(
|
||||
form.initial['time'].strftime('%H:%M'),
|
||||
session.official_timeslotassignment().timeslot.local_start_time().strftime('%H:%M'),
|
||||
)
|
||||
|
||||
|
||||
class InterimMeetingModelFormTests(TestCase):
|
||||
def test_enforces_authroles(self):
|
||||
|
|
|
@ -590,26 +590,26 @@ class InterimTests(TestCase):
|
|||
mock_form.changed_data = []
|
||||
mock_form.requires_approval = True
|
||||
|
||||
mock_form.cleaned_data = {'remote_participation': None}
|
||||
mock_form.cleaned_data = {'date': date_today(), 'time': datetime.time(1, 23), 'remote_participation': None}
|
||||
sessions_post_save(RequestFactory().post('/some/url'), [mock_form])
|
||||
self.assertTrue(mock_create_method.called)
|
||||
self.assertCountEqual(mock_create_method.call_args[0][0], [])
|
||||
|
||||
mock_create_method.reset_mock()
|
||||
mock_form.cleaned_data = {'remote_participation': 'manual'}
|
||||
mock_form.cleaned_data['remote_participation'] = 'manual'
|
||||
sessions_post_save(RequestFactory().post('/some/url'), [mock_form])
|
||||
self.assertTrue(mock_create_method.called)
|
||||
self.assertCountEqual(mock_create_method.call_args[0][0], [])
|
||||
|
||||
mock_create_method.reset_mock()
|
||||
mock_form.cleaned_data = {'remote_participation': 'meetecho'}
|
||||
mock_form.cleaned_data['remote_participation'] = 'meetecho'
|
||||
sessions_post_save(RequestFactory().post('/some/url'), [mock_form])
|
||||
self.assertTrue(mock_create_method.called)
|
||||
self.assertCountEqual(mock_create_method.call_args[0][0], [session])
|
||||
|
||||
# Check that an exception does not percolate through sessions_post_save
|
||||
mock_create_method.side_effect = RuntimeError('some error')
|
||||
mock_form.cleaned_data = {'remote_participation': 'meetecho'}
|
||||
mock_form.cleaned_data['remote_participation'] = 'meetecho'
|
||||
# create mock request with session / message storage
|
||||
request = RequestFactory().post('/some/url')
|
||||
setattr(request, 'session', 'session')
|
||||
|
|
|
@ -1076,9 +1076,9 @@ class InterimTests(IetfSeleniumTestCase):
|
|||
unexpected.add(entry.text)
|
||||
advance_month()
|
||||
|
||||
self.assertEqual(seen, visible_meetings, "Expected calendar entries not shown.")
|
||||
self.assertEqual(not_visible, set(), "Hidden calendar entries for expected interim meetings.")
|
||||
self.assertEqual(unexpected, set(), "Unexpected calendar entries visible")
|
||||
self.assertCountEqual(seen, visible_meetings, "Expected calendar entries not shown.")
|
||||
self.assertCountEqual(not_visible, set(), "Hidden calendar entries for expected interim meetings.")
|
||||
self.assertCountEqual(unexpected, set(), "Unexpected calendar entries visible")
|
||||
|
||||
def do_upcoming_view_filter_test(self, querystring, visible_meetings=()):
|
||||
self.login()
|
||||
|
@ -1152,102 +1152,85 @@ class InterimTests(IetfSeleniumTestCase):
|
|||
ietf_meetings = set(self.all_ietf_meetings())
|
||||
self.do_upcoming_view_filter_test('', ietf_meetings.union(self.displayed_interims()))
|
||||
|
||||
def test_upcoming_view_show_ietf_meetings(self):
|
||||
self.do_upcoming_view_filter_test('?show=ietf-meetings', self.all_ietf_meetings())
|
||||
|
||||
def test_upcoming_view_filter_show_group(self):
|
||||
# Show none
|
||||
ietf_meetings = set(self.all_ietf_meetings())
|
||||
self.do_upcoming_view_filter_test('?show=', ietf_meetings)
|
||||
self.do_upcoming_view_filter_test('?show=')
|
||||
|
||||
# Show one
|
||||
self.do_upcoming_view_filter_test('?show=mars',
|
||||
ietf_meetings.union(
|
||||
self.displayed_interims(groups=['mars'])
|
||||
))
|
||||
self.do_upcoming_view_filter_test('?show=mars', self.displayed_interims(groups=['mars']))
|
||||
|
||||
# Show two
|
||||
self.do_upcoming_view_filter_test('?show=mars,ames',
|
||||
ietf_meetings.union(
|
||||
self.displayed_interims(groups=['mars', 'ames'])
|
||||
))
|
||||
self.do_upcoming_view_filter_test('?show=mars,ames',self.displayed_interims(groups=['mars', 'ames']))
|
||||
|
||||
# Show two plus ietf-meetings
|
||||
self.do_upcoming_view_filter_test(
|
||||
'?show=ietf-meetings,mars,ames',
|
||||
set(self.all_ietf_meetings()).union(self.displayed_interims(groups=['mars', 'ames']))
|
||||
)
|
||||
|
||||
def test_upcoming_view_filter_show_area(self):
|
||||
mars = Group.objects.get(acronym='mars')
|
||||
area = mars.parent
|
||||
ietf_meetings = set(self.all_ietf_meetings())
|
||||
self.do_upcoming_view_filter_test('?show=%s' % area.acronym,
|
||||
ietf_meetings.union(
|
||||
self.displayed_interims(groups=['mars', 'ames'])
|
||||
))
|
||||
self.do_upcoming_view_filter_test('?show=%s' % area.acronym, self.displayed_interims(groups=['mars', 'ames']))
|
||||
|
||||
def test_upcoming_view_filter_show_type(self):
|
||||
ietf_meetings = set(self.all_ietf_meetings())
|
||||
self.do_upcoming_view_filter_test('?show=plenary',
|
||||
ietf_meetings.union(
|
||||
self.displayed_interims(groups=['sg'])
|
||||
))
|
||||
self.do_upcoming_view_filter_test('?show=plenary', self.displayed_interims(groups=['sg']))
|
||||
|
||||
def test_upcoming_view_filter_hide_group(self):
|
||||
mars = Group.objects.get(acronym='mars')
|
||||
area = mars.parent
|
||||
|
||||
# Without anything shown, should see only ietf meetings
|
||||
ietf_meetings = set(self.all_ietf_meetings())
|
||||
self.do_upcoming_view_filter_test('?hide=mars', ietf_meetings)
|
||||
self.do_upcoming_view_filter_test('?hide=mars')
|
||||
|
||||
# With group shown
|
||||
self.do_upcoming_view_filter_test('?show=ames,mars&hide=mars',
|
||||
ietf_meetings.union(
|
||||
self.displayed_interims(groups=['ames'])
|
||||
))
|
||||
self.do_upcoming_view_filter_test('?show=ames,mars&hide=mars', self.displayed_interims(groups=['ames']))
|
||||
# With area shown
|
||||
self.do_upcoming_view_filter_test('?show=%s&hide=mars' % area.acronym,
|
||||
ietf_meetings.union(
|
||||
self.displayed_interims(groups=['ames'])
|
||||
))
|
||||
|
||||
self.do_upcoming_view_filter_test('?show=%s&hide=mars' % area.acronym, self.displayed_interims(groups=['ames']))
|
||||
# With type shown
|
||||
self.do_upcoming_view_filter_test('?show=plenary&hide=sg',
|
||||
ietf_meetings)
|
||||
self.do_upcoming_view_filter_test('?show=plenary&hide=sg')
|
||||
|
||||
def test_upcoming_view_filter_hide_area(self):
|
||||
mars = Group.objects.get(acronym='mars')
|
||||
area = mars.parent
|
||||
|
||||
# Without anything shown, should see only ietf meetings
|
||||
ietf_meetings = set(self.all_ietf_meetings())
|
||||
self.do_upcoming_view_filter_test('?hide=%s' % area.acronym, ietf_meetings)
|
||||
# Without anything shown, should see nothing
|
||||
self.do_upcoming_view_filter_test('?hide=%s' % area.acronym)
|
||||
|
||||
# With area shown
|
||||
self.do_upcoming_view_filter_test('?show=%s&hide=%s' % (area.acronym, area.acronym),
|
||||
ietf_meetings)
|
||||
self.do_upcoming_view_filter_test('?show=%s&hide=%s' % (area.acronym, area.acronym))
|
||||
|
||||
# With group shown
|
||||
self.do_upcoming_view_filter_test('?show=mars&hide=%s' % area.acronym, ietf_meetings)
|
||||
self.do_upcoming_view_filter_test('?show=mars&hide=%s' % area.acronym)
|
||||
|
||||
# With type shown
|
||||
self.do_upcoming_view_filter_test('?show=regular&hide=%s' % area.acronym, ietf_meetings)
|
||||
self.do_upcoming_view_filter_test('?show=regular&hide=%s' % area.acronym)
|
||||
|
||||
# with IETF meetings shown
|
||||
self.do_upcoming_view_filter_test('?show=ietf-meetings,hide=%s' % area.acronym, self.all_ietf_meetings())
|
||||
|
||||
def test_upcoming_view_filter_hide_type(self):
|
||||
mars = Group.objects.get(acronym='mars')
|
||||
area = mars.parent
|
||||
|
||||
# Without anything shown, should see only ietf meetings
|
||||
ietf_meetings = set(self.all_ietf_meetings())
|
||||
self.do_upcoming_view_filter_test('?hide=regular', ietf_meetings)
|
||||
# Without anything shown, should see nothing
|
||||
self.do_upcoming_view_filter_test('?hide=regular')
|
||||
|
||||
# With group shown
|
||||
self.do_upcoming_view_filter_test('?show=mars&hide=regular', ietf_meetings)
|
||||
self.do_upcoming_view_filter_test('?show=mars&hide=regular')
|
||||
|
||||
# With type shown
|
||||
self.do_upcoming_view_filter_test('?show=plenary,regular&hide=%s' % area.acronym,
|
||||
ietf_meetings.union(
|
||||
self.do_upcoming_view_filter_test(
|
||||
'?show=plenary,regular&hide=regular',
|
||||
self.displayed_interims(groups=['sg'])
|
||||
))
|
||||
)
|
||||
|
||||
# With interim-meetings shown
|
||||
self.do_upcoming_view_filter_test('?show=plenary,regular&hide=regular', self.displayed_interims(groups=['sg']))
|
||||
|
||||
def test_upcoming_view_filter_whitespace(self):
|
||||
"""Whitespace in filter lists should be ignored"""
|
||||
meetings = set(self.all_ietf_meetings())
|
||||
meetings.update(self.displayed_interims(groups=['mars']))
|
||||
self.do_upcoming_view_filter_test('?show=mars , ames &hide= ames', meetings)
|
||||
self.do_upcoming_view_filter_test('?show=mars , ames &hide= ames', self.displayed_interims(groups=['mars']))
|
||||
|
||||
def test_upcoming_view_time_zone_selection(self):
|
||||
def _assert_interim_tz_correct(sessions, tz):
|
||||
|
|
|
@ -5,9 +5,11 @@ import datetime
|
|||
|
||||
from mock import patch
|
||||
|
||||
from ietf.group.factories import GroupFactory, GroupHistoryFactory
|
||||
from ietf.meeting.factories import MeetingFactory, SessionFactory, AttendedFactory
|
||||
from ietf.stats.factories import MeetingRegistrationFactory
|
||||
from ietf.utils.test_utils import TestCase
|
||||
from ietf.utils.timezone import date_today, datetime_today
|
||||
|
||||
|
||||
class MeetingTests(TestCase):
|
||||
|
@ -104,6 +106,14 @@ class MeetingTests(TestCase):
|
|||
vtz = meeting.vtimezone()
|
||||
self.assertIsNone(vtz)
|
||||
|
||||
def test_group_at_the_time(self):
|
||||
m = MeetingFactory(type_id='ietf', date=date_today() - datetime.timedelta(days=10))
|
||||
cached_groups = GroupFactory.create_batch(2)
|
||||
m.cached_groups_at_the_time = {g.pk: g for g in cached_groups} # fake the cache
|
||||
uncached_group_hist = GroupHistoryFactory(time=datetime_today() - datetime.timedelta(days=30))
|
||||
self.assertEqual(m.group_at_the_time(uncached_group_hist.group), uncached_group_hist)
|
||||
self.assertIn(uncached_group_hist.group.pk, m.cached_groups_at_the_time)
|
||||
|
||||
|
||||
class SessionTests(TestCase):
|
||||
def test_chat_archive_url_with_jabber(self):
|
||||
|
|
|
@ -4507,8 +4507,16 @@ class InterimTests(TestCase):
|
|||
# Just a quick check of functionality - details tested by test_js.InterimTests
|
||||
make_meeting_test_data(create_interims=True)
|
||||
url = urlreverse("ietf.meeting.views.upcoming_ical")
|
||||
r = self.client.get(url + '?show=mars')
|
||||
|
||||
r = self.client.get(url + '?show=mars')
|
||||
self.assertEqual(r.status_code, 200)
|
||||
assert_ical_response_is_valid(self, r,
|
||||
expected_event_summaries=[
|
||||
'mars - Martian Special Interest Group',
|
||||
],
|
||||
expected_event_count=1)
|
||||
|
||||
r = self.client.get(url + '?show=mars,ietf-meetings')
|
||||
self.assertEqual(r.status_code, 200)
|
||||
assert_ical_response_is_valid(self, r,
|
||||
expected_event_summaries=[
|
||||
|
@ -5374,12 +5382,11 @@ class InterimTests(TestCase):
|
|||
length_before = len(outbox)
|
||||
form_initial = r.context['form'].initial
|
||||
formset_initial = r.context['formset'].forms[0].initial
|
||||
new_time = formset_initial['time'] + datetime.timedelta(hours=1)
|
||||
data = {'group':group.pk,
|
||||
'meeting_type':'single',
|
||||
'session_set-0-id':meeting.session_set.first().id,
|
||||
'session_set-0-date':formset_initial['date'].strftime('%Y-%m-%d'),
|
||||
'session_set-0-time':new_time.strftime('%H:%M'),
|
||||
'session_set-0-time':'12:34',
|
||||
'session_set-0-requested_duration': '00:30',
|
||||
'session_set-0-remote_instructions':formset_initial['remote_instructions'],
|
||||
#'session_set-0-agenda':formset_initial['agenda'],
|
||||
|
@ -5392,7 +5399,10 @@ class InterimTests(TestCase):
|
|||
self.assertEqual(len(outbox),length_before)
|
||||
session = meeting.session_set.first()
|
||||
timeslot = session.official_timeslotassignment().timeslot
|
||||
self.assertEqual(timeslot.time,new_time)
|
||||
self.assertEqual(
|
||||
timeslot.time,
|
||||
meeting.tz().localize(datetime.datetime.combine(formset_initial['date'], datetime.time(12, 34))),
|
||||
)
|
||||
|
||||
def test_interim_request_edit(self):
|
||||
'''Edit request. Send notice of change'''
|
||||
|
@ -5412,13 +5422,12 @@ class InterimTests(TestCase):
|
|||
length_before = len(outbox)
|
||||
form_initial = r.context['form'].initial
|
||||
formset_initial = r.context['formset'].forms[0].initial
|
||||
new_time = formset_initial['time'] + datetime.timedelta(hours=1)
|
||||
new_duration = formset_initial['requested_duration'] + datetime.timedelta(hours=1)
|
||||
data = {'group':group.pk,
|
||||
'meeting_type':'single',
|
||||
'session_set-0-id':meeting.session_set.first().id,
|
||||
'session_set-0-date':formset_initial['date'].strftime('%Y-%m-%d'),
|
||||
'session_set-0-time':new_time.strftime('%H:%M'),
|
||||
'session_set-0-time': '12:34',
|
||||
'session_set-0-requested_duration':self.strfdelta(new_duration, '{hours}:{minutes}'),
|
||||
'session_set-0-remote_instructions':formset_initial['remote_instructions'],
|
||||
#'session_set-0-agenda':formset_initial['agenda'],
|
||||
|
@ -5432,7 +5441,10 @@ class InterimTests(TestCase):
|
|||
self.assertIn('CHANGED', outbox[-1]['Subject'])
|
||||
session = meeting.session_set.first()
|
||||
timeslot = session.official_timeslotassignment().timeslot
|
||||
self.assertEqual(timeslot.time,new_time)
|
||||
self.assertEqual(
|
||||
timeslot.time,
|
||||
meeting.tz().localize(datetime.datetime.combine(formset_initial['date'], datetime.time(12, 34))),
|
||||
)
|
||||
self.assertEqual(timeslot.duration,new_duration)
|
||||
|
||||
def strfdelta(self, tdelta, fmt):
|
||||
|
|
|
@ -3456,6 +3456,10 @@ def upcoming(request):
|
|||
# Set up for agenda filtering - only one filter_category here
|
||||
AgendaKeywordTagger(sessions=interim_sessions).apply()
|
||||
filter_organizer = AgendaFilterOrganizer(sessions=interim_sessions, single_category=True)
|
||||
# Allow filtering to show only IETF Meetings. This adds a button labeled "IETF Meetings" to the
|
||||
# "Other" column of the filter UI. When enabled, this adds the keyword "ietf-meetings" to the "show"
|
||||
# filter list. The IETF meetings are explicitly labeled with this keyword in upcoming.html.
|
||||
filter_organizer.add_extra_filter('IETF Meetings')
|
||||
|
||||
entries = list(ietf_meetings)
|
||||
entries.extend(list(interim_sessions))
|
||||
|
@ -3544,9 +3548,14 @@ def upcoming_ical(request):
|
|||
a.session = sessions.get(a.session_id) or a.session
|
||||
a.session.ical_status = ical_session_status(a)
|
||||
|
||||
# handle IETFs separately
|
||||
# Handle IETFs separately. Manually apply the 'ietf-meetings' filter.
|
||||
if filter_params is None or (
|
||||
'ietf-meetings' in filter_params['show'] and 'ietf-meetings' not in filter_params['hide']
|
||||
):
|
||||
ietfs = [m for m in meetings if m.type_id == 'ietf']
|
||||
preprocess_meeting_important_dates(ietfs)
|
||||
else:
|
||||
ietfs = []
|
||||
|
||||
meeting_vtz = {meeting.vtimezone() for meeting in meetings}
|
||||
meeting_vtz.discard(None)
|
||||
|
|
|
@ -385,7 +385,7 @@
|
|||
},
|
||||
{
|
||||
"fields": {
|
||||
"desc": "The document is in the RFC editor Queue (as confirmed by http://www.rfc-editor.org/queue.html).",
|
||||
"desc": "The document is in the RFC editor Queue (as confirmed by https://www.rfc-editor.org/queue.html).",
|
||||
"name": "RFC Ed Queue",
|
||||
"next_states": [
|
||||
7
|
||||
|
@ -2585,7 +2585,7 @@
|
|||
},
|
||||
{
|
||||
"fields": {
|
||||
"label": "Liason Statement State"
|
||||
"label": "Liaison Statement State"
|
||||
},
|
||||
"model": "doc.statetype",
|
||||
"pk": "liaison"
|
||||
|
@ -3844,7 +3844,7 @@
|
|||
{
|
||||
"fields": {
|
||||
"cc": [],
|
||||
"desc": "Recipients for message to adminstrators when a charter state edit needs followon administrative action",
|
||||
"desc": "Recipients for message to administrators when a charter state edit needs follow-on administrative action",
|
||||
"to": [
|
||||
"iesg_secretary"
|
||||
]
|
||||
|
@ -5909,7 +5909,7 @@
|
|||
},
|
||||
{
|
||||
"fields": {
|
||||
"desc": "The set of people who can approve this liasion statemetns",
|
||||
"desc": "The set of people who can approve this liaison statements",
|
||||
"template": "{{liaison.approver_emails|join:\", \"}}"
|
||||
},
|
||||
"model": "mailtrigger.recipient",
|
||||
|
|
|
@ -175,7 +175,7 @@ class MergeNomineeForm(forms.Form):
|
|||
secondary_emails = self.cleaned_data.get("secondary_emails")
|
||||
if primary_email and secondary_emails:
|
||||
if primary_email in secondary_emails:
|
||||
msg = "Primary and secondary email address must be differents"
|
||||
msg = "Primary and secondary email address must be different"
|
||||
self._errors["primary_email"] = self.error_class([msg])
|
||||
return self.cleaned_data
|
||||
|
||||
|
|
|
@ -65,7 +65,10 @@ class PersonFactory(factory.django.DjangoModelFactory):
|
|||
|
||||
user = factory.SubFactory(UserFactory)
|
||||
name = factory.LazyAttribute(lambda p: normalize_name('%s %s'%(p.user.first_name, p.user.last_name)))
|
||||
ascii = factory.LazyAttribute(lambda p: force_text(unidecode_name(p.name)))
|
||||
# Some i18n names, e.g., "शिला के.सी." have a dot at the end that is also part of the ASCII, e.g., "Shilaa Kesii."
|
||||
# That trailing dot breaks extract_authors(). Avoid this issue by stripping the dot from the ASCII.
|
||||
# Some others have a trailing semicolon (e.g., "உயிரோவியம் தங்கராஐ;") - strip those, too.
|
||||
ascii = factory.LazyAttribute(lambda p: force_text(unidecode_name(p.name)).rstrip(".;"))
|
||||
|
||||
class Params:
|
||||
with_bio = factory.Trait(biography = "\n\n".join(fake.paragraphs())) # type: ignore
|
||||
|
|
|
@ -84,7 +84,7 @@ class Command(BaseCommand):
|
|||
email.origin = email.person.user.username if email.person.user_id else ('script: %s deactivation' % options['reason'])
|
||||
email.save()
|
||||
PersonEvent.objects.create(person=email.person, type='email_address_deactivated',
|
||||
desc="Deactivated the email addres <%s>. Reason: %s" % (email.address, options['reason']) )
|
||||
desc="Deactivated the email address <%s>. Reason: %s" % (email.address, options['reason']) )
|
||||
else:
|
||||
if email is None:
|
||||
not_found.append(a)
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<input type="radio" name="wg_action_status" value="2"> External Review NOT APPROVED;
|
||||
<blockquote>
|
||||
<input type="radio" name="wg_action_status_sub" value="1"> The Secretariat will wait for instructions from <select name="note_draft_by"></select><br>
|
||||
<input type="radio" name="wg_action_status_sub" value="2"> The IESG decides the document needs more thime in INTERNAL REVIEW. The Secreatriat will put it back on the agenda for the next teleconference in the same category.<br>
|
||||
<input type="radio" name="wg_action_status_sub" value="2"> The IESG decides the document needs more time in INTERNAL REVIEW. The Secretariat will put it back on the agenda for the next teleconference in the same category.<br>
|
||||
<input type="radio" name="wg_action_status_sub" value="3"> The IESG has made changes since the charter was seen in INTERNAL REVIEW, and decides to send it back to INTERNAL REVIEW the charter again.
|
||||
</blockquote>
|
||||
{% endif %}
|
||||
|
|
|
@ -18,7 +18,7 @@ warnings.filterwarnings("ignore", message="The logout\(\) view is superseded by"
|
|||
warnings.filterwarnings("ignore", message="Report.file_reporters will no longer be available in Coverage.py 4.2", module="coverage.report")
|
||||
warnings.filterwarnings("ignore", message="{% load staticfiles %} is deprecated")
|
||||
warnings.filterwarnings("ignore", message="Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated", module="bleach")
|
||||
|
||||
warnings.filterwarnings("ignore", message="HTTPResponse.getheader\(\) is deprecated", module='selenium.webdriver')
|
||||
try:
|
||||
import syslog
|
||||
syslog.openlog(str("datatracker"), syslog.LOG_PID, syslog.LOG_USER)
|
||||
|
@ -542,7 +542,7 @@ INTERNAL_IPS = (
|
|||
|
||||
# no slash at end
|
||||
IDTRACKER_BASE_URL = "https://datatracker.ietf.org"
|
||||
RFCDIFF_BASE_URL = "https://www.ietf.org/rfcdiff"
|
||||
RFCDIFF_BASE_URL = "https://author-tools.ietf.org/iddiff"
|
||||
IDNITS_BASE_URL = "https://author-tools.ietf.org/api/idnits"
|
||||
IDNITS_SERVICE_URL = "https://author-tools.ietf.org/idnits"
|
||||
|
||||
|
@ -610,7 +610,7 @@ TEST_TEMPLATE_IGNORE = [
|
|||
"500.html" # isn't loaded by regular loader, but checked by test_500_page()
|
||||
]
|
||||
|
||||
TEST_COVERAGE_MASTER_FILE = os.path.join(BASE_DIR, "../release-coverage.json")
|
||||
TEST_COVERAGE_MAIN_FILE = os.path.join(BASE_DIR, "../release-coverage.json")
|
||||
TEST_COVERAGE_LATEST_FILE = os.path.join(BASE_DIR, "../latest-coverage.json")
|
||||
|
||||
TEST_CODE_COVERAGE_CHECKER = None
|
||||
|
@ -680,7 +680,7 @@ INTERNET_ALL_DRAFTS_ARCHIVE_DIR = '/a/ietfdata/doc/draft/archive'
|
|||
MEETING_RECORDINGS_DIR = '/a/www/audio'
|
||||
DERIVED_DIR = '/a/ietfdata/derived'
|
||||
|
||||
DOCUMENT_FORMAT_WHITELIST = ["txt", "ps", "pdf", "xml", "html", ]
|
||||
DOCUMENT_FORMAT_ALLOWLIST = ["txt", "ps", "pdf", "xml", "html", ]
|
||||
|
||||
# Mailing list info URL for lists hosted on the IETF servers
|
||||
MAILING_LIST_INFO_URL = "https://www.ietf.org/mailman/listinfo/%(list_addr)s"
|
||||
|
|
316
ietf/static/css/document_html.scss
Normal file
316
ietf/static/css/document_html.scss
Normal file
|
@ -0,0 +1,316 @@
|
|||
@use "sass:map";
|
||||
|
||||
// FIXME: It's not clear why these three variables remain unset by bs5, but just
|
||||
// set them to placeholder values so the CSS embedded in the HTML validates.
|
||||
$btn-font-family: inherit !default;
|
||||
$nav-link-font-weight: inherit !default;
|
||||
$tooltip-margin: inherit !default;
|
||||
|
||||
@import "bootstrap/scss/functions";
|
||||
@import "bootstrap/scss/variables";
|
||||
@import "bootstrap/scss/maps";
|
||||
@import "bootstrap/scss/mixins";
|
||||
@import "bootstrap/scss/utilities";
|
||||
@import "bootstrap/scss/root";
|
||||
|
||||
// Layout & components
|
||||
@import "bootstrap/scss/reboot";
|
||||
@import "bootstrap/scss/type";
|
||||
// @import "bootstrap/scss/images";
|
||||
@import "bootstrap/scss/containers";
|
||||
@import "bootstrap/scss/grid";
|
||||
// @import "bootstrap/scss/tables";
|
||||
@import "bootstrap/scss/forms";
|
||||
@import "bootstrap/scss/buttons";
|
||||
@import "bootstrap/scss/transitions";
|
||||
// @import "bootstrap/scss/dropdown";
|
||||
@import "bootstrap/scss/button-group";
|
||||
@import "bootstrap/scss/nav";
|
||||
@import "bootstrap/scss/navbar";
|
||||
// @import "bootstrap/scss/card";
|
||||
// @import "bootstrap/scss/accordion";
|
||||
// @import "bootstrap/scss/breadcrumb";
|
||||
@import "bootstrap/scss/pagination";
|
||||
@import "bootstrap/scss/badge";
|
||||
@import "bootstrap/scss/alert";
|
||||
// @import "bootstrap/scss/progress";
|
||||
// @import "bootstrap/scss/list-group";
|
||||
// @import "bootstrap/scss/close";
|
||||
// @import "bootstrap/scss/toasts";
|
||||
// @import "bootstrap/scss/modal";
|
||||
@import "bootstrap/scss/tooltip";
|
||||
// @import "bootstrap/scss/popover";
|
||||
// @import "bootstrap/scss/carousel";
|
||||
// @import "bootstrap/scss/spinners";
|
||||
// @import "bootstrap/scss/offcanvas";
|
||||
// @import "bootstrap/scss/placeholders";
|
||||
|
||||
// Helpers
|
||||
@import "bootstrap/scss/helpers";
|
||||
|
||||
// Utilities
|
||||
@import "bootstrap/scss/utilities/api";
|
||||
|
||||
:root {
|
||||
--doc-ptsize-max: 16pt;
|
||||
}
|
||||
|
||||
.overscroll-none {
|
||||
overscroll-behavior: none;
|
||||
}
|
||||
|
||||
.no-scrollbar {
|
||||
scrollbar-width: none;
|
||||
}
|
||||
|
||||
.sidebar-toggle[aria-expanded="true"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidebar-toggle[aria-expanded="false"] {
|
||||
display: inherit;
|
||||
}
|
||||
|
||||
@media screen {
|
||||
@include media-breakpoint-down(md) {
|
||||
body {
|
||||
padding-top: 60px;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-padding-top: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
body {
|
||||
padding-top: 70px;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-padding-top: 70px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rfcmarkup,
|
||||
.rfchtml {
|
||||
font-family: var(--bs-font-monospace);
|
||||
|
||||
caption {
|
||||
padding: 0;
|
||||
color: var(--bs-body-color);
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 1em;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
@media screen {
|
||||
@include media-breakpoint-only(xs) {
|
||||
font-size: min(7pt, var(--doc-ptsize-max));
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
font-size: min(9.5pt, var(--doc-ptsize-max));
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
font-size: min(9.5pt, var(--doc-ptsize-max));
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(lg) {
|
||||
font-size: min(11pt, var(--doc-ptsize-max));
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(xl) {
|
||||
font-size: min(13pt, var(--doc-ptsize-max));
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(xxl) {
|
||||
font-size: min(16pt, var(--doc-ptsize-max));
|
||||
}
|
||||
|
||||
.grey,
|
||||
hr {
|
||||
opacity: $hr-opacity;
|
||||
}
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-weight: bold;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
pre,
|
||||
code {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
width: 72ch;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.bcp14 {
|
||||
font-weight: bold;
|
||||
// color: $gray-700;
|
||||
}
|
||||
}
|
||||
|
||||
.rfcmarkup {
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
white-space: pre;
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
|
||||
tbody.meta tr {
|
||||
|
||||
td:first-child,
|
||||
th:first-child,
|
||||
td.edit {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
height: 100vh;
|
||||
|
||||
.toplink,
|
||||
#name-table-of-contents {
|
||||
display: none;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
display: block;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
td {
|
||||
margin-bottom: map.get($spacers, 3);
|
||||
}
|
||||
}
|
||||
|
||||
// Add some padding when there are multiple buttons in a line that can wrap
|
||||
.buttonlist .btn {
|
||||
margin-bottom: map.get($spacers, 1);
|
||||
}
|
||||
|
||||
// Make revision numbers pagination items fixed-width
|
||||
.revision-list {
|
||||
.page-item {
|
||||
width: 2.2rem;
|
||||
}
|
||||
|
||||
.page-item.rfc {
|
||||
width: 6.6rem;
|
||||
}
|
||||
}
|
||||
|
||||
#docinfo {
|
||||
max-height: 70vh;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
|
||||
.badge-obs {
|
||||
color: white;
|
||||
background-color: $orange-800;
|
||||
}
|
||||
|
||||
.badge-ps {
|
||||
color: black;
|
||||
background-color: $blue-300;
|
||||
}
|
||||
|
||||
.badge-exp {
|
||||
color: black;
|
||||
background-color: $yellow-200;
|
||||
}
|
||||
|
||||
.badge-inf {
|
||||
color: white;
|
||||
background-color: $orange;
|
||||
}
|
||||
|
||||
.badge-ds {
|
||||
color: black;
|
||||
background-color: $cyan-200;
|
||||
}
|
||||
|
||||
.badge-hist {
|
||||
color: white;
|
||||
background-color: $gray-700;
|
||||
}
|
||||
|
||||
.badge-std {
|
||||
color: black;
|
||||
background-color: $teal-200;
|
||||
}
|
||||
|
||||
.badge-bcp {
|
||||
color: white;
|
||||
background-color: $pink-500;
|
||||
}
|
||||
|
||||
.badge-unkn {
|
||||
color: black;
|
||||
background-color: $gray-300;
|
||||
}
|
||||
|
||||
.badge-draft {
|
||||
color: white;
|
||||
background-color: $danger;
|
||||
}
|
||||
|
||||
#toc-nav {
|
||||
width: inherit;
|
||||
overscroll-behavior-y: none; // Prevent overscrolling from scrolling the main content
|
||||
}
|
||||
|
||||
|
||||
@media print {
|
||||
@page {
|
||||
size: letter;
|
||||
margin: .75in;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
pre {
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
||||
a:link,
|
||||
a:visited {
|
||||
// color: inherit;
|
||||
// text-decoration: none;
|
||||
}
|
||||
|
||||
.newpage {
|
||||
page-break-before: always !important;
|
||||
}
|
||||
|
||||
.noprint {
|
||||
display: none;
|
||||
}
|
||||
}
|
6
ietf/static/css/document_html_inline.scss
Normal file
6
ietf/static/css/document_html_inline.scss
Normal file
|
@ -0,0 +1,6 @@
|
|||
@import "document_html";
|
||||
|
||||
// Make the bootstrap icons available via data-url.
|
||||
$bootstrap-icons-font-src: url(data-url:npm:bootstrap-icons/font/fonts/bootstrap-icons.woff2) format("woff2"),
|
||||
url(data-url:npm:bootstrap-icons/font/fonts/bootstrap-icons.woff) format("woff");
|
||||
@import "bootstrap-icons/font/bootstrap-icons";
|
6
ietf/static/css/document_html_referenced.scss
Normal file
6
ietf/static/css/document_html_referenced.scss
Normal file
|
@ -0,0 +1,6 @@
|
|||
@import "document_html";
|
||||
|
||||
// Make the bootstrap icons available.
|
||||
$bootstrap-icons-font-src: url("npm:bootstrap-icons/font/fonts/bootstrap-icons.woff2") format("woff2"),
|
||||
url("npm:bootstrap-icons/font/fonts/bootstrap-icons.woff") format("woff");
|
||||
@import "bootstrap-icons/font/bootstrap-icons";
|
381
ietf/static/css/document_html_txt.scss
Normal file
381
ietf/static/css/document_html_txt.scss
Normal file
|
@ -0,0 +1,381 @@
|
|||
:root {
|
||||
--line: 1.2em;
|
||||
--block: 0 0 0 3ch;
|
||||
--paragraph: var(--line) 0 var(--line) 3ch;
|
||||
}
|
||||
|
||||
// WeasyPrint can't handle CSS variables in multi-attribute properties, so work
|
||||
// around that
|
||||
// https://github.com/Kozea/WeasyPrint/issues/1219
|
||||
|
||||
@mixin margin-paragraph {
|
||||
margin-top: var(--line);
|
||||
margin-right: 0;
|
||||
margin-bottom: var(--line);
|
||||
margin-left: 3ch;
|
||||
}
|
||||
|
||||
@mixin margin-line {
|
||||
margin-top: var(--line);
|
||||
margin-right: 0;
|
||||
margin-bottom: var(--line);
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
@mixin margin-block {
|
||||
margin-top: 0;
|
||||
margin-right: 0;
|
||||
margin-bottom: 0;
|
||||
margin-left: 3ch;
|
||||
}
|
||||
|
||||
.rfchtml {
|
||||
// body {
|
||||
// color: black;
|
||||
// font-family: monospace;
|
||||
// font-size: 1em;
|
||||
line-height: var(--line);
|
||||
width: 72ch;
|
||||
|
||||
// margin: var(--line) 3ch;
|
||||
margin-top: var(--line);
|
||||
margin-right: 3ch;
|
||||
margin-bottom: var(--line);
|
||||
margin-left: 3ch;
|
||||
|
||||
h1, h2, h3, h4, h5 {
|
||||
font-weight: bold;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
// margin: var(--line) 0;
|
||||
@include margin-line;
|
||||
}
|
||||
.section-number {
|
||||
margin-right: 1ch;
|
||||
}
|
||||
p {
|
||||
// margin: var(--paragraph);
|
||||
@include margin-paragraph;
|
||||
}
|
||||
aside, ol, dl {
|
||||
// margin: var(--block);
|
||||
@include margin-block;
|
||||
}
|
||||
figure {
|
||||
margin: 0;
|
||||
}
|
||||
blockquote {
|
||||
// margin: var(--paragraph);
|
||||
@include margin-paragraph;
|
||||
border-left: 2px solid darkgrey;
|
||||
}
|
||||
|
||||
// Don't wrap boilerplate URLs; makes it look more like text version.
|
||||
:is(#status-of-memo, #copyright) a[href] {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Header junk */
|
||||
#external-metadata {
|
||||
display: none !important; /* metadata.min.js is evil because it produces unstyleable goop */
|
||||
}
|
||||
#identifiers dt:is(.label-stream, .label-rfc, .label-std, .label-bcp, .label-internet-draft,
|
||||
.label-workgroup, .label-intended-status, .label-obsoletes, .label-updates,
|
||||
.label-published, .label-expires, .label-category, .label-issn,
|
||||
.label-authors), .ears {
|
||||
display: none;
|
||||
}
|
||||
#identifiers {
|
||||
margin: 0;
|
||||
display: grid;
|
||||
grid-template-columns: 47ch 24ch;
|
||||
grid-auto-rows: auto;
|
||||
gap: 0 1ch;
|
||||
}
|
||||
#identifiers dt {
|
||||
margin: 0 1ch 0 0;
|
||||
float: revert;
|
||||
display: inline-block;
|
||||
}
|
||||
#identifiers dd {
|
||||
grid-column: 1;
|
||||
margin: 0;
|
||||
width: 47ch;
|
||||
/* HAXX: this gets around the lack of text-content-trim support */
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
#identifiers dd::before {
|
||||
margin: 0 1ch 0 0;
|
||||
}
|
||||
#identifiers dd.rfc::before {
|
||||
content: "Request for Comments:";
|
||||
}
|
||||
#identifiers dd.std::before {
|
||||
content: "STD:";
|
||||
}
|
||||
#identifiers dd.bcp::before {
|
||||
content: "BCP:";
|
||||
}
|
||||
#identifiers dd.internet-draft::before {
|
||||
content: "Internet-Draft:";
|
||||
}
|
||||
#identifiers dd.workgroup::before {
|
||||
content: "Workgroup:";
|
||||
}
|
||||
#identifiers dd.intended-status::before {
|
||||
content: "Intended Status:";
|
||||
}
|
||||
#identifiers dd.obsoletes::before {
|
||||
content: "Obsoletes:";
|
||||
margin: 0 0 0 -10ch;
|
||||
}
|
||||
#identifiers dd.obsoletes {
|
||||
padding-left: 10ch;
|
||||
width: 37ch;
|
||||
}
|
||||
#identifiers dd.updates::before {
|
||||
content: "Updates:";
|
||||
margin: 0 0 0 -8ch;
|
||||
}
|
||||
#identifiers dd.updates {
|
||||
padding-left: 8ch;
|
||||
width: 39ch;
|
||||
}
|
||||
#identifiers dd:is(.updates, .obsoletes) a {
|
||||
margin: 0 0 0 1ch;
|
||||
}
|
||||
#identifiers dd:is(.updates, .obsoletes) a:last-of-type {
|
||||
margin: 0 1ch;
|
||||
}
|
||||
#identifiers dd.published::before {
|
||||
content: "Published:";
|
||||
}
|
||||
#identifiers dd.expires::before {
|
||||
content: "Expires:";
|
||||
}
|
||||
#identifiers dd.category::before {
|
||||
content: "Category:";
|
||||
}
|
||||
#identifiers dd.issn::before {
|
||||
content: "ISSN:";
|
||||
}
|
||||
#identifiers dd.authors {
|
||||
grid-area: 1 / 2 / 100 / 3;
|
||||
width: 24ch;
|
||||
text-align: right;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#title {
|
||||
clear: left;
|
||||
text-align: center;
|
||||
margin-top: 2em;
|
||||
}
|
||||
#rfcnum {
|
||||
display: none;
|
||||
}
|
||||
.toplink {
|
||||
display: none;
|
||||
}
|
||||
nav.toc ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
nav.toc ul > li {
|
||||
padding-left: 2ch;
|
||||
}
|
||||
nav.toc > ul > li {
|
||||
padding-left: 3ch;
|
||||
}
|
||||
nav.toc ul > li > p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Lists */
|
||||
ol, ul {
|
||||
padding: 0;
|
||||
}
|
||||
ol {
|
||||
margin: 0 0 0 6ch; /* todo: deal with lists that have >= 10 items */
|
||||
}
|
||||
ol ol, ul ol {
|
||||
margin: 0 0 0 3ch;
|
||||
}
|
||||
ul {
|
||||
margin: 0 0 0 4ch;
|
||||
list-style-type: '*';
|
||||
}
|
||||
ul ul {
|
||||
list-style-type: '-';
|
||||
}
|
||||
ul ul, ol ul {
|
||||
margin-left: 1ch;
|
||||
}
|
||||
ul ul ul {
|
||||
list-style-type: 'o';
|
||||
}
|
||||
li {
|
||||
// margin: var(--line) 0;
|
||||
@include margin-line;
|
||||
padding: 0 0 0 2ch;
|
||||
}
|
||||
.compact li {
|
||||
margin: 0;
|
||||
}
|
||||
li p:first-child, dd p:first-child {
|
||||
margin: 0;
|
||||
}
|
||||
dt {
|
||||
float: left;
|
||||
clear: left;
|
||||
margin: 0 2ch 0 0;
|
||||
break-after: avoid;
|
||||
}
|
||||
dd {
|
||||
// margin: var(--paragraph);
|
||||
@include margin-paragraph;
|
||||
break-before: avoid;
|
||||
}
|
||||
dl.compact dt, dl.compact dd {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
dl.references dt {
|
||||
margin-right: 1ch;
|
||||
}
|
||||
dl.references dd {
|
||||
margin-left: 11ch;
|
||||
}
|
||||
dd.break {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Figures, tables */
|
||||
pre {
|
||||
// margin: var(--line) 0;
|
||||
@include margin-line;
|
||||
}
|
||||
div.artwork, div.sourcecode {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
align-items: end;
|
||||
}
|
||||
div.artwork.alignCenter, div.sourcecode.alignCenter {
|
||||
justify-content: center;
|
||||
}
|
||||
div.artwork.alignRight, div.sourcecode.alignRight {
|
||||
justify-content: end;
|
||||
}
|
||||
div.artwork::before, div.sourcecode::before {
|
||||
flex: 0 1 3ch;
|
||||
content: "";
|
||||
}
|
||||
div.artwork.alignRight::before, div.sourcecode.alignRight::before {
|
||||
flex-grow: 1;
|
||||
}
|
||||
div.artwork pre, div.sourcecode pre {
|
||||
flex: 0 0 content;
|
||||
margin: 0;
|
||||
max-width: 72ch;
|
||||
overflow: auto;
|
||||
}
|
||||
div.artwork .pilcrow, div.sourcecode .pilcrow {
|
||||
flex: 0 0 1ch;
|
||||
}
|
||||
figcaption, table caption {
|
||||
text-align: center;
|
||||
margin-top: var(--line);
|
||||
}
|
||||
table {
|
||||
--half-line: calc(var(--line) / 2 - 1px);
|
||||
caption-side: bottom;
|
||||
// margin: var(--line) 0 var(--half-line) 3ch;
|
||||
margin-top: var(--line);
|
||||
margin-right: 0;
|
||||
margin-bottom: var(--half-line);
|
||||
margin-left: 3ch;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table.center {
|
||||
margin-left: auto; /* todo: add 3ch */
|
||||
margin-right: auto;
|
||||
}
|
||||
table caption {
|
||||
margin-top: calc(var(--half-line) + var(--line));
|
||||
}
|
||||
thead, tfoot {
|
||||
border-top-style: double;
|
||||
border-bottom-style: double;
|
||||
}
|
||||
td, th {
|
||||
border: 1px solid black;
|
||||
// padding: var(--half-line) 1ch;
|
||||
padding-top: var(--half-line);
|
||||
padding-right: 1ch;
|
||||
padding-bottom: var(--half-line);
|
||||
padding-left: 1ch;
|
||||
}
|
||||
.text-left {
|
||||
text-align: left;
|
||||
}
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* Links */
|
||||
a.selfRef, a.pilcrow {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
}
|
||||
a.relref, a.xref {
|
||||
hyphens: none;
|
||||
}
|
||||
a.relref, a.xref.cite {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.pilcrow {
|
||||
display: inline-block;
|
||||
margin-right: -1ch;
|
||||
opacity: 0.01;
|
||||
text-decoration: none;
|
||||
}
|
||||
:hover > .pilcrow {
|
||||
opacity: 0.2;
|
||||
}
|
||||
* > .pilcrow[href]:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
/* sup, sub */
|
||||
sup, sub {
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
/* Authors */
|
||||
address {
|
||||
font-style: normal;
|
||||
// margin: 2em 0 var(--line) 3ch;
|
||||
margin-top: 2em;
|
||||
margin-right: 0;
|
||||
margin-bottom: var(--line);
|
||||
margin-left: 3ch;
|
||||
}
|
||||
h2 + address {
|
||||
margin-top: 1em;
|
||||
}
|
||||
address .tel, address .email {
|
||||
// margin: var(--line) 0 0;
|
||||
margin-top: var(--line);
|
||||
margin-right: 0;
|
||||
margin-bottom: 0;
|
||||
margin-left: 0;
|
||||
}
|
||||
address .tel + .email {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
|
@ -168,8 +168,9 @@ table tbody.meta {
|
|||
}
|
||||
}
|
||||
|
||||
// Try and hyphenate table headings
|
||||
th {
|
||||
// Try and hyphenate table headings and other things
|
||||
th,
|
||||
.hyphenate {
|
||||
hyphens: auto;
|
||||
}
|
||||
|
||||
|
@ -208,6 +209,17 @@ th {
|
|||
max-width: 300px;
|
||||
}
|
||||
|
||||
// Make revision numbers pagination items fixed-width
|
||||
.revision-list {
|
||||
.page-item {
|
||||
width: 2.2rem;
|
||||
}
|
||||
|
||||
.page-item.rfc {
|
||||
width: 6.6rem;
|
||||
}
|
||||
}
|
||||
|
||||
// Style the photo cards
|
||||
.photo {
|
||||
width: 12em;
|
||||
|
|
|
@ -3,21 +3,3 @@
|
|||
@import "bootstrap/scss/mixins";
|
||||
@import "select2/src/scss/core";
|
||||
@import "select2-bootstrap-5-theme/src/include-all";
|
||||
|
||||
// Propagate readonly property from input to select2 instrumentation, based on
|
||||
// https://stackoverflow.com/questions/41807096/select2-make-it-readonly-not-disabled-from-js/55001516#55001516
|
||||
select[readonly].select2-hidden-accessible + .select2-container {
|
||||
pointer-events: none;
|
||||
touch-action: none;
|
||||
|
||||
.select2-selection {
|
||||
background: $form-select-disabled-bg;
|
||||
color: $form-select-disabled-color;
|
||||
border-color: $form-select-disabled-border-color;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.select2-selection__arrow, .select2-selection__clear {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1,76 @@
|
|||
<svg width="765" height="990" style="display:inline" xmlns="http://www.w3.org/2000/svg"><g style="display:inline"><text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:400;font-stretch:normal;line-height:0%;font-family:'Arial Black';-inkscape-font-specification:'Arial Black,';text-align:start;letter-spacing:0;word-spacing:0;writing-mode:lr-tb;text-anchor:start;fill:#fff;fill-opacity:1;stroke:#000;stroke-width:1.908;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" x="250.217" y="565.473" transform="translate(0 -62.362)"><tspan x="250.217" y="565.473" style="font-size:102.5px;line-height:1.25">R</tspan></text><path style="fill:#bdbcbc;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m134.869 273.355-44.033 44.031 44.033 44.034 44.032-44.034-44.032-44.03m519.185-.001-44.032 44.031 44.032 44.034 44.031-44.034-44.03-44.03m-311.778-.001-44.032 44.031 44.032 44.034 44.032-44.034-44.032-44.03m103.693-.001-44.032 44.031 44.032 44.034 44.032-44.034-44.032-44.03m103.693-.001-44.032 44.031 44.032 44.034 44.033-44.034-44.033-44.03M290.8 325.407l-44.032 44.032 44.032 44.032 44.032-44.032-44.032-44.032m-52.217-52.052-44.033 44.031 44.033 44.034 44.033-44.034-44.033-44.03m155.911 52.051-44.032 44.032 44.032 44.032 44.032-44.032-44.032-44.032m103.693 0-44.032 44.032 44.032 44.032 44.032-44.032-44.032-44.032M290.8 221.827l-44.032 44.03 44.032 44.034 44.032-44.033-44.032-44.031m103.694 0-44.032 44.03 44.032 44.034 44.032-44.033-44.032-44.031m103.693 0-44.032 44.03 44.032 44.034 44.032-44.033-44.032-44.031" transform="translate(0 -62.362)"/><path style="fill:#fccf34;fill-opacity:1;fill-rule:nonzero;stroke:none" d="M98.431 312.254h90.633l49.886 49.886 51.52-51.52 51.807 51.807 104.12-104.12 52.06 52.059 51.52-51.52 53.948 53.949H692.4v10.248h-92.79l-49.903-49.901-51.79 51.79-51.79-51.79-103.58 103.581-51.79-51.792-51.52 51.522-54.22-54.22H97.89l.54-9.98" transform="translate(0 -62.362)"/><path style="fill:none;stroke:#0c0a08;stroke-width:1.90799999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" d="M98.431 312.254h90.633l49.886 49.886 51.52-51.52 51.807 51.807 104.12-104.12 52.06 52.059 51.52-51.52 53.948 53.949H692.4v10.248h-92.79l-49.903-49.901-51.79 51.79-51.79-51.79-103.58 103.581-51.79-51.792-51.52 51.522-54.22-54.22H97.89l.54-9.98z" transform="translate(0 -62.362)"/><path style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none" d="M79.997 327.492h21.04v-19.421h-21.04v19.421zm606.244 0h21.04v-19.421h-21.04v19.421zM98.468 565.473h25.715v-73.378H98.468v73.378zm341.277-54.979v-18.399h71.55v18.399h-22.919v54.979h-25.714v-54.98h-22.917m200.334-18.398h53.58v15.494h-27.867v13.34h26.145v15.495h-26.145v29.049H640.08v-73.378" transform="translate(0 -62.362)"/><path style="fill:#fff;fill-opacity:1;stroke:#000;stroke-width:1.90800011;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" d="m446.283 169.434-29.062 29.06 29.062 29.062 29.06-29.062-29.06-29.06m-111.179 7.485-29.061 29.06 29.06 29.062 29.062-29.062-29.061-29.06m-148.231 44.032-29.061 29.06 29.061 29.063 29.061-29.062-29.061-29.06m37.408 171.686-29.061 29.06 29.061 29.063 29.061-29.062-29.06-29.06m222.358-14.971-29.061 29.06 29.06 29.062 29.062-29.062-29.061-29.06m155.211-22.201-29.061 29.06 29.061 29.062 29.061-29.062-29.061-29.06M224.145 184.184l-14.531 14.53 14.53 14.531 14.531-14.53-14.53-14.531m52.217-22.027-14.53 14.53 14.53 14.531 14.53-14.531-14.53-14.53m14.751-44.252-14.531 14.53 14.53 14.531 14.531-14.53-14.53-14.531m74.192 29.501-14.531 14.53 14.531 14.53 14.53-14.53-14.53-14.53m118.444-14.751-14.531 14.53 14.53 14.531 14.532-14.53-14.531-14.53m29.501 29.501-14.53 14.53 14.53 14.531 14.53-14.531-14.53-14.53m51.477 22.027-14.531 14.53 14.53 14.531 14.531-14.53-14.53-14.531M201.855 369.897l-14.531 14.53 14.53 14.531 14.531-14.53-14.53-14.531m89.615 59.823-14.531 14.53 14.531 14.53L306 444.25l-14.53-14.53m103.693 0-14.53 14.53 14.53 14.53 14.53-14.53-14.53-14.53m140.42-37.302-14.531 14.53 14.53 14.531 14.531-14.53-14.53-14.53m-36.726 37.301-14.531 14.53 14.53 14.53 14.531-14.53-14.53-14.53m-140.94-37.082-29.06 29.06 29.06 29.063 29.062-29.062-29.062-29.06m243.488-171.688-14.531 14.53 14.53 14.532 14.531-14.531-14.53-14.53m-28.713-73.546-14.531 14.53 14.53 14.53 14.531-14.53-14.53-14.53" transform="translate(0 -62.362)"/></g></svg>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="627.284"
|
||||
height="449.19662"
|
||||
style="display:inline"
|
||||
version="1.1"
|
||||
id="svg303"
|
||||
sodipodi:docname="irtf-logo.svg"
|
||||
inkscape:version="1.2.1 (9c6d41e4, 2022-07-14)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs307" />
|
||||
<sodipodi:namedview
|
||||
id="namedview305"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.0373737"
|
||||
inkscape:cx="304.1334"
|
||||
inkscape:cy="446.80136"
|
||||
inkscape:window-width="1797"
|
||||
inkscape:window-height="1083"
|
||||
inkscape:window-x="951"
|
||||
inkscape:window-y="445"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg303" />
|
||||
<g
|
||||
style="display:inline"
|
||||
id="g301"
|
||||
transform="translate(-79.997,-54.868397)">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:400;font-stretch:normal;line-height:0%;font-family:'Arial Black';-inkscape-font-specification:'Arial Black,';text-align:start;letter-spacing:0;word-spacing:0;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.908;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
x="250.217"
|
||||
y="565.47302"
|
||||
transform="translate(0,-62.362)"
|
||||
id="text289"><tspan
|
||||
x="250.217"
|
||||
y="565.47302"
|
||||
style="font-size:102.5px;line-height:1.25"
|
||||
id="tspan287">R</tspan></text>
|
||||
<path
|
||||
style="fill:#bdbcbc;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 134.869,273.355 -44.033,44.031 44.033,44.034 44.032,-44.034 -44.032,-44.03 m 519.185,-10e-4 -44.032,44.031 44.032,44.034 44.031,-44.034 -44.03,-44.03 m -311.778,-10e-4 -44.032,44.031 44.032,44.034 44.032,-44.034 -44.032,-44.03 m 103.693,-10e-4 -44.032,44.031 44.032,44.034 44.032,-44.034 -44.032,-44.03 m 103.693,-10e-4 -44.032,44.031 44.032,44.034 44.033,-44.034 -44.033,-44.03 M 290.8,325.407 246.768,369.439 290.8,413.471 334.832,369.439 290.8,325.407 m -52.217,-52.052 -44.033,44.031 44.033,44.034 44.033,-44.034 -44.033,-44.03 m 155.911,52.051 -44.032,44.032 44.032,44.032 44.032,-44.032 -44.032,-44.032 m 103.693,0 -44.032,44.032 44.032,44.032 44.032,-44.032 -44.032,-44.032 M 290.8,221.827 246.768,265.857 290.8,309.891 334.832,265.858 290.8,221.827 m 103.694,0 -44.032,44.03 44.032,44.034 44.032,-44.033 -44.032,-44.031 m 103.693,0 -44.032,44.03 44.032,44.034 44.032,-44.033 -44.032,-44.031"
|
||||
transform="translate(0,-62.362)"
|
||||
id="path291" />
|
||||
<path
|
||||
style="fill:#fccf34;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 98.431,312.254 h 90.633 l 49.886,49.886 51.52,-51.52 51.807,51.807 104.12,-104.12 52.06,52.059 51.52,-51.52 53.948,53.949 H 692.4 v 10.248 h -92.79 l -49.903,-49.901 -51.79,51.79 -51.79,-51.79 -103.58,103.581 -51.79,-51.792 -51.52,51.522 -54.22,-54.22 H 97.89 l 0.54,-9.98"
|
||||
transform="translate(0,-62.362)"
|
||||
id="path293" />
|
||||
<path
|
||||
style="fill:none;stroke:#0c0a08;stroke-width:1.908;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 98.431,312.254 h 90.633 l 49.886,49.886 51.52,-51.52 51.807,51.807 104.12,-104.12 52.06,52.059 51.52,-51.52 53.948,53.949 H 692.4 v 10.248 h -92.79 l -49.903,-49.901 -51.79,51.79 -51.79,-51.79 -103.58,103.581 -51.79,-51.792 -51.52,51.522 -54.22,-54.22 H 97.89 l 0.54,-9.98 z"
|
||||
transform="translate(0,-62.362)"
|
||||
id="path295" />
|
||||
<path
|
||||
style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
d="m 79.997,327.492 h 21.04 v -19.421 h -21.04 z m 606.244,0 h 21.04 v -19.421 h -21.04 z M 98.468,565.473 h 25.715 V 492.095 H 98.468 Z m 341.277,-54.979 v -18.399 h 71.55 v 18.399 h -22.919 v 54.979 h -25.714 v -54.98 h -22.917 m 200.334,-18.398 h 53.58 v 15.494 h -27.867 v 13.34 h 26.145 v 15.495 h -26.145 v 29.049 H 640.08 v -73.378"
|
||||
transform="translate(0,-62.362)"
|
||||
id="path297" />
|
||||
<path
|
||||
style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.908;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 446.283,169.434 -29.062,29.06 29.062,29.062 29.06,-29.062 -29.06,-29.06 m -111.179,7.485 -29.061,29.06 29.06,29.062 29.062,-29.062 -29.061,-29.06 m -148.231,44.032 -29.061,29.06 29.061,29.063 29.061,-29.062 -29.061,-29.06 m 37.408,171.686 -29.061,29.06 29.061,29.063 29.061,-29.062 -29.06,-29.06 m 222.358,-14.971 -29.061,29.06 29.06,29.062 29.062,-29.062 -29.061,-29.06 m 155.211,-22.201 -29.061,29.06 29.061,29.062 29.061,-29.062 -29.061,-29.06 m -377.706,-171.283 -14.531,14.53 14.53,14.531 14.531,-14.53 -14.53,-14.531 m 52.217,-22.027 -14.53,14.53 14.53,14.531 14.53,-14.531 -14.53,-14.53 m 14.751,-44.252 -14.531,14.53 14.53,14.531 14.531,-14.53 -14.53,-14.531 m 74.192,29.501 -14.531,14.53 14.531,14.53 14.53,-14.53 -14.53,-14.53 m 118.444,-14.751 -14.531,14.53 14.53,14.531 14.532,-14.53 -14.531,-14.53 m 29.501,29.501 -14.53,14.53 14.53,14.531 14.53,-14.531 -14.53,-14.53 m 51.477,22.027 -14.531,14.53 14.53,14.531 14.531,-14.53 -14.53,-14.531 m -362.872,185.713 -14.531,14.53 14.53,14.531 14.531,-14.53 -14.53,-14.531 m 89.615,59.823 -14.531,14.53 14.531,14.53 14.53,-14.53 -14.53,-14.53 m 103.693,0 -14.53,14.53 14.53,14.53 14.53,-14.53 -14.53,-14.53 m 140.42,-37.302 -14.531,14.53 14.53,14.531 14.531,-14.53 -14.53,-14.53 m -36.726,37.301 -14.531,14.53 14.53,14.53 14.531,-14.53 -14.53,-14.53 m -140.94,-37.082 -29.06,29.06 29.06,29.063 29.062,-29.062 -29.062,-29.06 m 243.488,-171.688 -14.531,14.53 14.53,14.532 14.531,-14.531 -14.53,-14.53 m -28.713,-73.546 -14.531,14.53 14.53,14.53 14.531,-14.53 -14.53,-14.53"
|
||||
transform="translate(0,-62.362)"
|
||||
id="path299" />
|
||||
</g>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 6 KiB |
71
ietf/static/js/document_html.js
Normal file
71
ietf/static/js/document_html.js
Normal file
|
@ -0,0 +1,71 @@
|
|||
import {
|
||||
Tooltip as Tooltip,
|
||||
// Button as Button,
|
||||
// Collapse as Collapse,
|
||||
// ScrollSpy as ScrollSpy,
|
||||
Tab as Tab
|
||||
} from "bootstrap";
|
||||
|
||||
import Cookies from "js-cookie";
|
||||
import { populate_nav } from "./nav.js";
|
||||
|
||||
const cookies = Cookies.withAttributes({ sameSite: "strict" });
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function (event) {
|
||||
// handle point size slider
|
||||
const cookie = "doc-ptsize-max";
|
||||
|
||||
function change_ptsize(ptsize) {
|
||||
document.documentElement.style.setProperty(`--${cookie}`,
|
||||
`${ptsize}pt`);
|
||||
cookies.set(cookie, ptsize);
|
||||
}
|
||||
|
||||
document.getElementById("ptsize")
|
||||
.oninput = function () { change_ptsize(this.value) };
|
||||
|
||||
const ptsize = cookies.get(cookie);
|
||||
change_ptsize(ptsize ? Math.min(Math.max(7, ptsize), 16) : 12);
|
||||
|
||||
// Use the Bootstrap tooltip plugin for all elements with a title attribute
|
||||
const tt_triggers = document.querySelectorAll(
|
||||
"[title]:not([title=''])");
|
||||
[...tt_triggers].map(tt_el => {
|
||||
const tooltip = Tooltip.getOrCreateInstance(tt_el);
|
||||
tt_el.addEventListener("click", el => {
|
||||
tooltip.hide();
|
||||
tt_el.blur();
|
||||
});
|
||||
});
|
||||
|
||||
// Set up a nav pane
|
||||
const toc_pane = document.getElementById("toc-nav");
|
||||
populate_nav(toc_pane,
|
||||
`#content h2, #content h3, #content h4, #content h5, #content h6
|
||||
#content .h1, #content .h2, #content .h3, #content .h4, #content .h5, #content .h6`,
|
||||
["py-0"]);
|
||||
|
||||
// activate pref buttons selected by pref cookies
|
||||
document.querySelectorAll(".btn-check")
|
||||
.forEach(btn => {
|
||||
const id = btn.id.replace("-radio", "");
|
||||
if (cookies.get(btn.name) == id) {
|
||||
btn.checked = true;
|
||||
}
|
||||
btn.addEventListener("click", el => {
|
||||
cookies.set(btn.name, id);
|
||||
window.location.reload();
|
||||
});
|
||||
});
|
||||
|
||||
// activate tab selected in prefs
|
||||
let defpane;
|
||||
try {
|
||||
defpane = Tab.getOrCreateInstance(
|
||||
`#${cookies.get("deftab")}-tab`);
|
||||
} catch (err) {
|
||||
defpane = Tab.getOrCreateInstance("#docinfo-tab");
|
||||
};
|
||||
defpane.show();
|
||||
document.activeElement.blur();
|
||||
});
|
|
@ -315,7 +315,7 @@ function draw_graph(data, group) {
|
|||
})
|
||||
];
|
||||
|
||||
// // See https://github.com/d3/d3-force/blob/master/README.md#simulation_tick
|
||||
// // See https://github.com/d3/d3-force/blob/main/README.md#simulation_tick
|
||||
// for (let i = 0, n = Math.ceil(Math.log(simulation.alphaMin()) /
|
||||
// Math.log(1 - simulation.alphaDecay())); i <
|
||||
// n; ++i) {
|
||||
|
|
|
@ -24,7 +24,7 @@ if (!process.env.BUILD_DEPLOY) {
|
|||
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
import debounce from "lodash/debounce";
|
||||
import { populate_nav } from "./nav.js";
|
||||
|
||||
// setup CSRF protection using jQuery
|
||||
function csrfSafeMethod(method) {
|
||||
|
@ -154,9 +154,9 @@ $(document)
|
|||
$(function () {
|
||||
const contentElement = $('#content.ietf-auto-nav');
|
||||
if (contentElement.length > 0) {
|
||||
const heading_selector = "h2:not([style='display:none']):not(.navskip), h3:not([style='display:none']):not(.navskip), h4:not([style='display:none']):not(.navskip), h5:not([style='display:none']):not(.navskip), h6:not([style='display:none']):not(.navskip), .nav-heading:not([style='display:none']):not(.navskip)";
|
||||
const headings = contentElement
|
||||
.find("h1:visible, h2:visible, h3:visible, h4:visible, h5:visible, h6:visible, .nav-heading:visible")
|
||||
.not(".navskip");
|
||||
.find(heading_selector);
|
||||
|
||||
const contents = (headings.length > 0) &&
|
||||
($(headings)
|
||||
|
@ -178,8 +178,6 @@ $(function () {
|
|||
|
||||
if (pageTooTall || haveExtraNav) {
|
||||
// console.log("Enabling nav.");
|
||||
let n = 0;
|
||||
let last_level;
|
||||
|
||||
contentElement
|
||||
.attr("data-bs-offset", 0)
|
||||
|
@ -197,48 +195,7 @@ $(function () {
|
|||
.children()
|
||||
.last();
|
||||
|
||||
contentElement
|
||||
.find("h1:visible, h2:visible, h3:visible, h4:visible, h5:visible, h6:visible, .nav-heading:visible")
|
||||
.not(".navskip")
|
||||
.each(function () {
|
||||
// Some headings have line breaks in them - only use first line in that case.
|
||||
const frag = $(this)
|
||||
.html()
|
||||
.split("<br")
|
||||
.shift();
|
||||
const text = $.parseHTML(frag)
|
||||
.map(x => $(x)
|
||||
.text())
|
||||
.join(" ");
|
||||
|
||||
if (text === undefined || text === "") {
|
||||
// Nothing to do for empty headings.
|
||||
return;
|
||||
}
|
||||
let id = $(this)
|
||||
.attr("id");
|
||||
|
||||
if (id === undefined) {
|
||||
id = `autoid-${++n}`;
|
||||
$(this)
|
||||
.attr("id", id);
|
||||
}
|
||||
|
||||
const level = parseInt(this.nodeName.substring(1)) - 1;
|
||||
if (!last_level) {
|
||||
last_level = level;
|
||||
}
|
||||
|
||||
if (level > last_level) {
|
||||
last_level = level;
|
||||
} else
|
||||
while (level < last_level) {
|
||||
last_level--;
|
||||
}
|
||||
|
||||
$(nav)
|
||||
.append(`<a class="nav-link" href="#${id}">${text}</a>`);
|
||||
});
|
||||
populate_nav(nav[0], heading_selector);
|
||||
|
||||
if (haveExtraNav) {
|
||||
$('#righthand-panel').append('<div id="righthand-extra" class="w-100 py-3"></div>');
|
||||
|
@ -246,18 +203,6 @@ $(function () {
|
|||
extraNav.remove();
|
||||
}
|
||||
|
||||
$(document)
|
||||
// Chrome apparently wants this debounced to something >10ms,
|
||||
// otherwise the main view doesn't scroll?
|
||||
.on("scroll", debounce(function () {
|
||||
const item = $('#righthand-nav')
|
||||
.find(".active")
|
||||
.last();
|
||||
if (item.length) {
|
||||
item[0].scrollIntoView({ block: "center", behavior: "smooth" });
|
||||
}
|
||||
}, 100));
|
||||
|
||||
// offset the scrollspy to account for the menu bar
|
||||
const contentOffset = contentElement ? contentElement.offset().top : 0;
|
||||
|
||||
|
|
99
ietf/static/js/nav.js
Normal file
99
ietf/static/js/nav.js
Normal file
|
@ -0,0 +1,99 @@
|
|||
import debounce from "lodash/debounce";
|
||||
|
||||
function make_nav() {
|
||||
const nav = document.createElement("nav");
|
||||
nav.classList.add("nav-pills", "ps-3", "flex-column");
|
||||
return nav;
|
||||
}
|
||||
|
||||
function get_level(el) {
|
||||
let h;
|
||||
if (el.tagName.match(/^h\d/i)) {
|
||||
h = el.tagName
|
||||
} else {
|
||||
el.classList.forEach(cl => {
|
||||
if (cl.match(/^h\d/i)) {
|
||||
h = cl;
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
return h.charAt(h.length - 1);
|
||||
}
|
||||
|
||||
export function populate_nav(nav, heading_selector, classes) {
|
||||
// Extract section headings from document
|
||||
const headings = document.querySelectorAll(heading_selector);
|
||||
const min_level = Math.min(...Array.from(headings)
|
||||
.map(get_level));
|
||||
|
||||
let nav_stack = [nav];
|
||||
let cur_level = 0;
|
||||
let n = 0;
|
||||
|
||||
headings.forEach(el => {
|
||||
const level = get_level(el) - min_level;
|
||||
|
||||
if (level < cur_level) {
|
||||
while (level < cur_level) {
|
||||
let nav = nav_stack.pop();
|
||||
cur_level--;
|
||||
nav_stack[level].appendChild(nav);
|
||||
}
|
||||
} else {
|
||||
while (level > cur_level) {
|
||||
nav_stack.push(make_nav());
|
||||
cur_level++;
|
||||
}
|
||||
}
|
||||
|
||||
const link = document.createElement("a");
|
||||
link.classList.add("nav-link", "ps-1", "d-flex", "hyphenate",
|
||||
classes);
|
||||
|
||||
if (!el.id) {
|
||||
el.id = `autoid-${++n}`;
|
||||
}
|
||||
link.href = `#${el.id}`;
|
||||
|
||||
const words = el.innerText.split(/\s+/);
|
||||
let nr = "";
|
||||
if (words[0].includes(".")) {
|
||||
nr = words.shift();
|
||||
} else if (words.length > 1 && words[1].includes(".")) {
|
||||
nr = words.shift() + " " + words.shift();
|
||||
nr = nr.replace(/\s*Appendix\s*/, "");
|
||||
}
|
||||
|
||||
if (nr) {
|
||||
const number = document.createElement("div");
|
||||
number.classList.add("pe-1");
|
||||
number.textContent = nr;
|
||||
link.appendChild(number);
|
||||
}
|
||||
|
||||
const text = document.createElement("div");
|
||||
text.classList.add("text-break");
|
||||
text.textContent = words.join(" ");
|
||||
link.appendChild(text);
|
||||
|
||||
nav_stack[level].appendChild(link);
|
||||
});
|
||||
|
||||
for (var i = nav_stack.length - 1; i > 0; i--) {
|
||||
nav_stack[i - 1].appendChild(nav_stack[i]);
|
||||
}
|
||||
|
||||
// Chrome apparently wants this debounced to something >10ms,
|
||||
// otherwise the main view doesn't scroll?
|
||||
document.addEventListener("scroll", debounce(function () {
|
||||
const items = nav.querySelectorAll(".active");
|
||||
const item = [...items].pop();
|
||||
if (item) {
|
||||
item.scrollIntoView({
|
||||
block: "center",
|
||||
behavior: "smooth"
|
||||
});
|
||||
}
|
||||
}, 100));
|
||||
}
|
|
@ -345,7 +345,7 @@ def document_stats(request, stats_type=None):
|
|||
|
||||
basename, ext = t
|
||||
ext = ext.lower()
|
||||
if not any(ext==whitelisted_ext for whitelisted_ext in settings.DOCUMENT_FORMAT_WHITELIST):
|
||||
if not any(ext==allowlisted_ext for allowlisted_ext in settings.DOCUMENT_FORMAT_ALLOWLIST):
|
||||
continue
|
||||
|
||||
canonical_name = doc_names_with_missing_types.get(basename)
|
||||
|
|
|
@ -338,7 +338,7 @@ class SubmissionBaseUploadForm(forms.Form):
|
|||
if group:
|
||||
return group
|
||||
else:
|
||||
raise forms.ValidationError('Draft names starting with draft-%s- are restricted, please pick a differen name' % ntype)
|
||||
raise forms.ValidationError('Draft names starting with draft-%s- are restricted, please pick a different name' % ntype)
|
||||
return None
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
|
||||
|
||||
Network Working Group %(initials)s %(surname)s
|
||||
Network Working Group %(firstpagename)37s
|
||||
Internet-Draft Test Centre Inc.
|
||||
Intended status: Informational %(month)s %(year)s
|
||||
Expires: %(expiration)s
|
||||
|
@ -10,7 +10,6 @@ Expires: %(expiration)s
|
|||
|
||||
%(title)s
|
||||
%(name)s
|
||||
|
||||
Abstract
|
||||
|
||||
This document describes how to test tests.
|
||||
|
|
|
@ -107,6 +107,10 @@ def submission_file(name_in_doc, name_in_post, group, templatename, author=None,
|
|||
if year is None:
|
||||
year = _today.strftime("%Y")
|
||||
|
||||
# extract_authors() cuts the author line off at the first space past 80 characters
|
||||
# very long factory-generated names can hence be truncated, causing a failure
|
||||
# ietf/submit/test_submission.txt was changed so that 37-character names and shorter will work
|
||||
# this may need further adjustment if longer names still cause failures
|
||||
submission_text = template % dict(
|
||||
date=_today.strftime("%d %B %Y"),
|
||||
expiration=(_today + datetime.timedelta(days=100)).strftime("%d %B, %Y"),
|
||||
|
@ -119,6 +123,7 @@ def submission_file(name_in_doc, name_in_post, group, templatename, author=None,
|
|||
asciiAuthor=author.ascii,
|
||||
initials=author.initials(),
|
||||
surname=author.ascii_parts()[3] if ascii else author.name_parts()[3],
|
||||
firstpagename=f"{author.initials()} {author.ascii_parts()[3] if ascii else author.name_parts()[3]}",
|
||||
asciiSurname=author.ascii_parts()[3],
|
||||
email=email,
|
||||
title=title,
|
||||
|
|
|
@ -567,7 +567,7 @@ def post_approved_draft(url, name):
|
|||
"Authorization": "Basic %s" % force_str(base64.encodebytes(smart_bytes("%s:%s" % (username, password)))).replace("\n", ""),
|
||||
}
|
||||
|
||||
log("Posting RFC-Editor notifcation of approved draft '%s' to '%s'" % (name, url))
|
||||
log("Posting RFC-Editor notification of approved draft '%s' to '%s'" % (name, url))
|
||||
text = error = ""
|
||||
|
||||
try:
|
||||
|
|
|
@ -186,8 +186,8 @@
|
|||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item {% if flavor != 'top' %} text-wrap link-primary{% endif %}"
|
||||
href="{% url 'ietf.ietfauth.views.add_account_whitelist' %}">
|
||||
Account whitelist
|
||||
href="{% url 'ietf.ietfauth.views.add_account_allowlist' %}">
|
||||
Account allowlist
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
{% load origin %}
|
||||
{% load static %}
|
||||
{% origin %}
|
||||
{% if debug %}
|
||||
{% if settings.DEBUG %}
|
||||
{% if sql_debug %}
|
||||
{% load debug_filters %}
|
||||
{{ sql_queries|length }} queries ({{ sql_queries|timesum }}s)
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
{% block content %}
|
||||
{% origin %}
|
||||
{{ top|safe }}
|
||||
{% include "doc/revisions_list.html" %}
|
||||
{% include "doc/revisions_list.html" with document_html=document_html %}
|
||||
<div id="timeline"></div>
|
||||
{% if doc.rev != latest_rev %}
|
||||
<div class="alert alert-warning my-3">The information below is for an old version of the document.</div>
|
||||
|
@ -38,363 +38,7 @@
|
|||
{% endif %}
|
||||
{% endif %}
|
||||
<table class="table table-sm table-borderless">
|
||||
<tbody class="meta border-top">
|
||||
<tr>
|
||||
<th scope="row">Document</th>
|
||||
<th scope="row">Type</th>
|
||||
<td class="edit"></td>
|
||||
<td>
|
||||
{% if doc.get_state_slug == "rfc" and not snapshot %}
|
||||
<span class="text-success">RFC - {{ doc.std_level }}</span>
|
||||
{% if published %}
|
||||
({{ doc.pub_date|date:"F Y" }})
|
||||
{% else %}
|
||||
(Publication date unknown)
|
||||
{% endif %}
|
||||
{% if has_verified_errata %}
|
||||
<a class="badge rounded-pill bg-danger text-decoration-none text-light"
|
||||
href="https://www.rfc-editor.org/errata_search.php?rfc={{ doc.rfc_number }}" title="Click to view errata." rel="nofollow">
|
||||
Errata
|
||||
</a>
|
||||
{% elif has_errata %}
|
||||
<a class="badge rounded-pill bg-warning text-decoration-none text-light"
|
||||
href="https://www.rfc-editor.org/errata_search.php?rfc={{ doc.rfc_number }}" title="Click to view errata." rel="nofollow">
|
||||
Errata
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if obsoleted_by %}<div>Obsoleted by {{ obsoleted_by|urlize_related_source_list|join:", " }}</div>{% endif %}
|
||||
{% if updated_by %}<div>Updated by {{ updated_by|urlize_related_source_list|join:", " }}</div>{% endif %}
|
||||
{% if obsoletes %}<div>Obsoletes {{ obsoletes|urlize_related_target_list|join:", " }}</div>{% endif %}
|
||||
{% if updates %}<div>Updates {{ updates|urlize_related_target_list|join:", " }}</div>{% endif %}
|
||||
{% if status_changes %}
|
||||
<div>Status changed by {{ status_changes|urlize_related_source_list|join:", " }}</div>
|
||||
{% endif %}
|
||||
{% if proposed_status_changes %}
|
||||
<div>Proposed status changed by {{ proposed_status_changes|urlize_related_source_list|join:", " }}</div>
|
||||
{% endif %}
|
||||
{% if rfc_aliases %}<div>Also known as {{ rfc_aliases|join:", "|urlize_ietf_docs }}</div>{% endif %}
|
||||
{% if draft_name %}
|
||||
<div>
|
||||
Was
|
||||
<a href="{% url 'ietf.doc.views_doc.document_main' name=draft_name %}">{{ draft_name }}</a>
|
||||
{% if submission %}({{ submission|safe }}){% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if snapshot and doc.doc.get_state_slug == 'rfc' %}
|
||||
<span>This is an older version of an Internet-Draft that was ultimately published as an RFC.</span>
|
||||
{% elif snapshot and doc.rev != latest_rev %}
|
||||
<span>This is an older version of an Internet-Draft whose latest revision is {{ doc.doc.get_state }}</span>
|
||||
{% else %}
|
||||
<span class="{% if doc.get_state_slug == 'active' %}text-success{% elif doc.get_state_slug == 'expired' %}text-danger{% endif %}">{% if snapshot and doc.rev == latest_rev %}{{ doc.doc.get_state }}{% else %}{{ doc.get_state }}{% endif %} Internet-Draft</span>
|
||||
{% if submission %}({{ submission|safe }}){% endif %}
|
||||
{% if resurrected_by %}- resurrect requested by {{ resurrected_by }}{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<th scope="row">Author{{ doc.authors|pluralize }}</th>
|
||||
<td class="edit">
|
||||
{% if can_edit_authors %}
|
||||
<a class="btn btn-primary btn-sm"
|
||||
href="{% url 'ietf.doc.views_doc.edit_authors' name=doc.name %}">Edit</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{# Implementation that uses the current primary email for each author #}
|
||||
{% for author in doc.authors %}
|
||||
{% person_link author %}{% if not forloop.last %},{% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<th scope="row">Last updated</th>
|
||||
<td class="edit"></td>
|
||||
<td>
|
||||
{{ doc.time|date:"Y-m-d" }}
|
||||
{% if latest_revision and latest_revision.time|date:"Y-m-d" != doc.time|date:"Y-m-d" %}
|
||||
<span class="text-muted">(Latest revision {{ latest_revision.time|date:"Y-m-d" }})</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% if replaces or can_edit_stream_info %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<th scope="row">Replaces</th>
|
||||
<td class="edit">
|
||||
{% if can_edit_stream_info and not snapshot %}
|
||||
<a class="btn btn-primary btn-sm"
|
||||
href="{% url 'ietf.doc.views_draft.replaces' name=doc.name %}">Edit</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if replaces %}
|
||||
{{ replaces|urlize_related_target_list|join:", " }}
|
||||
{% else %}
|
||||
<span class="text-muted">(None)</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if replaced_by %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<th scope="row">
|
||||
Replaced by
|
||||
</th>
|
||||
<td class="edit">
|
||||
</td>
|
||||
<td>
|
||||
{{ replaced_by|urlize_related_source_list|join:", " }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if can_view_possibly_replaces %}
|
||||
{% if possibly_replaces %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<th scope="row">
|
||||
Possibly Replaces
|
||||
</th>
|
||||
<td class="edit">
|
||||
{% if can_edit_replaces and not snapshot %}
|
||||
<a class="btn btn-primary btn-sm"
|
||||
href="{% url 'ietf.doc.views_draft.review_possibly_replaces' name=doc.name %}">
|
||||
Edit
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{{ possibly_replaces|urlize_related_target_list|join:", " }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if possibly_replaced_by %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<th scope="row">
|
||||
Possibly Replaced By
|
||||
</th>
|
||||
<td class="edit">
|
||||
{% if can_edit_replaces and not snapshot %}
|
||||
{% comment %}<a class="btn btn-primary btn-sm"
|
||||
href="{% url 'ietf.doc.views_draft.review_possibly_replaces' name=doc.name %}">Edit</a>{% endcomment %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{{ possibly_replaced_by|urlize_related_source_list|join:", " }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<th scope="row">
|
||||
Stream
|
||||
</th>
|
||||
<td class="edit">
|
||||
{% if can_change_stream and not snapshot %}
|
||||
<a class="btn btn-primary btn-sm"
|
||||
href="{% url 'ietf.doc.views_draft.change_stream' name=doc.name %}">
|
||||
Edit
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td {% if stream_desc == "(None)" %}class="text-muted"{%endif%}>
|
||||
{{ stream_desc }}
|
||||
</td>
|
||||
</tr>
|
||||
{% if doc.get_state_slug != "rfc" and not snapshot %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<th scope="row">
|
||||
Intended RFC status
|
||||
</th>
|
||||
<td class="edit">
|
||||
{% if can_edit_stream_info and not snapshot %}
|
||||
<a class="btn btn-primary btn-sm"
|
||||
href="{% url 'ietf.doc.views_draft.change_intention' name=doc.name %}">
|
||||
Edit
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if doc.intended_std_level %}
|
||||
{{ doc.intended_std_level }}
|
||||
{% else %}
|
||||
<span class="text-muted">
|
||||
(None)
|
||||
</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<th scope="row">
|
||||
Formats
|
||||
</th>
|
||||
<td class="edit">
|
||||
</td>
|
||||
<td>
|
||||
{% if doc.get_state_slug != "active" and doc.get_state_slug != "rfc" %}
|
||||
<div class="badge rounded-pill bg-warning float-end">
|
||||
Expired & archived
|
||||
</div>
|
||||
{% endif %}
|
||||
{% include "doc/document_format_buttons.html" %}
|
||||
</td>
|
||||
</tr>
|
||||
{% for check in doc.submission.latest_checks %}
|
||||
{% if check.passed != None and check.symbol.strip %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<th scope="row">
|
||||
{{ check.checker|title }}
|
||||
</th>
|
||||
<td class="edit">
|
||||
</td>
|
||||
<td>
|
||||
{% if check.errors or check.warnings %}
|
||||
<span class="checker-warning"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#check-{{ check.pk }}"
|
||||
title="{{ check.checker|title }} returned warnings or errors.">
|
||||
{{ check.symbol|safe }}
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="checker-success"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#check-{{ check.pk }}"
|
||||
title="{{ check.checker|title }} passed">
|
||||
{{ check.symbol|safe }}
|
||||
</span>
|
||||
{% endif %}
|
||||
<a href="#"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#check-{{ check.pk }}">
|
||||
{{ check.errors }} errors, {{ check.warnings }} warnings
|
||||
</a>
|
||||
{% include "doc/yang-check-modal-overlay.html" %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if review_assignments or can_request_review %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<th scope="row">
|
||||
Reviews
|
||||
</th>
|
||||
<td class="edit">
|
||||
</td>
|
||||
<td>
|
||||
{% for review_assignment in review_assignments %}
|
||||
{% include "doc/review_assignment_summary.html" with current_doc_name=doc.name current_rev=doc.rev %}
|
||||
{% endfor %}
|
||||
{% if no_review_from_teams %}
|
||||
{% for team in no_review_from_teams %}
|
||||
{{ team.acronym.upper }}{% if not forloop.last %},{% endif %}
|
||||
{% endfor %}
|
||||
will not review this version
|
||||
{% endif %}
|
||||
{% if can_request_review or can_submit_unsolicited_review_for_teams %}
|
||||
<div {% if review_assignments or no_review_from_teams %} class="mt-3"{% endif %}>
|
||||
{% if can_request_review %}
|
||||
<a class="btn btn-primary btn-sm"
|
||||
href="{% url "ietf.doc.views_review.request_review" doc.name %}">
|
||||
<i class="bi bi-check-circle">
|
||||
</i>
|
||||
Request review
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if can_submit_unsolicited_review_for_teams|length == 1 %}
|
||||
<a class="btn btn-primary btn-sm"
|
||||
href="{% url "ietf.doc.views_review.complete_review" doc.name can_submit_unsolicited_review_for_teams.0.acronym %}">
|
||||
<i class="bi bi-pencil-square">
|
||||
</i>
|
||||
Submit unsolicited review
|
||||
</a>
|
||||
{% elif can_submit_unsolicited_review_for_teams %}
|
||||
<a class="btn btn-primary btn-sm"
|
||||
href="{% url "ietf.doc.views_review.submit_unsolicited_review_choose_team" doc.name %}">
|
||||
<i class="bi bi-pencil-square">
|
||||
</i>
|
||||
Submit unsolicited review
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if conflict_reviews %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<th scope="row">
|
||||
IETF conflict review
|
||||
</th>
|
||||
<td class="edit">
|
||||
</td>
|
||||
<td>
|
||||
{{ conflict_reviews|join:", "|urlize_ietf_docs }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% with doc.docextresource_set.all as resources %}
|
||||
{% if resources or can_edit_stream_info or can_edit_individual %}
|
||||
<tr>
|
||||
<td>
|
||||
</td>
|
||||
<th scope="row">
|
||||
Additional resources
|
||||
</th>
|
||||
<td class="edit">
|
||||
{% if can_edit_stream_info or can_edit_individual %}
|
||||
<a class="btn btn-primary btn-sm"
|
||||
href="{% url 'ietf.doc.views_draft.edit_doc_extresources' name=doc.name %}">
|
||||
Edit
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if resources or doc.group and doc.group.list_archive %}
|
||||
{% for resource in resources|dictsort:"display_name" %}
|
||||
{% if resource.name.type.slug == 'url' or resource.name.type.slug == 'email' %}
|
||||
<a href="{{ resource.value }}" title="{{ resource.name.name }}">
|
||||
{% firstof resource.display_name resource.name.name %}
|
||||
</a>
|
||||
<br>
|
||||
{# Maybe make how a resource displays itself a method on the class so templates aren't doing this switching #}
|
||||
{% else %}
|
||||
<span title="{{ resource.name.name }}">
|
||||
{% firstof resource.display_name resource.name.name %}: {{ resource.value|escape }}
|
||||
</span>
|
||||
<br>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if doc.group and doc.group.list_archive %}
|
||||
{% if doc.group.list_archive|startswith:settings.MAILING_LIST_ARCHIVE_URL %}
|
||||
<a href="{{ doc.group.list_archive }}?q={{ doc.name }}">
|
||||
Mailing list discussion
|
||||
</a>
|
||||
{% elif doc.group.list_archive|is_valid_url %}
|
||||
<a href="{{ doc.group.list_archive }}">
|
||||
Mailing list discussion
|
||||
</a>
|
||||
{% else %}
|
||||
{{ doc.group.list_archive|urlencode }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</tbody>
|
||||
{% include "doc/document_info.html" %}
|
||||
<tbody class="meta border-top">
|
||||
<tr>
|
||||
<th scope="row">
|
||||
|
|
|
@ -1,7 +1,18 @@
|
|||
{% if file_urls %}
|
||||
<div class="buttonlist">
|
||||
{% for label, url in file_urls %}
|
||||
<a class="btn btn-primary btn-sm" href="{{ url }}">
|
||||
{% if label != skip_format %}
|
||||
<a class="btn btn-primary btn-sm"
|
||||
{% if label == 'pdf' or label == 'pdfized' %}
|
||||
download="{% if not snapshot and doc.get_state_slug == 'rfc' %}rfc{{ doc.rfc_number }}{% else %}{{ doc.name }}-{{ doc.rev }}{% endif %}.pdf"
|
||||
{% comment %}
|
||||
TODO: determine if we want bibtex to jiust download
|
||||
{% elif label == 'bibtex' %}
|
||||
download="{% if not snapshot and doc.get_state_slug == 'rfc' %}rfc{{ doc.rfc_number }}{% else %}{{ doc.name }}-{{ doc.rev }}{% endif %}.bib"
|
||||
{% endcomment %}
|
||||
{% endif %}
|
||||
{% if label != 'htmlized' %}target="_blank"{% endif %}
|
||||
href="{{ url }}">
|
||||
{% if label == 'pdf' or label == 'pdfized' %}
|
||||
<i class="bi bi-file-pdf"></i> pdf
|
||||
{% elif label == 'xml' or label == 'html' %}
|
||||
|
@ -16,6 +27,7 @@
|
|||
<i class="bi bi-file-diff"></i> w/errata
|
||||
{% endif %}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
|
|
|
@ -1,92 +1,276 @@
|
|||
{% extends "doc/htmlized_base.html" %}
|
||||
{# Copyright The IETF Trust 2016, All Rights Reserved #}
|
||||
<!DOCTYPE html>
|
||||
{% load analytical %}
|
||||
{% load origin %}
|
||||
{% load static %}
|
||||
{% load ietf_filters %}
|
||||
{% block pagehead %}
|
||||
{% load ietf_filters textfilters %}
|
||||
{% origin %}
|
||||
<html lang="en">
|
||||
<head>
|
||||
{% analytical_head_top %}
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>
|
||||
{% if not snapshot and doc.get_state_slug == "rfc" %}
|
||||
RFC {{ doc.rfc_number }} - {{ doc.title }}
|
||||
{% else %}
|
||||
{{ doc.name }}-{{ doc.rev }}
|
||||
{% endif %}
|
||||
</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
{% if request.COOKIES.pagedeps == 'inline' %}
|
||||
<script>{{ js|safe }}</script>
|
||||
<style>{{ css|safe }}</style>
|
||||
{% else %}
|
||||
<link rel="stylesheet" href="{% static 'ietf/css/document_html_referenced.css' %}">
|
||||
{% if html %}
|
||||
<link rel="stylesheet" href="{% static 'ietf/css/document_html_txt.css' %}">
|
||||
{% endif %}
|
||||
<script src="{% static 'ietf/js/document_html.js' %}"></script>
|
||||
{% endif %}
|
||||
<link rel="alternate"
|
||||
type="application/atom+xml"
|
||||
title="Document changes"
|
||||
href="/feed/document-changes/{{ doc.name }}/">
|
||||
<meta name="description"
|
||||
{% if doc.get_state_slug == "rfc" %}
|
||||
content="{{ doc.title }} (RFC {{ doc.rfc_number }}{% if published %}, {{ published.time|date:"F Y" }}{% endif %}{% if obsoleted_by %}; obsoleted by {{ obsoleted_by|join:", " }}{% endif %})"
|
||||
{% if not snapshot and doc.get_state_slug == 'rfc' %}
|
||||
content="{{ doc.title }} (RFC {{ doc.rfc_number }}{% if published %}, {{ published.time|date:'F Y' }}{% endif %}{% if obsoleted_by %}; obsoleted by {{ obsoleted_by|join:', ' }}{% endif %}"
|
||||
{% else %}
|
||||
content="{{ doc.title }} (Internet-Draft, {{ doc.time|date:"Y" }})"
|
||||
content="{{ doc.title }} (Internet-Draft, {{ doc.time|date:'Y' }})"
|
||||
{% endif %}>
|
||||
{% endblock %}
|
||||
{% block morecss %}
|
||||
.bgwhite { background-color: white; }
|
||||
.bgred { background-color: #F44; }
|
||||
.bggrey { background-color: #666; }
|
||||
.bgbrown { background-color: #840; }
|
||||
.bgorange { background-color: #FA0; }
|
||||
.bgyellow { background-color: #EE0; }
|
||||
.bgmagenta{ background-color: #F4F; }
|
||||
.bgblue { background-color: #66F; }
|
||||
.bgcyan { background-color: #4DD; }
|
||||
.bggreen { background-color: #4F4; }
|
||||
.draftcontent { margin-top:1em;}
|
||||
{% endblock %}
|
||||
{% block title %}
|
||||
{% if doc.get_state_slug == "rfc" %}
|
||||
RFC {{ doc.rfc_number }} - {{ doc.title }}
|
||||
{% include "base/icons.html" %}
|
||||
{% include "doc/opengraph.html" %}
|
||||
{% analytical_head_bottom %}
|
||||
</head>
|
||||
<body>
|
||||
{% analytical_body_top %}
|
||||
<button class="btn btn-outline-secondary position-fixed top-0 end-0 m-2 sidebar-toggle"
|
||||
type="button"
|
||||
id="sidebar-on"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#sidebar"
|
||||
aria-expanded="{% if request.COOKIES.sidebar != 'off'%}true{% else %}false{% endif %}"
|
||||
aria-controls="sidebar"
|
||||
aria-label="Show metadata sidebar"
|
||||
title="Show metadata sidebar">
|
||||
<i class="bi bi-layout-sidebar-reverse"></i>
|
||||
</button>
|
||||
<nav class="navbar navbar-light bg-light px-1 fixed-top d-print-none d-md-none">
|
||||
<a class="nav-link ps-1"
|
||||
href="{% url 'ietf.doc.views_doc.document_main' name=doc.canonical_name %}">
|
||||
{% if not snapshot and doc.get_state_slug == "rfc" %}
|
||||
RFC {{ doc.rfc_number }}
|
||||
{% else %}
|
||||
{{ doc.name }}-{{ doc.rev }}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<!-- [html-validate-disable-block no-inline-style, attr-quotes, void-style -- FIXME: it's everywhere in this old code] -->
|
||||
{% origin %}
|
||||
<br class="d-sm-none">
|
||||
<span class="ms-sm-3 badge rounded-pill badge-{% if not snapshot %}{{ doc|std_level_to_label_format }}{% else %}draft{% endif %}">
|
||||
{% if not snapshot %}
|
||||
{{ doc.std_level }}
|
||||
{% else %}
|
||||
Internet-Draft
|
||||
{% endif %}
|
||||
</span>
|
||||
</a>
|
||||
<button class="navbar-toggler p-1"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#docinfo-collapse"
|
||||
aria-controls="docinfo-collapse"
|
||||
aria-expanded="false"
|
||||
aria-label="Show document information">
|
||||
<span class="navbar-toggler-icon small"></span>
|
||||
</button>
|
||||
<div class="navbar-nav navbar-nav-scroll overscroll-none collapse pt-1" id="docinfo-collapse">
|
||||
<div class="bg-light p-0">
|
||||
<table class="table table-sm table-borderless small">
|
||||
<tbody class="meta align-top">
|
||||
<tr>
|
||||
<th scope="row"></th>
|
||||
<th scope="row">Title</th>
|
||||
<td class="edit"></td>
|
||||
<td>{{ doc.title }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
{% include "doc/document_info.html" with sidebar=False %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="row g-0">
|
||||
<div class="col d-flex justify-content-center lh-sm"
|
||||
data-bs-spy="scroll"
|
||||
data-bs-target="#toc-nav"
|
||||
data-bs-smooth-scroll="true"
|
||||
tabindex="0"
|
||||
id="content">
|
||||
{% if html and request.COOKIES.htmlconf != 'txt' %}
|
||||
<div class="rfchtml">
|
||||
<br class="noprint">
|
||||
{{ html|safe }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="rfcmarkup">
|
||||
<div class="noprint" style="height: .5em;">
|
||||
<div onmouseover="this.style.cursor='pointer';"
|
||||
onclick="showLegend();"
|
||||
onmouseout="hideLegend()"
|
||||
style="height: .5em; min-height: .5em; width: 96ex; "
|
||||
class="meta-info {{ doccolor }}"
|
||||
title="Click for color legend.">
|
||||
</div>
|
||||
<div id="legend"
|
||||
class="meta-info noprint pre legend"
|
||||
style="position:absolute; top: 4px; left: 4ex; visibility:hidden; background-color: white; padding: 4px 9px 5px 7px; border: solid #345 1px; "
|
||||
onmouseover="showLegend();"
|
||||
onmouseout="hideLegend();">
|
||||
</div>
|
||||
</div>
|
||||
{% if doc.meta %}
|
||||
<div class="noprint">
|
||||
<pre class="pre meta-info">{{ doc.supermeta|safe }}
|
||||
{{ doc.meta|safe }}</pre>
|
||||
<br class="noprint">
|
||||
<!-- [html-validate-disable-block attr-quotes, void-style, element-permitted-content, heading-level -- FIXME: rfcmarkup/rfc2html generates HTML with issues] -->
|
||||
{{ doc.htmlized|default:"Generation of htmlized text failed"|linkify|safe }}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="draftcontent">{{ doc.htmlized|default:"Generation of htmlized text failed"|safe }}</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block js %}
|
||||
<script>
|
||||
var legend_html = 'Color legend:<br> \
|
||||
<table> \
|
||||
<tr><td>Unknown:</td> <td><span class="bgwhite"> </span></td></tr> \
|
||||
<tr><td>Draft:</td> <td><span class="bgred"> </span></td></tr> \
|
||||
<tr><td>Informational:</td> <td><span class="bgorange"> </span></td></tr> \
|
||||
<tr><td>Experimental:</td> <td><span class="bgyellow"> </span></td></tr> \
|
||||
<tr><td>Best Common Practice:</td> <td><span class="bgmagenta"> </span></td></tr> \
|
||||
<tr><td>Proposed Standard:</td> <td><span class="bgblue"> </span></td></tr> \
|
||||
<tr><td>Draft Standard (old designation):</td> <td><span class="bgcyan"> </span></td></tr> \
|
||||
<tr><td>Internet Standard:</td> <td><span class="bggreen"> </span></td></tr> \
|
||||
<tr><td>Historic:</td> <td><span class="bggrey"> </span></td></tr> \
|
||||
<tr><td>Obsolete:</td> <td><span class="bgbrown"> </span></td></tr> \
|
||||
</table>';
|
||||
function showLegend() {
|
||||
var elem = document.getElementById('legend');
|
||||
elem.innerHTML = legend_html
|
||||
elem.style.visibility='visible';
|
||||
}
|
||||
function hideLegend() {
|
||||
var elem = document.getElementById('legend');
|
||||
elem.style.visibility='hidden';
|
||||
elem.innerHTML = "";
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
<div class="d-none d-md-block d-print-none col-3 bg-light collapse{% if request.COOKIES.sidebar != 'off'%} show{% endif %}" id="sidebar">
|
||||
<div class="position-fixed col-3 border-start sidebar overflow-scroll overscroll-none no-scrollbar">
|
||||
<button class="btn btn-outline-secondary float-end m-2"
|
||||
type="button"
|
||||
id="sidebar-off"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#sidebar"
|
||||
aria-expanded="{% if request.COOKIES.sidebar != 'off'%}true{% else %}false{% endif %}"
|
||||
aria-controls="sidebar"
|
||||
aria-label="Hide metadata sidebar"
|
||||
title="Hide metadata sidebar">
|
||||
<i class="bi bi-arrow-bar-up"></i>
|
||||
</button>
|
||||
<div class="pt-2 pt-lg-3 px-md-2 px-lg-3">
|
||||
<p>
|
||||
<a href="{% url 'ietf.doc.views_doc.document_main' name=doc.canonical_name %}">
|
||||
{% if not snapshot and doc.get_state_slug == "rfc" %}
|
||||
RFC {{ doc.rfc_number }}
|
||||
{% else %}
|
||||
{{ doc.name }}-{{ doc.rev }}
|
||||
{% endif %}
|
||||
<br>
|
||||
<span class="badge rounded-pill badge-{% if not snapshot %}{{ doc|std_level_to_label_format }}{% else %}draft{% endif %}">
|
||||
{% if not snapshot %}
|
||||
{{ doc.std_level }}
|
||||
{% else %}
|
||||
Internet-Draft
|
||||
{% endif %}
|
||||
</span>
|
||||
</a>
|
||||
</p>
|
||||
{% if request.COOKIES.htmlconf != 'html' and html %}
|
||||
<div class="alert alert-info small">
|
||||
You are viewing the legacy <code><a class="text-decoration-none text-reset" href="https://github.com/ietf-tools/rfc2html">rfc2html</a></code>
|
||||
rendering of this document. Change the
|
||||
preferences for a modern <code><a class="text-decoration-none text-reset" href="https://github.com/ietf-tools/xml2rfc">xml2rfc</a></code>-based
|
||||
HTMLization.
|
||||
</div>
|
||||
{% elif request.COOKIES.htmlconf == 'html' and not html %}
|
||||
<div class="alert alert-info small">
|
||||
You are viewing the legacy <code><a class="text-decoration-none text-reset" href="https://github.com/ietf-tools/rfc2html">rfc2html</a></code>
|
||||
rendering, because no <code><a class="text-decoration-none text-reset" href="https://github.com/ietf-tools/xml2rfc">xml2rfc</a></code>-generated
|
||||
HTML is available for this document.
|
||||
</div>
|
||||
{% endif %}
|
||||
<ul class="nav nav-tabs nav-fill small" role="tablist">
|
||||
<li class="nav-item" role="presentation" title="Document information">
|
||||
<button class="nav-link px-2"
|
||||
id="docinfo-tab"
|
||||
data-bs-toggle="tab"
|
||||
data-bs-target="#docinfo-tab-pane"
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-controls="docinfo-tab-pane"
|
||||
aria-selected="true">
|
||||
<i class="bi bi-info-circle"></i><span class="d-none d-md-block d-xl-inline ms-xl-1">Info</span>
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation" title="Table of contents">
|
||||
<button class="nav-link px-2"
|
||||
id="toc-tab"
|
||||
data-bs-toggle="tab"
|
||||
data-bs-target="#toc-tab-pane"
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-controls="toc-tab-pane"
|
||||
aria-selected="false">
|
||||
<i class="bi bi-list-ol"></i><span class="d-none d-md-block d-xl-inline ms-xl-1">Contents</span>
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation" title="Preferences">
|
||||
<button class="nav-link px-2"
|
||||
id="pref-tab"
|
||||
data-bs-toggle="tab"
|
||||
data-bs-target="#pref-tab-pane"
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-controls="pref-tab-pane"
|
||||
aria-selected="false">
|
||||
<i class="bi bi-gear"></i><span class="d-none d-md-block d-xl-inline ms-xl-1">Prefs</span>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tab-content pt-2">
|
||||
<div class="tab-pane"
|
||||
id="docinfo-tab-pane"
|
||||
role="tabpanel"
|
||||
aria-labelledby="docinfo-tab"
|
||||
tabindex="0">
|
||||
<table class="table table-sm table-borderless">
|
||||
{% include "doc/document_info.html" with sidebar=True %}
|
||||
</table>
|
||||
</div>
|
||||
<div class="tab-pane mb-5"
|
||||
id="toc-tab-pane"
|
||||
role="tabpanel"
|
||||
aria-labelledby="toc-tab"
|
||||
tabindex="0">
|
||||
<nav class="nav nav-pills flex-column small" id="toc-nav">
|
||||
</nav>
|
||||
</div>
|
||||
<div class="tab-pane mb-5 small"
|
||||
id="pref-tab-pane"
|
||||
role="tabpanel"
|
||||
aria-labelledby="pref-tab"
|
||||
tabindex="0">
|
||||
<label class="form-label fw-bold mb-2">Show sidebar by default</label>
|
||||
<div class="btn-group-vertical btn-group-sm d-flex" role="group">
|
||||
<input type="radio" class="btn-check" name="sidebar" id="on-radio">
|
||||
<label class="btn btn-outline-primary" for="on-radio">Yes</label>
|
||||
<input type="radio" class="btn-check" name="sidebar" id="off-radio">
|
||||
<label class="btn btn-outline-primary" for="off-radio">No</label>
|
||||
</div>
|
||||
<label class="form-label fw-bold mt-4 mb-2">Tab to show by default</label>
|
||||
<div class="btn-group-vertical btn-group-sm d-flex" role="group">
|
||||
<input type="radio" class="btn-check" name="deftab" id="docinfo-radio">
|
||||
<label class="btn btn-outline-primary" for="docinfo-radio">
|
||||
<i class="bi bi-info-circle me-1"></i>Info
|
||||
</label>
|
||||
<input type="radio" class="btn-check" name="deftab" id="toc-radio">
|
||||
<label class="btn btn-outline-primary" for="toc-radio">
|
||||
<i class="bi bi-list-ol me-1"></i>Contents
|
||||
</label>
|
||||
</div>
|
||||
<label class="form-label fw-bold mt-4 mb-2">HTMLization configuration</label>
|
||||
<div class="btn-group-vertical btn-group-sm d-flex" role="group">
|
||||
<input type="radio" class="btn-check" name="htmlconf" id="txt-radio">
|
||||
<label class="btn btn-outline-primary" for="txt-radio" title="This is the traditional HTMLization method.">
|
||||
<i class="bi bi-badge-sd me-1"></i>HTMLize the plaintext
|
||||
</label>
|
||||
<input type="radio" class="btn-check" name="htmlconf" id="html-radio">
|
||||
<label class="btn btn-outline-primary" for="html-radio" title="This is the modern HTMLization method.">
|
||||
<i class="bi bi-badge-hd me-1"></i>Plaintextify the HTML
|
||||
</label>
|
||||
</div>
|
||||
<label class="form-label fw-bold mt-4 mb-2" for="ptsize">Maximum font size</label>
|
||||
<input type="range" class="form-range" min="7" max="16" id="ptsize" oninput="ptdemo.value = ptsize.value">
|
||||
<label class="form-label fw-bold mt-4 mb-2">Page dependencies</label>
|
||||
<div class="btn-group-vertical btn-group-sm d-flex" role="group">
|
||||
<input type="radio" class="btn-check" name="pagedeps" id="inline-radio">
|
||||
<label class="btn btn-outline-primary" for="inline-radio" title="Generate larger, standalone web pages that do not require network access to render.">
|
||||
<i class="bi bi-box me-1"></i>Inline
|
||||
</label>
|
||||
<input type="radio" class="btn-check" name="pagedeps" id="reference-radio">
|
||||
<label class="btn btn-outline-primary" for="reference-radio" title="Generate regular web pages that require network access to render.">
|
||||
<i class="bi bi-link-45deg me-1"></i>Reference
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% analytical_body_bottom %}
|
||||
</body>
|
||||
</html>
|
449
ietf/templates/doc/document_info.html
Normal file
449
ietf/templates/doc/document_info.html
Normal file
|
@ -0,0 +1,449 @@
|
|||
{# Copyright The IETF Trust 2016-2020, All Rights Reserved #}
|
||||
{% load origin %}
|
||||
{% load static %}
|
||||
{% load ietf_filters %}
|
||||
{% load person_filters %}
|
||||
{% origin %}
|
||||
|
||||
<tbody class="meta align-top {% if not document_html %} border-top{% endif %}">
|
||||
<tr>
|
||||
<th scope="row">Document</th>
|
||||
<th scope="row">{% if document_html %}Document type{% else %}Type{% endif %}</th>
|
||||
<td class="edit"></td>
|
||||
<td>
|
||||
{% if doc.get_state_slug == "rfc" and not snapshot %}
|
||||
<span class="text-success">RFC
|
||||
{% if not document_html %}
|
||||
- {{ doc.std_level }}
|
||||
{% else %}
|
||||
<span class="badge rounded-pill badge-{% if not snapshot %}{{ doc|std_level_to_label_format }}{% else %}draft{% endif %}">{{ doc.std_level }}</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
{% if published %}
|
||||
{% if document_html %}<br>{% else %}({% endif %}{{ doc.pub_date|date:"F Y" }}{% if not document_html %}){% endif %}
|
||||
{% else %}
|
||||
<span class="text-muted">(Publication date unknown)</span>
|
||||
{% endif %}
|
||||
{% if document_html %}<br>{% endif %}
|
||||
{% if has_verified_errata or has_errata %}
|
||||
<a class="{% if document_html %}btn btn-danger btn-sm my-1{% else %}badge rounded-pill bg-danger text-decoration-none text-light{% endif %}"
|
||||
href="https://www.rfc-editor.org/errata_search.php?rfc={{ doc.rfc_number }}" title="Click to view errata." rel="nofollow">
|
||||
Errata
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if doc.related_ipr %}
|
||||
<a title="Click to view IPR declarations." class="{% if document_html %}btn btn-warning btn-sm my-1{% else %}badge rounded-pill bg-warning text-decoration-none text-light{% endif %}" href="{% url 'ietf.ipr.views.search' %}?submit=draft&id={{ doc.name }}">IPR</a>
|
||||
{% endif %}
|
||||
{% if obsoleted_by %}<div>Obsoleted by {{ obsoleted_by|urlize_related_source_list:document_html|join:", " }}</div>{% endif %}
|
||||
{% if updated_by %}<div>Updated by {{ updated_by|urlize_related_source_list:document_html|join:", " }}</div>{% endif %}
|
||||
{% if obsoletes %}<div>Obsoletes {{ obsoletes|urlize_related_target_list:document_html|join:", " }}</div>{% endif %}
|
||||
{% if updates %}<div>Updates {{ updates|urlize_related_target_list:document_html|join:", " }}</div>{% endif %}
|
||||
{% if status_changes %}
|
||||
<div>Status changed by {{ status_changes|urlize_related_source_list|join:", " }}</div>
|
||||
{% endif %}
|
||||
{% if proposed_status_changes %}
|
||||
<div>Proposed status changed by {{ proposed_status_changes|urlize_related_source_list|join:", " }}</div>
|
||||
{% endif %}
|
||||
{% if rfc_aliases %}<div>Also known as {{ rfc_aliases|join:", "|urlize_ietf_docs }}</div>{% endif %}
|
||||
{% if draft_name %}
|
||||
<div>
|
||||
Was
|
||||
<a href="{% url 'ietf.doc.views_doc.document_main' name=draft_name %}">{{ draft_name }}</a>
|
||||
{% if submission %}({{ submission|safe }}){% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if snapshot and doc.doc.get_state_slug == 'rfc' %}
|
||||
<div{% if document_html %} class="alert alert-warning small"{% endif %}>This is an older version of an Internet-Draft that was ultimately published as <a href="{% url 'ietf.doc.views_doc.document_html' name=doc.doc.canonical_name %}">{{doc.doc.canonical_name|prettystdname}}</a>.</div>
|
||||
{% elif snapshot and doc.rev != latest_rev %}
|
||||
<div{% if document_html %} class="alert alert-warning small"{% endif %}>This is an older version of an Internet-Draft whose latest revision state is "{{ doc.doc.get_state }}".</div>
|
||||
{% else %}
|
||||
<span class="{% if doc.get_state_slug == 'active' %}text-success{% elif doc.get_state_slug == 'expired' or doc.get_state_slug == 'repl' %}text-danger{% endif %}">{% if snapshot and doc.rev == latest_rev %}{{ doc.doc.get_state }}{% else %}{{ doc.get_state }}{% endif %} Internet-Draft</span>
|
||||
{% if submission %}({{ submission|safe }}){% endif %}
|
||||
{% if resurrected_by %}- resurrect requested by {{ resurrected_by }}{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if doc.get_state_slug != "active" and doc.get_state_slug != "rfc" %}
|
||||
<div class="badge rounded-pill bg-warning{% if not document_html %} float-end{% endif %}">
|
||||
Expired & archived
|
||||
</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% if document_html %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<th scope="row">Select version</th>
|
||||
<td class="edit"></td>
|
||||
<td>
|
||||
{% include "doc/revisions_list.html" with document_html=document_html %}
|
||||
</td>
|
||||
</tr>
|
||||
{% if doc.rev != "00" %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<th scope="row">Compare versions</th>
|
||||
<td class="edit"></td>
|
||||
<td>
|
||||
<a class="btn btn-primary btn-sm" href="{{ settings.RFCDIFF_BASE_URL }}?difftype=--hwdiff&url2={{ doc.name }}-{{ doc.rev }}.txt" title="Inline diff (wdiff)">Inline</a>
|
||||
<a class="btn btn-primary btn-sm" href="{{ settings.RFCDIFF_BASE_URL }}?url2={{ doc.name }}-{{ doc.rev }}.txt" title="Side-by-side diff">Side-by-side</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<th scope="row">Author{{ doc.authors|pluralize }}</th>
|
||||
<td class="edit">
|
||||
{% if can_edit_authors %}
|
||||
<a class="btn btn-primary btn-sm"
|
||||
href="{% url 'ietf.doc.views_doc.edit_authors' name=doc.name %}">Edit</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{# Implementation that uses the current primary email for each author #}
|
||||
{% for author in doc.authors %}
|
||||
{% person_link author %}{% if not forloop.last %},{% endif %}
|
||||
{% endfor %}
|
||||
{% if document_html and not snapshot or document_html and doc.rev == latest_rev%}
|
||||
<br>
|
||||
<a class="btn btn-primary btn-sm mt-1" href="mailto:{{ doc.name }}@ietf.org?subject={{ doc.name}}" title="Send email to the document authors">Email authors</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% if not document_html %}
|
||||
{# FIXME: This shows the date of the last history event, which is not what participants necessarily expect here. #}
|
||||
<tr>
|
||||
<td></td>
|
||||
<th scope="row">Last updated</th>
|
||||
<td class="edit"></td>
|
||||
<td>
|
||||
{{ doc.time|date:"Y-m-d" }}
|
||||
{% if latest_revision and latest_revision.time|date:"Y-m-d" != doc.time|date:"Y-m-d" %}
|
||||
<span class="text-muted">(Latest revision {{ latest_revision.time|date:"Y-m-d" }})</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if replaces or not document_html and can_edit_stream_info %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<th scope="row">Replaces</th>
|
||||
<td class="edit">
|
||||
{% if can_edit_stream_info and not snapshot %}
|
||||
<a class="btn btn-primary btn-sm"
|
||||
href="{% url 'ietf.doc.views_draft.replaces' name=doc.name %}">Edit</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if replaces %}
|
||||
{% if document_html %}
|
||||
{{ replaces|urlize_related_target_list:document_html|join:"<br>" }}
|
||||
{% else %}
|
||||
{{ replaces|urlize_related_target_list:document_html|join:", " }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="text-muted">(None)</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if replaced_by %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<th scope="row">
|
||||
Replaced by
|
||||
</th>
|
||||
<td class="edit">
|
||||
</td>
|
||||
<td>
|
||||
{% if document_html %}
|
||||
{{ replaced_by|urlize_related_source_list:document_html|join:"<br>" }}
|
||||
{% else %}
|
||||
{{ replaced_by|urlize_related_source_list:document_html|join:", " }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if can_view_possibly_replaces %}
|
||||
{% if possibly_replaces %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<th scope="row">
|
||||
Possibly Replaces
|
||||
</th>
|
||||
<td class="edit">
|
||||
{% if can_edit_replaces and not snapshot %}
|
||||
<a class="btn btn-primary btn-sm"
|
||||
href="{% url 'ietf.doc.views_draft.review_possibly_replaces' name=doc.name %}">
|
||||
Edit
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if document_html %}
|
||||
{{ possibly_replaces|urlize_related_target_list:document_html|join:"<br>" }}
|
||||
{% else %}
|
||||
{{ possibly_replaces|urlize_related_target_list:document_html|join:", " }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if possibly_replaced_by %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<th scope="row">
|
||||
Possibly Replaced By
|
||||
</th>
|
||||
<td class="edit">
|
||||
{% if can_edit_replaces and not snapshot %}
|
||||
{% comment %}<a class="btn btn-primary btn-sm"
|
||||
href="{% url 'ietf.doc.views_draft.review_possibly_replaces' name=doc.name %}">Edit</a>{% endcomment %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if document_html %}
|
||||
{{ possibly_replaced_by|urlize_related_source_list:document_html|join:"<br>" }}
|
||||
{% else %}
|
||||
{{ possibly_replaced_by|urlize_related_source_list:document_html|join:", " }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<th scope="row">
|
||||
RFC stream
|
||||
</th>
|
||||
<td class="edit">
|
||||
{% if can_change_stream and not snapshot %}
|
||||
<a class="btn btn-primary btn-sm"
|
||||
href="{% url 'ietf.doc.views_draft.change_stream' name=doc.name %}">
|
||||
Edit
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td {% if stream_desc == "(None)" %}class="text-muted"{%endif%}>
|
||||
{% if stream_desc != "(None)" %}
|
||||
{% if doc.stream.name|lower in 'iab,irtf,ise,editorial' %}
|
||||
<a href="{% url 'ietf.group.views.stream_documents' acronym=doc.stream.name|lower %}">
|
||||
{% endif %}
|
||||
{% if document_html %}
|
||||
{% if doc.stream.name|lower in 'iab,ietf,irtf' %}
|
||||
<img alt="{{ doc.stream.name|upper }} Logo"
|
||||
title="{{ stream_desc }}"
|
||||
class="w-25 mt-1"
|
||||
{% if doc.stream.name|lower == 'iab' %}
|
||||
src="{% static 'ietf/images/iab-logo.svg' %}"
|
||||
{% elif doc.stream.name|lower == 'ietf' %}
|
||||
src="{% static 'ietf/images/ietf-logo.svg' %}"
|
||||
{% elif doc.stream.name|lower == 'irtf' %}
|
||||
src="{% static 'ietf/images/irtf-logo.svg' %}"
|
||||
{% endif %}
|
||||
>
|
||||
{% else %}
|
||||
{{ stream_desc }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{{ stream_desc }}
|
||||
{% endif %}
|
||||
{% if doc.stream.name|lower in 'iab,irtf,ise,editorial' %}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{{ stream_desc }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% if doc.get_state_slug != "rfc" and not snapshot %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<th scope="row">
|
||||
Intended RFC status
|
||||
</th>
|
||||
<td class="edit">
|
||||
{% if can_edit_stream_info and not snapshot %}
|
||||
<a class="btn btn-primary btn-sm"
|
||||
href="{% url 'ietf.doc.views_draft.change_intention' name=doc.name %}">
|
||||
Edit
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if doc.intended_std_level %}
|
||||
{{ doc.intended_std_level }}
|
||||
{% else %}
|
||||
<span class="text-muted">
|
||||
(None)
|
||||
</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<th scope="row">
|
||||
{% if document_html %}Other formats{% else %}Formats{% endif %}
|
||||
</th>
|
||||
<td class="edit">
|
||||
</td>
|
||||
<td>
|
||||
{% if document_html %}
|
||||
{% include "doc/document_format_buttons.html" with skip_format="htmlized" %}
|
||||
{% else %}
|
||||
{% include "doc/document_format_buttons.html" %}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% for check in doc.submission.latest_checks %}
|
||||
{% if check.passed != None and check.symbol.strip %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<th scope="row">
|
||||
{{ check.checker|title }}
|
||||
</th>
|
||||
<td class="edit">
|
||||
</td>
|
||||
<td>
|
||||
{% if check.errors or check.warnings %}
|
||||
<span class="checker-warning"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#check-{{ check.pk }}"
|
||||
title="{{ check.checker|title }} returned warnings or errors.">
|
||||
{{ check.symbol|safe }}
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="checker-success"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#check-{{ check.pk }}"
|
||||
title="{{ check.checker|title }} passed">
|
||||
{{ check.symbol|safe }}
|
||||
</span>
|
||||
{% endif %}
|
||||
<a href="#"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#check-{{ check.pk }}">
|
||||
{{ check.errors }} errors, {{ check.warnings }} warnings
|
||||
</a>
|
||||
{% include "doc/yang-check-modal-overlay.html" %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if not document_html %}
|
||||
{% if review_assignments or can_request_review %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<th scope="row">
|
||||
Reviews
|
||||
</th>
|
||||
<td class="edit">
|
||||
</td>
|
||||
<td>
|
||||
{% for review_assignment in review_assignments %}
|
||||
{% include "doc/review_assignment_summary.html" with current_doc_name=doc.name current_rev=doc.rev %}
|
||||
{% endfor %}
|
||||
{% if no_review_from_teams %}
|
||||
{% for team in no_review_from_teams %}
|
||||
{{ team.acronym.upper }}{% if not forloop.last %},{% endif %}
|
||||
{% endfor %}
|
||||
will not review this version
|
||||
{% endif %}
|
||||
{% if can_request_review or can_submit_unsolicited_review_for_teams %}
|
||||
<div {% if review_assignments or no_review_from_teams %}class="mt-3"{% endif %}>
|
||||
{% if can_request_review %}
|
||||
<a class="btn btn-primary btn-sm"
|
||||
href="{% url "ietf.doc.views_review.request_review" doc.name %}">
|
||||
<i class="bi bi-check-circle">
|
||||
</i>
|
||||
Request review
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if can_submit_unsolicited_review_for_teams|length == 1 %}
|
||||
<a class="btn btn-primary btn-sm"
|
||||
href="{% url "ietf.doc.views_review.complete_review" doc.name can_submit_unsolicited_review_for_teams.0.acronym %}">
|
||||
<i class="bi bi-pencil-square">
|
||||
</i>
|
||||
Submit unsolicited review
|
||||
</a>
|
||||
{% elif can_submit_unsolicited_review_for_teams %}
|
||||
<a class="btn btn-primary btn-sm"
|
||||
href="{% url "ietf.doc.views_review.submit_unsolicited_review_choose_team" doc.name %}">
|
||||
<i class="bi bi-pencil-square">
|
||||
</i>
|
||||
Submit unsolicited review
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if conflict_reviews %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<th scope="row">
|
||||
IETF conflict review
|
||||
</th>
|
||||
<td class="edit">
|
||||
</td>
|
||||
<td>
|
||||
{{ conflict_reviews|join:", "|urlize_ietf_docs }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% with doc.docextresource_set.all as resources %}
|
||||
{% if document_html and resources or document_html and doc.group and doc.group.list_archive %}
|
||||
{% if resources or doc.group and doc.group.list_archive or can_edit_stream_info or can_edit_individual %}
|
||||
<tr>
|
||||
<td>
|
||||
</td>
|
||||
<th scope="row">
|
||||
Additional resources
|
||||
</th>
|
||||
<td class="edit">
|
||||
{% if can_edit_stream_info or can_edit_individual %}
|
||||
<a class="btn btn-primary btn-sm"
|
||||
href="{% url 'ietf.doc.views_draft.edit_doc_extresources' name=doc.name %}">
|
||||
Edit
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if resources or doc.group and doc.group.list_archive %}
|
||||
{% for resource in resources|dictsort:"display_name" %}
|
||||
{% if resource.name.type.slug == 'url' or resource.name.type.slug == 'email' %}
|
||||
<a href="{{ resource.value }}" title="{{ resource.name.name }}">
|
||||
{% firstof resource.display_name resource.name.name %}
|
||||
</a>
|
||||
<br>
|
||||
{# Maybe make how a resource displays itself a method on the class so templates aren't doing this switching #}
|
||||
{% else %}
|
||||
<span title="{{ resource.name.name }}">
|
||||
{% firstof resource.display_name resource.name.name %}: {{ resource.value|escape }}
|
||||
</span>
|
||||
<br>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if doc.group and doc.group.list_archive %}
|
||||
{% if doc.group.list_archive|startswith:settings.MAILING_LIST_ARCHIVE_URL %}
|
||||
<a href="{{ doc.group.list_archive }}?q={{ doc.name }}">
|
||||
Mailing list discussion
|
||||
</a>
|
||||
{% elif doc.group.list_archive|is_valid_url %}
|
||||
<a href="{{ doc.group.list_archive }}">
|
||||
Mailing list discussion
|
||||
</a>
|
||||
{% else %}
|
||||
{{ doc.group.list_archive|urlencode }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</tbody>
|
|
@ -1,139 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
{% load ietf_filters static %}
|
||||
{# Copyright The IETF Trust 2021, All Rights Reserved #}
|
||||
{% load origin %}
|
||||
{% origin %}
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>
|
||||
{% block title %}No title{% endblock %}
|
||||
</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>
|
||||
@media only screen
|
||||
and (min-width: 992px)
|
||||
and (max-width: 1199px) {
|
||||
body { font-size: 14pt; }
|
||||
div.content { width: 96ex; margin: 0 auto; }
|
||||
}
|
||||
@media only screen
|
||||
and (min-width: 768px)
|
||||
and (max-width: 991px) {
|
||||
body { font-size: 14pt; }
|
||||
div.content { width: 96ex; margin: 0 auto; }
|
||||
}
|
||||
@media only screen
|
||||
and (min-width: 480px)
|
||||
and (max-width: 767px) {
|
||||
body { font-size: 11pt; }
|
||||
div.content { width: 96ex; margin: 0 auto; }
|
||||
}
|
||||
@media only screen
|
||||
and (max-width: 479px) {
|
||||
body { font-size: 8pt; }
|
||||
div.content { width: 96ex; margin: 0 auto; }
|
||||
}
|
||||
@media only screen
|
||||
and (min-width : 375px)
|
||||
and (max-width : 667px) {
|
||||
body { font-size: 9.5pt; }
|
||||
div.content { width: 96ex; margin: 0; }
|
||||
}
|
||||
@media only screen
|
||||
and (min-width: 1200px) {
|
||||
body { font-size: 10pt; margin: 0 4em; }
|
||||
div.content { width: 96ex; margin: 0; }
|
||||
}
|
||||
h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
|
||||
font-weight: bold;
|
||||
/* line-height: 0pt; */
|
||||
display: inline;
|
||||
white-space: pre;
|
||||
font-family: monospace;
|
||||
font-size: 1em;
|
||||
font-weight: bold;
|
||||
}
|
||||
pre {
|
||||
font-size: 1em;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
.pre {
|
||||
white-space: pre;
|
||||
font-family: monospace;
|
||||
}
|
||||
.header{
|
||||
font-weight: bold;
|
||||
}
|
||||
.newpage {
|
||||
page-break-before: always;
|
||||
}
|
||||
.invisible {
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
}
|
||||
@media print {
|
||||
body {
|
||||
margin-top: 5em;
|
||||
font-family: monospace;
|
||||
font-size: 10.5pt;
|
||||
}
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
a:link, a:visited {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
.noprint {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@media screen {
|
||||
.grey, .grey a:link, .grey a:visited {
|
||||
color: #777;
|
||||
}
|
||||
.meta-info {
|
||||
background-color: #EEE;
|
||||
width: 96ex;
|
||||
}
|
||||
.top {
|
||||
border-top: 7px solid #EEE;
|
||||
}
|
||||
.pad {
|
||||
padding-top: 7px;
|
||||
line-height: 24px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
.bgwhite { background-color: white; }
|
||||
.bgred { background-color: #F44; }
|
||||
.bggrey { background-color: #666; }
|
||||
.bgbrown { background-color: #840; }
|
||||
.bgorange { background-color: #FA0; }
|
||||
.bgyellow { background-color: #EE0; }
|
||||
.bgmagenta{ background-color: #F4F; }
|
||||
.bgblue { background-color: #66F; }
|
||||
.bgcyan { background-color: #4DD; }
|
||||
.bggreen { background-color: #4F4; }
|
||||
|
||||
.legend { font-size: 90%; }
|
||||
.cplate { font-size: 70%; border: solid grey 1px; }
|
||||
}
|
||||
|
||||
{% block morecss %}{% endblock %}
|
||||
</style>
|
||||
{% block pagehead %}{% endblock %}
|
||||
{% include "base/icons.html" %}
|
||||
</head>
|
||||
<body {% block bodyAttrs %}{% endblock %}>
|
||||
<div class="content" id="content">
|
||||
{% block content %}{{ content|safe }}{% endblock %}
|
||||
{% block content_end %}{% endblock %}
|
||||
</div>
|
||||
{% block footer %}{% endblock %}
|
||||
{% block js %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
|
@ -1,4 +1,4 @@
|
|||
{% autoescape off %}As you requsted, the Internet Draft {{ doc.file_tag }}
|
||||
{% autoescape off %}As you requested, the Internet Draft {{ doc.file_tag }}
|
||||
has been resurrected.
|
||||
|
||||
Datatracker URL: {{ url }}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue