ci: merge main to release

This commit is contained in:
Robert Sparks 2023-06-22 12:17:07 -05:00 committed by GitHub
commit df3366b789
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 344 additions and 155 deletions

22
.pnp.cjs generated
View file

@ -65,7 +65,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["eslint-plugin-promise", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.1"],\
["eslint-plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:9.14.1"],\
["file-saver", "npm:2.0.5"],\
["highcharts", "npm:11.0.1"],\
["highcharts", "npm:11.1.0"],\
["html-validate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:7.18.1"],\
["ical.js", "npm:1.5.0"],\
["jquery", "npm:3.7.0"],\
@ -84,7 +84,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["pinia", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.1.3"],\
["pinia-plugin-persist", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:1.0.0"],\
["pug", "npm:3.0.2"],\
["sass", "npm:1.62.1"],\
["sass", "npm:1.63.4"],\
["seedrandom", "npm:3.0.5"],\
["select2", "npm:4.1.0-rc.0"],\
["select2-bootstrap-5-theme", "npm:1.3.0"],\
@ -5487,10 +5487,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
}]\
]],\
["highcharts", [\
["npm:11.0.1", {\
"packageLocation": "./.yarn/cache/highcharts-npm-11.0.1-05a14e3887-773a7b8765.zip/node_modules/highcharts/",\
["npm:11.1.0", {\
"packageLocation": "./.yarn/cache/highcharts-npm-11.1.0-0d42a04430-f9b8cdc38b.zip/node_modules/highcharts/",\
"packageDependencies": [\
["highcharts", "npm:11.0.1"]\
["highcharts", "npm:11.1.0"]\
],\
"linkType": "HARD"\
}]\
@ -7895,7 +7895,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["eslint-plugin-promise", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:6.1.1"],\
["eslint-plugin-vue", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:9.14.1"],\
["file-saver", "npm:2.0.5"],\
["highcharts", "npm:11.0.1"],\
["highcharts", "npm:11.1.0"],\
["html-validate", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:7.18.1"],\
["ical.js", "npm:1.5.0"],\
["jquery", "npm:3.7.0"],\
@ -7914,7 +7914,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["pinia", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:2.1.3"],\
["pinia-plugin-persist", "virtual:dc3fc578bfa5e06182a4d2be39ede0bc5b74940b1ffe0d70c26892ab140a4699787750fba175dc306292e80b4aa2c8c5f68c2a821e69b2c37e360c0dff36ff66#npm:1.0.0"],\
["pug", "npm:3.0.2"],\
["sass", "npm:1.62.1"],\
["sass", "npm:1.63.4"],\
["seedrandom", "npm:3.0.5"],\
["select2", "npm:4.1.0-rc.0"],\
["select2-bootstrap-5-theme", "npm:1.3.0"],\
@ -7998,10 +7998,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
],\
"linkType": "HARD"\
}],\
["npm:1.62.1", {\
"packageLocation": "./.yarn/cache/sass-npm-1.62.1-c16d65fd28-1b1b3584b3.zip/node_modules/sass/",\
["npm:1.63.4", {\
"packageLocation": "./.yarn/cache/sass-npm-1.63.4-bf5f3496c2-12bde5beff.zip/node_modules/sass/",\
"packageDependencies": [\
["sass", "npm:1.62.1"],\
["sass", "npm:1.63.4"],\
["chokidar", "npm:3.5.3"],\
["immutable", "npm:4.0.0"],\
["source-map-js", "npm:1.0.2"]\
@ -8716,7 +8716,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["less", null],\
["postcss", "npm:8.4.23"],\
["rollup", "npm:3.21.6"],\
["sass", "npm:1.62.1"],\
["sass", "npm:1.63.4"],\
["stylus", null],\
["sugarss", null],\
["terser", null]\

Binary file not shown.

View file

@ -17,8 +17,8 @@
"luxon": "3.3.0"
},
"devDependencies": {
"eslint": "8.41.0",
"eslint-config-standard": "17.0.0",
"eslint": "8.42.0",
"eslint-config-standard": "17.1.0",
"eslint-plugin-import": "2.27.5",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-promise": "6.1.1",
@ -111,9 +111,9 @@
}
},
"node_modules/@eslint/js": {
"version": "8.41.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.41.0.tgz",
"integrity": "sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==",
"version": "8.42.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.42.0.tgz",
"integrity": "sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@ -126,9 +126,9 @@
"dev": true
},
"node_modules/@humanwhocodes/config-array": {
"version": "0.11.8",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
"integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==",
"version": "0.11.10",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz",
"integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==",
"dev": true,
"dependencies": {
"@humanwhocodes/object-schema": "^1.2.1",
@ -1718,16 +1718,16 @@
}
},
"node_modules/eslint": {
"version": "8.41.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.41.0.tgz",
"integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==",
"version": "8.42.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.42.0.tgz",
"integrity": "sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.4.0",
"@eslint/eslintrc": "^2.0.3",
"@eslint/js": "8.41.0",
"@humanwhocodes/config-array": "^0.11.8",
"@eslint/js": "8.42.0",
"@humanwhocodes/config-array": "^0.11.10",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
"ajv": "^6.10.0",
@ -1774,9 +1774,9 @@
}
},
"node_modules/eslint-config-standard": {
"version": "17.0.0",
"resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.0.0.tgz",
"integrity": "sha512-/2ks1GKyqSOkH7JFvXJicu0iMpoojkwB+f5Du/1SC0PtBL+s8v30k9njRZ21pm2drKYm2342jFnGWzttxPmZVg==",
"version": "17.1.0",
"resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz",
"integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==",
"dev": true,
"funding": [
{
@ -1792,10 +1792,13 @@
"url": "https://feross.org/support"
}
],
"engines": {
"node": ">=12.0.0"
},
"peerDependencies": {
"eslint": "^8.0.1",
"eslint-plugin-import": "^2.25.2",
"eslint-plugin-n": "^15.0.0",
"eslint-plugin-n": "^15.0.0 || ^16.0.0 ",
"eslint-plugin-promise": "^6.0.0"
}
},
@ -6326,9 +6329,9 @@
}
},
"@eslint/js": {
"version": "8.41.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.41.0.tgz",
"integrity": "sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==",
"version": "8.42.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.42.0.tgz",
"integrity": "sha512-6SWlXpWU5AvId8Ac7zjzmIOqMOba/JWY8XZ4A7q7Gn1Vlfg/SFFIlrtHXt9nPn4op9ZPAkl91Jao+QQv3r/ukw==",
"dev": true
},
"@gar/promisify": {
@ -6338,9 +6341,9 @@
"dev": true
},
"@humanwhocodes/config-array": {
"version": "0.11.8",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
"integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==",
"version": "0.11.10",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz",
"integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==",
"dev": true,
"requires": {
"@humanwhocodes/object-schema": "^1.2.1",
@ -7531,16 +7534,16 @@
"dev": true
},
"eslint": {
"version": "8.41.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.41.0.tgz",
"integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==",
"version": "8.42.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.42.0.tgz",
"integrity": "sha512-ulg9Ms6E1WPf67PHaEY4/6E2tEn5/f7FXGzr3t9cBMugOmf1INYvuUwwh1aXQN4MfJ6a5K2iNwP3w4AColvI9A==",
"dev": true,
"requires": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.4.0",
"@eslint/eslintrc": "^2.0.3",
"@eslint/js": "8.41.0",
"@humanwhocodes/config-array": "^0.11.8",
"@eslint/js": "8.42.0",
"@humanwhocodes/config-array": "^0.11.10",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
"ajv": "^6.10.0",
@ -7589,9 +7592,9 @@
}
},
"eslint-config-standard": {
"version": "17.0.0",
"resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.0.0.tgz",
"integrity": "sha512-/2ks1GKyqSOkH7JFvXJicu0iMpoojkwB+f5Du/1SC0PtBL+s8v30k9njRZ21pm2drKYm2342jFnGWzttxPmZVg==",
"version": "17.1.0",
"resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz",
"integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==",
"dev": true,
"requires": {}
},

View file

@ -14,8 +14,8 @@
"luxon": "3.3.0"
},
"devDependencies": {
"eslint": "8.41.0",
"eslint-config-standard": "17.0.0",
"eslint": "8.42.0",
"eslint-config-standard": "17.1.0",
"eslint-plugin-import": "2.27.5",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-promise": "6.1.1",

View file

@ -9,7 +9,7 @@
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"@octokit/core": "^4.2.1",
"@octokit/core": "^4.2.4",
"luxon": "^3.3.0"
}
},
@ -25,9 +25,9 @@
}
},
"node_modules/@octokit/core": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.2.1.tgz",
"integrity": "sha512-tEDxFx8E38zF3gT7sSMDrT1tGumDgsw5yPG6BBh/X+5ClIQfMH/Yqocxz1PnHx6CHyF6pxmovUTOfZAUvQ0Lvw==",
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.2.4.tgz",
"integrity": "sha512-rYKilwgzQ7/imScn3M9/pFfUf4I1AZEH3KhyJmtPdE2zfaXAn2mFfUy4FbKewzc2We5y/LlKLj36fWJLKC2SIQ==",
"dependencies": {
"@octokit/auth-token": "^3.0.0",
"@octokit/graphql": "^5.0.0",
@ -215,9 +215,9 @@
}
},
"@octokit/core": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.2.1.tgz",
"integrity": "sha512-tEDxFx8E38zF3gT7sSMDrT1tGumDgsw5yPG6BBh/X+5ClIQfMH/Yqocxz1PnHx6CHyF6pxmovUTOfZAUvQ0Lvw==",
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.2.4.tgz",
"integrity": "sha512-rYKilwgzQ7/imScn3M9/pFfUf4I1AZEH3KhyJmtPdE2zfaXAn2mFfUy4FbKewzc2We5y/LlKLj36fWJLKC2SIQ==",
"requires": {
"@octokit/auth-token": "^3.0.0",
"@octokit/graphql": "^5.0.0",

View file

@ -10,7 +10,7 @@
"author": "",
"license": "ISC",
"dependencies": {
"@octokit/core": "^4.2.1",
"@octokit/core": "^4.2.4",
"luxon": "^3.3.0"
}
}

View file

@ -1,6 +1,9 @@
server {
listen 8000 default_server;
listen [::]:8000 default_server;
proxy_read_timeout 1d;
proxy_send_timeout 1d;
root /var/www/html;
index index.html index.htm index.nginx-debian.html;

View file

@ -22,7 +22,6 @@ echo "Fix chromedriver /dev/shm permissions..."
sudo chmod 1777 /dev/shm
# Run nginx
echo "Starting nginx..."
sudo nginx
@ -30,6 +29,9 @@ sudo nginx
echo "Compiling native node packages..."
yarn rebuild
# Silence Browserlist warnings
export BROWSERSLIST_IGNORE_OLD_DATA=1
# Generate static assets
echo "Building static assets... (this could take a minute or two)"
yarn build

View file

@ -12,12 +12,11 @@ from django.core.exceptions import ObjectDoesNotExist
import debug # pyflakes:ignore
import tastypie
import tastypie.resources
import tastypie.serializers
from tastypie.api import Api
from tastypie.bundle import Bundle
from tastypie.exceptions import ApiFieldError
from tastypie.serializers import Serializer # pyflakes:ignore (we're re-exporting this)
from tastypie.fields import ApiField
_api_list = []
@ -152,3 +151,8 @@ class ToOneField(tastypie.fields.ToOneField):
dehydrated = self.dehydrate_related(fk_bundle, fk_resource, for_list=for_list)
fk_resource._meta.cache.set(cache_key, dehydrated)
return dehydrated
class Serializer(tastypie.serializers.Serializer):
def format_datetime(self, data):
return data.astimezone(datetime.timezone.utc).replace(tzinfo=None).isoformat(timespec="seconds") + "Z"

View file

@ -1,6 +1,7 @@
# Copyright The IETF Trust 2007-2020, All Rights Reserved
# -*- coding: utf-8 -*-
import debug # pyflakes:ignore
import datetime
import unicodedata
@ -8,8 +9,12 @@ import unicodedata
from django.contrib.syndication.views import Feed, FeedDoesNotExist
from django.utils.feedgenerator import Atom1Feed, Rss201rev2Feed
from django.urls import reverse as urlreverse
from django.template.defaultfilters import truncatewords, truncatewords_html, date as datefilter
from django.template.defaultfilters import linebreaks # type: ignore
from django.template.defaultfilters import (
truncatewords,
truncatewords_html,
date as datefilter,
)
from django.template.defaultfilters import linebreaks # type: ignore
from django.utils import timezone
from django.utils.html import strip_tags
@ -21,12 +26,12 @@ from ietf.utils.timezone import RPC_TZINFO
def strip_control_characters(s):
"""Remove Unicode control / non-printing characters from a string"""
replacement_char = unicodedata.lookup('REPLACEMENT CHARACTER')
return ''.join(
replacement_char if unicodedata.category(c)[0] == 'C' else c
for c in s
replacement_char = unicodedata.lookup("REPLACEMENT CHARACTER")
return "".join(
replacement_char if unicodedata.category(c)[0] == "C" else c for c in s
)
class DocumentChangesFeed(Feed):
feed_type = Atom1Feed
@ -39,25 +44,37 @@ class DocumentChangesFeed(Feed):
def link(self, obj):
if obj is None:
raise FeedDoesNotExist
return urlreverse('ietf.doc.views_doc.document_history', kwargs=dict(name=obj.canonical_name()))
return urlreverse(
"ietf.doc.views_doc.document_history",
kwargs=dict(name=obj.canonical_name()),
)
def subtitle(self, obj):
return "History of change entries for %s." % obj.display_name()
def items(self, obj):
events = obj.docevent_set.all().order_by("-time","-id").select_related("by", "newrevisiondocevent", "submissiondocevent")
events = (
obj.docevent_set.all()
.order_by("-time", "-id")
.select_related("by", "newrevisiondocevent", "submissiondocevent")
)
augment_events_with_revision(obj, events)
return events
def item_title(self, item):
return strip_control_characters("[%s] %s [rev. %s]" % (
item.by,
truncatewords(strip_tags(item.desc), 15),
item.rev,
))
return strip_control_characters(
"[%s] %s [rev. %s]"
% (
item.by,
truncatewords(strip_tags(item.desc), 15),
item.rev,
)
)
def item_description(self, item):
return strip_control_characters(truncatewords_html(format_textarea(item.desc), 20))
return strip_control_characters(
truncatewords_html(format_textarea(item.desc), 20)
)
def item_pubdate(self, item):
return item.time
@ -66,17 +83,28 @@ class DocumentChangesFeed(Feed):
return str(item.by)
def item_link(self, item):
return urlreverse('ietf.doc.views_doc.document_history', kwargs=dict(name=item.doc.canonical_name())) + "#history-%s" % item.pk
return (
urlreverse(
"ietf.doc.views_doc.document_history",
kwargs=dict(name=item.doc.canonical_name()),
)
+ "#history-%s" % item.pk
)
class InLastCallFeed(Feed):
title = "Documents in Last Call"
subtitle = "Announcements for documents in last call."
feed_type = Atom1Feed
author_name = 'IESG Secretary'
author_name = "IESG Secretary"
link = "/doc/iesg/last-call/"
def items(self):
docs = list(Document.objects.filter(type="draft", states=State.objects.get(type="draft-iesg", slug="lc")))
docs = list(
Document.objects.filter(
type="draft", states=State.objects.get(type="draft-iesg", slug="lc")
)
)
for d in docs:
d.lc_event = d.latest_event(LastCallDocEvent, type="sent_last_call")
@ -86,9 +114,11 @@ class InLastCallFeed(Feed):
return docs
def item_title(self, item):
return "%s (%s - %s)" % (item.name,
datefilter(item.lc_event.time, "F j"),
datefilter(item.lc_event.expires, "F j, Y"))
return "%s (%s - %s)" % (
item.name,
datefilter(item.lc_event.time, "F j"),
datefilter(item.lc_event.expires, "F j, Y"),
)
def item_description(self, item):
return strip_control_characters(linebreaks(item.lc_event.desc))
@ -96,33 +126,55 @@ class InLastCallFeed(Feed):
def item_pubdate(self, item):
return item.lc_event.time
class Rss201WithNamespacesFeed(Rss201rev2Feed):
def root_attributes(self):
attrs = super(Rss201WithNamespacesFeed, self).root_attributes()
attrs['xmlns:dcterms'] = 'http://purl.org/dc/terms/'
attrs['xmlns:media'] = 'http://search.yahoo.com/mrss/'
attrs['xmlns:xsi'] = 'http://www.w3.org/2001/XMLSchema-instance'
attrs["xmlns:dcterms"] = "http://purl.org/dc/terms/"
attrs["xmlns:media"] = "http://search.yahoo.com/mrss/"
attrs["xmlns:xsi"] = "http://www.w3.org/2001/XMLSchema-instance"
return attrs
def add_item_elements(self, handler, item):
super(Rss201WithNamespacesFeed, self).add_item_elements(handler, item)
for element_name in ['abstract','accessRights', 'format', 'publisher',]:
dc_item_name = 'dcterms_%s' % element_name
dc_element_name = 'dcterms:%s' % element_name
attrs= {'xsi:type':'dcterms:local'} if element_name == 'publisher' else {}
for element_name in [
"abstract",
"accessRights",
"format",
"publisher",
]:
dc_item_name = "dcterms_%s" % element_name
dc_element_name = "dcterms:%s" % element_name
attrs = {"xsi:type": "dcterms:local"} if element_name == "publisher" else {}
if dc_item_name in item and item[dc_item_name] is not None:
handler.addQuickElement(dc_element_name,item[dc_item_name],attrs)
handler.addQuickElement(dc_element_name, item[dc_item_name], attrs)
if 'doi' in item and item['doi'] is not None:
handler.addQuickElement('dcterms:identifier',item['doi'],{'xsi:type':'dcterms:doi'})
if 'doiuri' in item and item['doiuri'] is not None:
handler.addQuickElement('dcterms:identifier',item['doiuri'],{'xsi:type':'dcterms:uri'})
if "doi" in item and item["doi"] is not None:
handler.addQuickElement(
"dcterms:identifier", item["doi"], {"xsi:type": "dcterms:doi"}
)
if "doiuri" in item and item["doiuri"] is not None:
handler.addQuickElement(
"dcterms:identifier", item["doiuri"], {"xsi:type": "dcterms:uri"}
)
# TODO: consider using media:group
if "media_contents" in item and item["media_contents"] is not None:
for media_content in item["media_contents"]:
handler.startElement(
"media:content",
{
"url": media_content["url"],
"type": media_content["media_type"],
},
)
if "is_format_of" in media_content:
handler.addQuickElement(
"dcterms:isFormatOf", media_content["is_format_of"]
)
handler.endElement("media:content")
if 'media_content' in item and item['media_content'] is not None:
handler.startElement('media:content',{'url':item['media_content']['url'],'type':'text/plain'})
handler.addQuickElement('dcterms:isFormatOf',item['media_content']['link_url'])
handler.endElement('media:content')
class RfcFeed(Feed):
feed_type = Rss201WithNamespacesFeed
@ -130,55 +182,96 @@ class RfcFeed(Feed):
author_name = "RFC Editor"
link = "https://www.rfc-editor.org/rfc-index2.html"
def get_object(self,request,year=None):
def get_object(self, request, year=None):
self.year = year
def items(self):
if self.year:
# Find published RFCs based on their official publication year
start_of_year = datetime.datetime(int(self.year), 1, 1, tzinfo=RPC_TZINFO)
start_of_next_year = datetime.datetime(int(self.year) + 1, 1, 1, tzinfo=RPC_TZINFO)
start_of_next_year = datetime.datetime(
int(self.year) + 1, 1, 1, tzinfo=RPC_TZINFO
)
rfc_events = DocEvent.objects.filter(
type='published_rfc',
type="published_rfc",
time__gte=start_of_year,
time__lt=start_of_next_year,
).order_by('-time')
).order_by("-time")
else:
cutoff = timezone.now() - datetime.timedelta(days=8)
rfc_events = DocEvent.objects.filter(type='published_rfc',time__gte=cutoff).order_by('-time')
rfc_events = DocEvent.objects.filter(
type="published_rfc", time__gte=cutoff
).order_by("-time")
results = [(e.doc, e.time) for e in rfc_events]
for doc,time in results:
for doc, time in results:
doc.publication_time = time
return [doc for doc,time in results]
return [doc for doc, time in results]
def item_title(self, item):
return "%s : %s" % (item.canonical_name(),item.title)
return "%s : %s" % (item.canonical_name(), item.title)
def item_description(self, item):
return item.abstract
def item_link(self, item):
return "https://rfc-editor.org/info/%s"%item.canonical_name()
return "https://rfc-editor.org/info/%s" % item.canonical_name()
def item_pubdate(self, item):
return item.publication_time
def item_extra_kwargs(self, item):
extra = super(RfcFeed, self).item_extra_kwargs(item)
extra.update({'dcterms_accessRights': 'gratis'})
extra.update({'dcterms_format': 'text/html'})
extra.update({'media_content': {'url': 'https://rfc-editor.org/rfc/%s.txt' % item.canonical_name(),
'link_url': self.item_link(item)
}
})
extra.update({'doi':'10.17487/%s' % item.canonical_name().upper()})
extra.update({'doiuri':'http://dx.doi.org/10.17487/%s' % item.canonical_name().upper()})
extra.update({"dcterms_accessRights": "gratis"})
extra.update({"dcterms_format": "text/html"})
media_contents = []
if int(item.rfc_number()) < 8650:
if int(item.rfc_number()) not in [8, 9, 51, 418, 500, 530, 589]:
for fmt, media_type in [("txt", "text/plain"), ("html", "text/html")]:
media_contents.append(
{
"url": f"https://rfc-editor.org/rfc/{item.canonical_name()}.{fmt}",
"media_type": media_type,
"is_format_of": self.item_link(item),
}
)
if int(item.rfc_number()) not in [571, 587]:
media_contents.append(
{
"url": f"https://www.rfc-editor.org/rfc/pdfrfc/{item.canonical_name()}.txt.pdf",
"media_type": "application/pdf",
"is_format_of": self.item_link(item),
}
)
else:
media_contents.append(
{
"url": f"https://www.rfc-editor.org/rfc/{item.canonical_name()}.xml",
"media_type": "application/rfc+xml",
}
)
for fmt, media_type in [
("txt", "text/plain"),
("html", "text/html"),
("pdf", "application/pdf"),
]:
media_contents.append(
{
"url": f"https://rfc-editor.org/rfc/{item.canonical_name()}.{fmt}",
"media_type": media_type,
"is_format_of": f"https://www.rfc-editor.org/rfc/{item.canonical_name()}.xml",
}
)
extra.update({"media_contents": media_contents})
extra.update({"doi": "10.17487/%s" % item.canonical_name().upper()})
extra.update(
{"doiuri": "http://dx.doi.org/10.17487/%s" % item.canonical_name().upper()}
)
#TODO
# R104 Publisher (Mandatory - but we need a string from them first)
extra.update({'dcterms_publisher':'rfc-editor.org'})
extra.update({"dcterms_publisher": "rfc-editor.org"})
#TODO MAYBE (Optional stuff)
# TODO MAYBE (Optional stuff)
# R108 License
# R115 Creator/Contributor (which would we use?)
# F305 Checksum (do they use it?) (or should we put the our digital signature in here somewhere?)
@ -188,4 +281,3 @@ class RfcFeed(Feed):
# R118 Keyword
return extra

View file

@ -1911,11 +1911,31 @@ class DocTestCase(TestCase):
self.assertContains(r, doc.name)
def test_rfc_feed(self):
WgRfcFactory()
rfc = WgRfcFactory(alias2__name="rfc9000")
DocEventFactory(doc=rfc, type="published_rfc")
r = self.client.get("/feed/rfc/")
self.assertTrue(r.status_code, 200)
q = PyQuery(r.content[39:]) # Strip off the xml declaration
self.assertEqual(len(q("item")), 1)
item = q("item")[0]
media_content = item.findall("{http://search.yahoo.com/mrss/}content")
self.assertEqual(len(media_content),4)
types = set([m.attrib["type"] for m in media_content])
self.assertEqual(types, set(["application/rfc+xml", "text/plain", "text/html", "application/pdf"]))
rfcs_2016 = WgRfcFactory.create_batch(3) # rfc numbers will be well below v3
for rfc in rfcs_2016:
e = DocEventFactory(doc=rfc, type="published_rfc")
e.time = e.time.replace(year=2016)
e.save()
r = self.client.get("/feed/rfc/2016")
self.assertTrue(r.status_code, 200)
q = PyQuery(r.content[39:])
self.assertEqual(len(q("item")), 3)
item = q("item")[0]
media_content = item.findall("{http://search.yahoo.com/mrss/}content")
self.assertEqual(len(media_content), 3)
types = set([m.attrib["type"] for m in media_content])
self.assertEqual(types, set(["text/plain", "text/html", "application/pdf"]))
def test_state_help(self):
url = urlreverse('ietf.doc.views_help.state_help', kwargs=dict(type="draft-iesg"))

View file

@ -140,17 +140,36 @@ def fill_in_document_table_attributes(docs, have_telechat_date=False):
d.obsoleted_by_list = []
d.updated_by_list = []
xed_by = RelatedDocument.objects.filter(target__name__in=list(rfc_aliases.values()),
relationship__in=("obs", "updates")).select_related('target')
rel_rfc_aliases = dict([ (a.document.id, re.sub(r"rfc(\d+)", r"RFC \1", a.name, flags=re.IGNORECASE)) for a in DocAlias.objects.filter(name__startswith="rfc", docs__id__in=[rel.source_id for rel in xed_by]) ])
# Revisit this block after RFCs become first-class Document objects
xed_by = list(
RelatedDocument.objects.filter(
target__name__in=list(rfc_aliases.values()),
relationship__in=("obs", "updates"),
).select_related("target")
)
rel_rfc_aliases = {
a.document.id: re.sub(r"rfc(\d+)", r"RFC \1", a.name, flags=re.IGNORECASE)
for a in DocAlias.objects.filter(
name__startswith="rfc", docs__id__in=[rel.source_id for rel in xed_by]
)
}
xed_by.sort(
key=lambda rel: int(
re.sub(
r"rfc\s*(\d+)",
r"\1",
rel_rfc_aliases[rel.source_id],
flags=re.IGNORECASE,
)
)
)
for rel in xed_by:
d = doc_dict[rel.target.document.id]
s = rel_rfc_aliases[rel.source_id]
if rel.relationship_id == "obs":
l = d.obsoleted_by_list
d.obsoleted_by_list.append(s)
elif rel.relationship_id == "updates":
l = d.updated_by_list
l.append(rel_rfc_aliases[rel.source_id])
l.sort()
d.updated_by_list.append(s)
def augment_docs_with_related_docs_info(docs):
"""Augment all documents with related documents information.

View file

@ -114,13 +114,46 @@ def render_document_top(request, doc, tab, name):
rsab_ballot,
None if rsab_ballot else "RSAB Evaluation Ballot has not been created yet"
))
if doc.type_id in ("draft","conflrev", "statchg"):
tabs.append(("IESG Evaluation Record", "ballot", urlreverse("ietf.doc.views_doc.document_ballot", kwargs=dict(name=name)), iesg_ballot, None if iesg_ballot else "IESG Evaluation Ballot has not been created yet"))
elif doc.type_id == "charter" and doc.group.type_id == "wg":
tabs.append(("IESG Review", "ballot", urlreverse("ietf.doc.views_doc.document_ballot", kwargs=dict(name=name)), iesg_ballot, None if iesg_ballot else "IESG Review Ballot has not been created yet"))
if doc.type_id == "draft" or (doc.type_id == "charter" and doc.group.type_id == "wg"):
tabs.append(("IESG Writeups", "writeup", urlreverse('ietf.doc.views_doc.document_writeup', kwargs=dict(name=name)), True, None))
if iesg_ballot or (doc.group and doc.group.type_id == "wg"):
if doc.type_id in ("draft", "conflrev", "statchg"):
tabs.append(
(
"IESG Evaluation Record",
"ballot",
urlreverse(
"ietf.doc.views_doc.document_ballot", kwargs=dict(name=name)
),
iesg_ballot,
None,
)
)
elif doc.type_id == "charter" and doc.group and doc.group.type_id == "wg":
tabs.append(
(
"IESG Review",
"ballot",
urlreverse(
"ietf.doc.views_doc.document_ballot", kwargs=dict(name=name)
),
iesg_ballot,
None,
)
)
if doc.type_id == "draft" or (
doc.type_id == "charter" and doc.group and doc.group.type_id == "wg"
):
tabs.append(
(
"IESG Writeups",
"writeup",
urlreverse(
"ietf.doc.views_doc.document_writeup", kwargs=dict(name=name)
),
True,
None,
)
)
tabs.append(("Email expansions","email",urlreverse('ietf.doc.views_doc.document_email', kwargs=dict(name=name)), True, None))
tabs.append(("History", "history", urlreverse('ietf.doc.views_doc.document_history', kwargs=dict(name=name)), True, None))
@ -151,6 +184,7 @@ def interesting_doc_relations(doc):
that_doc_relationships = ('replaces', 'possibly_replaces', 'updates', 'obs')
# TODO: This returns the relationships in database order, which may not be the order we want to display them in.
interesting_relations_that = cls.objects.filter(target__docs=target, relationship__in=that_relationships).select_related('source')
interesting_relations_that_doc = cls.objects.filter(source=doc, relationship__in=that_doc_relationships).prefetch_related('target__docs')

View file

@ -343,7 +343,7 @@ class NominateForm(forms.ModelForm):
'year': self.nomcom.year(),
}
path = nomcom_template_path + NOMINATION_RECEIPT_TEMPLATE
send_mail(None, to_email, from_email, subject, path, context, cc=cc)
send_mail(None, to_email, from_email, subject, path, context, cc=cc, copy=False, save=False)
return nomination
@ -458,7 +458,7 @@ class NominateNewPersonForm(forms.ModelForm):
'year': self.nomcom.year(),
}
path = nomcom_template_path + NOMINATION_RECEIPT_TEMPLATE
send_mail(None, to_email, from_email, subject, path, context, cc=cc)
send_mail(None, to_email, from_email, subject, path, context, cc=cc, copy=False, save=False)
return nomination
@ -551,7 +551,7 @@ class FeedbackForm(forms.ModelForm):
}
path = nomcom_template_path + FEEDBACK_RECEIPT_TEMPLATE
# TODO - make the thing above more generic
send_mail(None, to_email, from_email, subject, path, context, cc=cc, copy=False)
send_mail(None, to_email, from_email, subject, path, context, cc=cc, copy=False, save=False)
class Meta:
model = Feedback

View file

@ -122,7 +122,7 @@ class NomcomViewsTest(TestCase):
self.check_url_status(url, 200)
self.client.logout()
login_testing_unauthorized(self, MEMBER_USER, url)
return self.check_url_status(url, 200)
self.check_url_status(url, 200)
def access_chair_url(self, url):
login_testing_unauthorized(self, COMMUNITY_USER, url)
@ -134,7 +134,7 @@ class NomcomViewsTest(TestCase):
login_testing_unauthorized(self, COMMUNITY_USER, url)
login_testing_unauthorized(self, CHAIR_USER, url)
login_testing_unauthorized(self, SECRETARIAT_USER, url)
return self.check_url_status(url, 200)
self.check_url_status(url, 200)
def test_private_index_view(self):
"""Verify private home view"""
@ -599,6 +599,8 @@ class NomcomViewsTest(TestCase):
self.nominate_view(public=True,confirmation=True)
self.assertEqual(len(outbox), messages_before + 3)
self.assertEqual(Message.objects.count(), 2)
self.assertFalse(Message.objects.filter(subject="Nomination receipt").exists())
self.assertEqual('IETF Nomination Information', outbox[-3]['Subject'])
self.assertEqual(self.email_from, outbox[-3]['From'])
@ -625,8 +627,7 @@ class NomcomViewsTest(TestCase):
def test_private_nominate(self):
self.access_member_url(self.private_nominate_url)
return self.nominate_view(public=False)
self.client.logout()
self.nominate_view(public=False)
def test_public_nominate_newperson(self):
login_testing_unauthorized(self, COMMUNITY_USER, self.public_nominate_url)
@ -666,13 +667,13 @@ class NomcomViewsTest(TestCase):
def test_private_nominate_newperson(self):
self.access_member_url(self.private_nominate_url)
return self.nominate_newperson_view(public=False)
self.client.logout()
self.nominate_newperson_view(public=False, confirmation=True)
self.assertFalse(Message.objects.filter(subject="Nomination receipt").exists())
def test_private_nominate_newperson_who_already_exists(self):
EmailFactory(address='nominee@example.com')
self.access_member_url(self.private_nominate_newperson_url)
return self.nominate_newperson_view(public=False)
self.nominate_newperson_view(public=False)
def test_public_nominate_with_automatic_questionnaire(self):
nomcom = get_nomcom_by_year(self.year)
@ -844,8 +845,7 @@ class NomcomViewsTest(TestCase):
def test_add_questionnaire(self):
self.access_chair_url(self.add_questionnaire_url)
return self.add_questionnaire()
self.client.logout()
self.add_questionnaire()
def add_questionnaire(self, *args, **kwargs):
public = kwargs.pop('public', False)
@ -906,6 +906,8 @@ class NomcomViewsTest(TestCase):
# We're interested in the confirmation receipt here
self.assertEqual(len(outbox),3)
self.assertEqual('NomCom comment confirmation', outbox[2]['Subject'])
self.assertEqual(Message.objects.count(), 2)
self.assertFalse(Message.objects.filter(subject="NomCom comment confirmation").exists())
email_body = get_payload_text(outbox[2])
self.assertIn(position, email_body)
self.assertNotIn('$', email_body)
@ -920,7 +922,7 @@ class NomcomViewsTest(TestCase):
def test_private_feedback(self):
self.access_member_url(self.private_feedback_url)
return self.feedback_view(public=False)
self.feedback_view(public=False)
def feedback_view(self, *args, **kwargs):
public = kwargs.pop('public', True)

View file

@ -9,13 +9,20 @@
<p id="instructions" class="alert alert-info my-3">
{% if nomcom.group.state_id == 'conclude' %}
Feedback to this NomCom is closed.
{% elif positions|length != 0 and topics|length != 0 %}
Select a nominee or topic from the list on the right to obtain a new feedback form.
{% elif positions|length != 0 %}
Select a nominee from the list on the right to obtain a new feedback form.
{% elif topics|length != 0 %}
Select a topic from the list on the right to obtain a new feedback form.
{% else %}
Select a nominee from the list of nominees on the right to obtain a new feedback form.
This NomCom is not accepting feedback at this time.
{% endif %}
</p>
{% if nomcom|has_publickey %}
<div class="row">
<div id="nominees" class="col-sm-2 order-last">
{% if positions|length != 0 %}
<h2 class="navskip mt-4">Nominees</h2>
<p>
A number after a name indicates
@ -43,6 +50,8 @@
</div>
{% endif %}
{% endfor %}
{% endif %}
{% if topics|length != 0 %}
<h2 class="navskip mt-4">Topics</h2>
<div class="d-grid gap-3">
{% for t in topics %}
@ -58,6 +67,7 @@
</a>
{% endfor %}
</div>
{% endif %}
</div>
<div class="col-sm-10">
{% if form %}

View file

@ -24,7 +24,7 @@
"caniuse-lite": "1.0.30001495",
"d3": "7.8.5",
"file-saver": "2.0.5",
"highcharts": "11.0.1",
"highcharts": "11.1.0",
"ical.js": "1.5.0",
"jquery": "3.7.0",
"js-cookie": "3.0.5",
@ -70,7 +70,7 @@
"jquery-migrate": "3.4.1",
"parcel": "2.9.1",
"pug": "3.0.2",
"sass": "1.62.1",
"sass": "1.63.4",
"seedrandom": "3.0.5",
"vite": "4.3.9"
},

View file

@ -4429,10 +4429,10 @@ browserlist@latest:
languageName: node
linkType: hard
"highcharts@npm:11.0.1":
version: 11.0.1
resolution: "highcharts@npm:11.0.1"
checksum: 773a7b876502d616b7c5f522610b061cc714233a6ecdd7f7d073151fdf53bc597c01a758fbda5bba9069a0ee487e7defddfbdb1de73a78db6267a9257250137c
"highcharts@npm:11.1.0":
version: 11.1.0
resolution: "highcharts@npm:11.1.0"
checksum: f9b8cdc38b3b41bcc4c3a2331d9b1c769400639e2d0094484a0f5274aaba619551b95b442a69f7f4e47c2c8445681e3651f6036207fe1928a1a982f5278ae85e
languageName: node
linkType: hard
@ -6651,7 +6651,7 @@ browserlist@latest:
eslint-plugin-promise: 6.1.1
eslint-plugin-vue: 9.14.1
file-saver: 2.0.5
highcharts: 11.0.1
highcharts: 11.1.0
html-validate: 7.18.1
ical.js: 1.5.0
jquery: 3.7.0
@ -6670,7 +6670,7 @@ browserlist@latest:
pinia: 2.1.3
pinia-plugin-persist: 1.0.0
pug: 3.0.2
sass: 1.62.1
sass: 1.63.4
seedrandom: 3.0.5
select2: 4.1.0-rc.0
select2-bootstrap-5-theme: 1.3.0
@ -6734,16 +6734,16 @@ browserlist@latest:
languageName: node
linkType: hard
"sass@npm:1.62.1":
version: 1.62.1
resolution: "sass@npm:1.62.1"
"sass@npm:1.63.4":
version: 1.63.4
resolution: "sass@npm:1.63.4"
dependencies:
chokidar: ">=3.0.0 <4.0.0"
immutable: ^4.0.0
source-map-js: ">=0.6.2 <2.0.0"
bin:
sass: sass.js
checksum: 1b1b3584b38a63dd94156b65f13b90e3f84b170a38c3d5e3fa578b7a32a37aeb349b4926b0eaf9448d48e955e86b1ee01b13993f19611dad8068af07a607c13b
checksum: 12bde5beff85a7018157d90c8b9d5aec8b56832f89fcfeca146f10936eecf97e669d22fd41f812b3407ed259bbb114d69c9ecbfc7ee9b15308211fb910cdf5eb
languageName: node
linkType: hard