Merge remote-tracking branch 'origin/main' into feat/postgres

This commit is contained in:
Robert Sparks 2022-12-20 08:31:02 -06:00
commit 795c182df8
No known key found for this signature in database
GPG key ID: 6E2A6A5775F91318
107 changed files with 1379 additions and 1178 deletions

20
.github/workflows/dependency-review.yml vendored Normal file
View file

@ -0,0 +1,20 @@
# Dependency Review Action
#
# This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging.
#
# Source repository: https://github.com/actions/dependency-review-action
# Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement
name: 'Dependency Review'
on: [pull_request]
permissions:
contents: read
jobs:
dependency-review:
runs-on: ubuntu-latest
steps:
- name: 'Checkout Repository'
uses: actions/checkout@v3
- name: 'Dependency Review'
uses: actions/dependency-review-action@v2

View file

@ -148,7 +148,7 @@ jobs:
ref: 'feat/postgres'
- name: Download DB Dump
uses: actions/download-artifact@v3.0.0
uses: actions/download-artifact@v3
with:
name: dump

1073
.pnp.cjs generated

File diff suppressed because it is too large Load diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

0
.yarn/cache/shepherd.js-npm-10.0.1-64acc35968-be51f42734.zip vendored Normal file → Executable file
View file

View file

Binary file not shown.

View file

@ -606,6 +606,7 @@ class DocumentInfo(models.Model):
# The path here has to match the urlpattern for htmlized
# documents in order to produce correct intra-document links
html = rfc2html.markup(text, path=settings.HTMLIZER_URL_PREFIX)
html = f'<div class="rfcmarkup">{html}</div>'
if html:
cache.set(cache_key, html, settings.HTMLIZER_CACHE_TIME)
return html

View file

@ -140,7 +140,7 @@ def ballot_icon(context, doc):
i = i + 1
res.append("</tr></tbody></table></a>")
res.append('<div id="modal-%d" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true"><div class="modal-dialog modal-dialog-scrollable modal-xl"><div class="modal-content"></div></div></div>' % ballot.pk)
res.append('<div id="modal-%d" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true"><div class="modal-dialog modal-dialog-scrollable modal-xl modal-fullscreen-lg-down"><div class="modal-content"></div></div></div>' % ballot.pk)
return mark_safe("".join(res))

View file

@ -744,6 +744,12 @@ Man Expires September 22, 2015 [Page 3]
q = PyQuery(r.content)
self.assertEqual(q('title').text(), 'draft-ietf-mars-test-01')
# check that revision list has expected versions
self.assertEqual(len(q('#sidebar .revision-list .page-item.active a.page-link[href$="draft-ietf-mars-test-01"]')), 1)
# check that diff dropdowns have expected versions
self.assertEqual(len(q('#sidebar option[value="draft-ietf-mars-test-00"][selected="selected"]')), 1)
rfc = WgRfcFactory()
(Path(settings.RFC_PATH) / rfc.get_base_name()).touch()
r = self.client.get(urlreverse("ietf.doc.views_doc.document_html", kwargs=dict(name=rfc.canonical_name())))
@ -1281,7 +1287,12 @@ Man Expires September 22, 2015 [Page 3]
def test_edit_authors_edit_fields(self):
draft = WgDraftFactory()
DocumentAuthorFactory.create_batch(3, document=draft)
DocumentAuthorFactory.create_batch(
3,
document=draft,
affiliation='Somewhere, Inc.',
country='Bolivia',
)
url = urlreverse('ietf.doc.views_doc.edit_authors', kwargs=dict(name=draft.name))
change_reason = 'reorder the authors'
@ -1293,8 +1304,9 @@ Man Expires September 22, 2015 [Page 3]
authors = draft.documentauthor_set.all(),
basis=change_reason
)
new_email = EmailFactory(person=draft.authors()[0])
old_address = draft.authors()[0].email()
new_email = EmailFactory(person=draft.authors()[0], address=f'changed-{old_address}')
post_data['author-0-email'] = new_email.address
post_data['author-1-affiliation'] = 'University of Nowhere'
post_data['author-2-country'] = 'Chile'
@ -1701,7 +1713,7 @@ class DocTestCase(TestCase):
href = q(f'div.balloter-name a[href$="{author_slug}"]').attr('href')
ids = [
target.attr('id')
for target in q(f'p.h5[id$="{author_slug}"]').items()
for target in q(f'div.h5[id$="{author_slug}"]').items()
]
self.assertEqual(len(ids), 1, 'Should be exactly one link for the balloter')
self.assertEqual(href, f'#{ids[0]}', 'Anchor href should match ID')

View file

@ -1198,9 +1198,9 @@ class BallotContentTests(TestCase):
)
def _assertBallotMessage(self, q, balloter, expected):
heading = q(f'p.h5[id$="_{slugify(balloter.plain_name())}"]')
heading = q(f'div.h5[id$="_{slugify(balloter.plain_name())}"]')
self.assertEqual(len(heading), 1)
# <p.h5/> is followed by a panel with the message of interest, so use next()
# <div.h5> is followed by a panel with the message of interest, so use next()
self.assertEqual(
len(heading.next().find(
f'*[title="{expected}"]'
@ -1381,4 +1381,4 @@ class BallotContentTests(TestCase):
q = PyQuery(content)
self._assertBallotMessage(q, balloters[0], 'No email send requests for this discuss')
self._assertBallotMessage(q, balloters[1], 'No ballot position send log available')
self._assertBallotMessage(q, old_balloter, 'No ballot position send log available')
self._assertBallotMessage(q, old_balloter, 'No ballot position send log available')

View file

@ -345,6 +345,16 @@ class ReviewTests(TestCase):
self.assertIn("This team has completed other reviews", message)
self.assertIn("{} -01 Serious Issues".format(reviewer_email.person.ascii), message)
# check events
assignment_events = assignment.reviewassignmentdocevent_set.all()
self.assertEqual(assignment_events.count(), 1)
e = assignment_events.first()
self.assertEqual(e.type, 'assigned_review_request')
self.assertIn('is assigned', e.desc)
self.assertEqual(e.doc, doc)
request_events = review_req.reviewrequestdocevent_set.all()
self.assertEqual(request_events.count(), 0)
def test_previously_reviewed_replaced_doc(self):
review_team = ReviewTeamFactory(acronym="reviewteam", name="Review Team", type_id="review", list_email="reviewteam@ietf.org", parent=Group.objects.get(acronym="farfut"))
rev_role = RoleFactory(group=review_team,person__user__username='reviewer',person__user__email='reviewer@example.com',person__name='Some Reviewer',name_id='reviewer')

View file

@ -533,6 +533,7 @@ def document_main(request, name, rev=None, document_html=False):
review_assignments=review_assignments,
no_review_from_teams=no_review_from_teams,
due_date=due_date,
diff_revisions=get_diff_revisions(request, name, doc if isinstance(doc,Document) else doc.doc) if document_html else None
))
if doc.type_id == "charter":
@ -809,22 +810,20 @@ def document_html(request, name, rev=None):
if num_found > 1:
raise Http404("Multiple documents matched: %s" % name)
if found.matched_name.startswith('rfc') and name != found.matched_name:
return redirect('ietf.doc.views_doc.document_html', name=found.matched_name)
doc = found.documents.get()
rev = found.matched_rev
if doc.is_rfc() and rev is None:
if not name.startswith('rfc'):
return redirect('ietf.doc.views_doc.document_html', name=doc.canonical_name())
if found.matched_rev or found.matched_name.startswith('rfc'):
rev = found.matched_rev
else:
rev = doc.rev
if rev:
doc = doc.history_set.filter(rev=rev).first() or doc.fake_history_obj(rev)
if not os.path.exists(doc.get_file_name()):
raise Http404("File not found: %s" % doc.get_file_name())
return document_main(request, name, rev=rev, document_html=True)
return document_main(request, name=doc.name, rev=doc.rev if not doc.is_rfc() else None, document_html=True)
def document_pdfized(request, name, rev=None, ext=None):
@ -901,44 +900,77 @@ def document_email(request,name):
)
def document_history(request, name):
doc = get_object_or_404(Document, docalias__name=name)
top = render_document_top(request, doc, "history", name)
def get_diff_revisions(request, name, doc):
diffable = any(
[
name.startswith(prefix)
for prefix in [
"rfc",
"draft",
"charter",
"conflict-review",
"status-change",
]
]
)
if not diffable:
return []
# pick up revisions from events
diff_revisions = []
diffable = [ name.startswith(prefix) for prefix in ["rfc", "draft", "charter", "conflict-review", "status-change", ]]
if any(diffable):
diff_documents = [ doc ]
diff_documents.extend(Document.objects.filter(docalias__relateddocument__source=doc, docalias__relateddocument__relationship="replaces"))
diff_documents = [doc]
diff_documents.extend(
Document.objects.filter(
docalias__relateddocument__source=doc,
docalias__relateddocument__relationship="replaces",
)
)
if doc.get_state_slug() == "rfc":
e = doc.latest_event(type="published_rfc")
aliases = doc.docalias.filter(name__startswith="rfc")
if aliases:
name = aliases[0].name
diff_revisions.append((name, "", e.time if e else doc.time, name))
if doc.get_state_slug() == "rfc":
e = doc.latest_event(type="published_rfc")
aliases = doc.docalias.filter(name__startswith="rfc")
if aliases:
name = aliases[0].name
diff_revisions.append((name, "", e.time if e else doc.time, name))
seen = set()
for e in NewRevisionDocEvent.objects.filter(type="new_revision", doc__in=diff_documents).select_related('doc').order_by("-time", "-id"):
if (e.doc.name, e.rev) in seen:
continue
seen = set()
for e in (
NewRevisionDocEvent.objects.filter(type="new_revision", doc__in=diff_documents)
.select_related("doc")
.order_by("-time", "-id")
):
if (e.doc.name, e.rev) in seen:
continue
seen.add((e.doc.name, e.rev))
seen.add((e.doc.name, e.rev))
url = ""
if name.startswith("charter"):
url = request.build_absolute_uri(urlreverse('ietf.doc.views_charter.charter_with_milestones_txt', kwargs=dict(name=e.doc.name, rev=e.rev)))
elif name.startswith("conflict-review"):
url = find_history_active_at(e.doc, e.time).get_href()
elif name.startswith("status-change"):
url = find_history_active_at(e.doc, e.time).get_href()
elif name.startswith("draft") or name.startswith("rfc"):
# rfcdiff tool has special support for IDs
url = e.doc.name + "-" + e.rev
url = ""
if name.startswith("charter"):
url = request.build_absolute_uri(
urlreverse(
"ietf.doc.views_charter.charter_with_milestones_txt",
kwargs=dict(name=e.doc.name, rev=e.rev),
)
)
elif name.startswith("conflict-review"):
url = find_history_active_at(e.doc, e.time).get_href()
elif name.startswith("status-change"):
url = find_history_active_at(e.doc, e.time).get_href()
elif name.startswith("draft") or name.startswith("rfc"):
# rfcdiff tool has special support for IDs
url = e.doc.name + "-" + e.rev
diff_revisions.append((e.doc.name, e.rev, e.time, url))
diff_revisions.append((e.doc.name, e.rev, e.time, url))
return diff_revisions
def document_history(request, name):
doc = get_object_or_404(Document, docalias__name=name)
top = render_document_top(request, doc, "history", name)
diff_revisions = get_diff_revisions(request, name, doc)
# grab event history
events = doc.docevent_set.all().order_by("-time", "-id").select_related("by")

View file

@ -398,15 +398,6 @@ def assign_review_request_to_reviewer(request, review_req, reviewer, add_skip=Fa
review_req.team.acronym.upper(),
reviewer.person if reviewer else "(None)")
update_change_reason(assignment, descr)
ReviewRequestDocEvent.objects.create(
type="assigned_review_request",
doc=review_req.doc,
rev=review_req.doc.rev,
by=request.user.person,
desc=descr,
review_request=review_req,
state_id='assigned',
)
ReviewAssignmentDocEvent.objects.create(
type="assigned_review_request",
@ -416,7 +407,7 @@ def assign_review_request_to_reviewer(request, review_req, reviewer, add_skip=Fa
desc="Request for {} review by {} is assigned to {}".format(
review_req.type.name,
review_req.team.acronym.upper(),
reviewer.person,
reviewer.person if reviewer else "(None)",
),
review_assignment=assignment,
state_id='assigned',

View file

@ -154,7 +154,6 @@ $tooltip-margin: inherit !default;
}
pre {
width: 72ch;
margin: 0;
padding: 0;
}
@ -176,6 +175,11 @@ $tooltip-margin: inherit !default;
white-space: pre;
display: inline;
}
.newpage {
margin-top: -1.25em;
}
}
tbody.meta tr {
@ -206,6 +210,15 @@ tbody.meta tr {
}
}
.navbar {
td:not(:first-child),
th:not(:first-child) {
padding-top: 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);
@ -290,11 +303,16 @@ tbody.meta tr {
margin: .75in;
}
* {
.rfcmarkup {
font-size: 9.75pt !important;
line-height: 1.25em !important;
}
.rfchtml {
font-size: 9.75pt;
line-height: 1.25em;
}
body {
margin: 0;
padding: 0;
@ -318,3 +336,15 @@ tbody.meta tr {
display: none;
}
}
// Select2 styling
@import "select2";
.select2-results__option,
.select2-search__field {
font-size: small !important;
}
.select2-container--open {
z-index: 9999999;
}

View file

@ -70,11 +70,6 @@ blockquote {
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 */
@ -87,10 +82,6 @@ blockquote {
}
#identifiers {
margin: 0;
display: grid;
grid-template-columns: 47ch 24ch;
grid-auto-rows: auto;
gap: 0 1ch;
}
#identifiers dt {
margin: 0 1ch 0 0;
@ -98,7 +89,6 @@ blockquote {
display: inline-block;
}
#identifiers dd {
grid-column: 1;
margin: 0;
width: 47ch;
/* HAXX: this gets around the lack of text-content-trim support */
@ -146,7 +136,7 @@ blockquote {
margin: 0 0 0 1ch;
}
#identifiers dd:is(.updates, .obsoletes) a:last-of-type {
margin: 0 1ch;
margin-right: 1ch;
}
#identifiers dd.published::before {
content: "Published:";
@ -160,11 +150,52 @@ blockquote {
#identifiers dd.issn::before {
content: "ISSN:";
}
#identifiers dd.authors {
grid-area: 1 / 2 / 100 / 3;
width: 24ch;
text-align: right;
display: block;
/* Thanks WeasyPrint for not supporting @supports */
/* @supports not (display: grid) { */
#identifiers dd.authors {
padding-left: 8ch;
width: 64ch;
}
#identifiers dd.authors::before {
content: "Authors:";
margin: 0 0 0 -8ch;
}
#identifiers dd.authors .author {
display: inline-block;
margin: 0 2ch 0 1ch;
}
#identifiers dd.authors .author:last-of-type {
margin-right: 0;
}
/* } */
/* #identifiers styling for when grid layout is supported, or not */
@supports(display: grid) {
#identifiers {
display: grid;
grid-template-columns: 47ch 24ch;
grid-auto-rows: auto;
gap: 0 1ch;
}
#identifiers dd {
grid-column: 1;
}
#identifiers dd.authors {
grid-area: 1 / 2 / 100 / 3;
width: 24ch;
text-align: right;
display: block;
/* overrides for @supports not block */
padding-left: 0;
}
/* more overrides for @supports not block */
#identifiers dd.authors::before {
display: none;
}
#identifiers dd.authors .author {
display: block;
margin: 0;
}
}
#title {
@ -175,6 +206,9 @@ blockquote {
#rfcnum {
display: none;
}
:is(#status-of-memo, #copyright) a {
white-space: nowrap;
}
.toplink {
display: none;
}
@ -200,7 +234,7 @@ ol, ul {
ol {
margin: 0 0 0 6ch; /* todo: deal with lists that have >= 10 items */
}
ol ol, ul ol {
:is(ol, ul) ol {
margin: 0 0 0 3ch;
}
ul {
@ -210,7 +244,7 @@ ul {
ul ul {
list-style-type: '-';
}
ul ul, ol ul {
:is(ul, ol) ul {
margin-left: 1ch;
}
ul ul ul {
@ -224,7 +258,7 @@ li {
.compact li {
margin: 0;
}
li p:first-child, dd p:first-child {
:is(li, dd) p:first-child {
margin: 0;
}
dt {
@ -238,7 +272,7 @@ dd {
@include margin-paragraph;
break-before: avoid;
}
dl.compact dt, dl.compact dd {
dl.compact :is(dt, dd) {
margin-top: 0;
margin-bottom: 0;
}
@ -248,7 +282,7 @@ dl.references dt {
dl.references dd {
margin-left: 11ch;
}
dd.break {
:is(dd, span).break {
display: none;
}
@ -257,31 +291,31 @@ pre {
// margin: var(--line) 0;
@include margin-line;
}
div.artwork, div.sourcecode {
div:is(.artwork, .sourcecode) {
display: flex;
flex-wrap: nowrap;
align-items: end;
}
div.artwork.alignCenter, div.sourcecode.alignCenter {
div:is(.artwork, .sourcecode).alignCenter {
justify-content: center;
}
div.artwork.alignRight, div.sourcecode.alignRight {
div:is(.artwork, .sourcecode).alignRight {
justify-content: end;
}
div.artwork::before, div.sourcecode::before {
div:is(.artwork, .sourcecode)::before {
flex: 0 1 3ch;
content: "";
}
div.artwork.alignRight::before, div.sourcecode.alignRight::before {
div:is(.artwork, .sourcecode).alignRight::before {
flex-grow: 1;
}
div.artwork pre, div.sourcecode pre {
div:is(.artwork, .sourcecode) pre {
flex: 0 0 content;
margin: 0;
max-width: 72ch;
overflow: auto;
}
div.artwork .pilcrow, div.sourcecode .pilcrow {
div:is(.artwork, .sourcecode) .pilcrow {
flex: 0 0 1ch;
}
figcaption, table caption {
@ -335,7 +369,7 @@ a.selfRef, a.pilcrow {
a.relref, a.xref {
hyphens: none;
}
a.relref, a.xref.cite {
a:is(.relref, .xref:is(.cite, .auto.internal)) {
white-space: nowrap;
}
.pilcrow {

View file

@ -8,6 +8,7 @@ import {
import Cookies from "js-cookie";
import { populate_nav } from "./nav.js";
import "./select2.js";
const cookies = Cookies.withAttributes({ sameSite: "strict" });
@ -47,8 +48,8 @@ document.addEventListener("DOMContentLoaded", function (event) {
["py-0"]);
// activate pref buttons selected by pref cookies or localStorage
const in_localStorage = ["deftab"];
document.querySelectorAll(".btn-check")
const in_localStorage = ["deftab", "reflinks"];
document.querySelectorAll("#pref-tab-pane .btn-check")
.forEach(btn => {
const id = btn.id.replace("-radio", "");
@ -79,4 +80,36 @@ document.addEventListener("DOMContentLoaded", function (event) {
};
defpane.show();
document.activeElement.blur();
if (localStorage.getItem("reflinks") != "refsection") {
// make links to references go directly to the referenced doc
document.querySelectorAll("a[href^='#'].xref")
.forEach(ref => {
const loc = document
.getElementById(ref.hash.substring(1))
.nextElementSibling;
if (!loc ||
loc.tagName != "DD" ||
!loc.closest(".references")) {
return;
}
const url = loc.querySelector(
"a:not([href='']:last-of-type)");
if (url) {
const rfc = url.href.match(/(rfc\d+)$/i);
if (rfc) {
// keep RFC links within the datatracker
const base = ref.href.match(
/^(.*\/)rfc\d+.*$/i);
if (base) {
ref.href = base[1] + rfc[1];
return;
}
}
ref.href = url.href;
}
});
}
});

View file

@ -66,6 +66,11 @@ window.setupSelect2Field = function (e) {
.focus()
});
// Remove spurious title attribute (https://github.com/select2/select2/pull/3988)
$(document)
.on("mouseenter", ".select2-selection__rendered", function () { $(this)
.removeAttr("title"); });
e.select2({
multiple: maxEntries !== 1,
maximumSelectionSize: maxEntries,

View file

@ -4,7 +4,7 @@
{% load ietf_filters %}
{% load textfilters %}
<div class="row">
<div class="col-md-2 d-none d-md-block d-sm-block d-lg-block d-xl-block d-xxl-block">
<div class="col-md-2">
{% for n, positions in position_groups %}
<p class="h5">
<span class="badge rounded-pill {{ n|pos_to_label_format }}">{{ n.name }}</span>
@ -85,10 +85,12 @@
{% for n, positions in position_groups %}
{% for p in positions %}
{% if not p.is_old_pos %}
<p class="h5 mt-4"
id="{{ doc.name|slugify }}_{{ p.balloter.plain_name|slugify }}">
{{ p.balloter.plain_name }}
<span class="float-end">
<div class="h5 d-flex mt-4"
id="{{ doc.name|slugify }}_{{ p.balloter.plain_name|slugify }}">
<div class="flex-fill">
{{ p.balloter.plain_name }}
</div>
<div class="flex-fill text-end">
{% if p.old_positions %}<span class="text-muted small">(was {{ p.old_positions|join:", " }})</span>{% endif %}
<span class="badge rounded-pill {{ p.pos|pos_to_label_format }}">{{ p.pos }}</span>
{% if user|has_role:"Secretariat" %}
@ -98,8 +100,8 @@
Edit
</a>
{% endif %}
</span>
</p>
</div>
</div>
{% if p.pos.blocking and p.discuss %}
<div class="card border-danger {% if p.comment %} mb-2{% endif %}">
<div class="card-header bg-danger text-light">
@ -158,9 +160,12 @@
{% for n, positions in position_groups %}
{% for p in positions %}
{% if p.is_old_pos %}
<p class="h5 mt-4" id="{{ doc.name|slugify }}_{{ p.balloter.plain_name|slugify }}">
<span class="text-muted">({{ p.balloter.plain_name }}; former steering group member)</span>
<span class="float-end">
<div class="h5 d-flex mt-4"
id="{{ doc.name|slugify }}_{{ p.balloter.plain_name|slugify }}">
<div class="flex-fill text-muted">
{{ p.balloter.plain_name }} <span class="badge rounded-pill bg-secondary">Former IESG member</span>
</div>
<div class="flex-fill text-end">
{% if p.old_positions %}<span class="text-muted small">(was {{ p.old_positions|join:", " }})</span>{% endif %}
<span class="badge rounded-pill {{ p.pos|pos_to_label_format }}">{{ p.pos }}</span>
{% if user|has_role:"Secretariat" %}
@ -170,8 +175,8 @@
Edit
</a>
{% endif %}
</span>
</p>
</div>
</div>
<div class="card {{ p.pos|pos_to_border_format }}">
<div class="card-header {{ p.pos|pos_to_label_format }}">
<div>
@ -211,4 +216,4 @@
{% endfor %}
{% endfor %}
</div>
</div>
</div>

Some files were not shown because too many files have changed in this diff Show more