Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e50d34c
fix: Reorder conflict review columns
larseggert Oct 24, 2023
a2efb79
Remove some more stuff that isn't needed
larseggert Oct 24, 2023
1815134
Merge branch 'main' into fix-6528
larseggert Oct 25, 2023
4e54054
Merge branch 'main' into fix-6528
larseggert Oct 26, 2023
32c1178
Progress
larseggert Oct 27, 2023
0dbfb00
Delivers current functionality
larseggert Oct 27, 2023
11855f0
Merge branch 'main' into fix-6528
larseggert Oct 27, 2023
ac8e7d0
Add some comments
larseggert Oct 27, 2023
32ef13c
Handle expired docs
larseggert Oct 27, 2023
deab423
Interim commit
larseggert Oct 28, 2023
d55403a
Fix tests
larseggert Oct 30, 2023
d8c74a0
Cleanup
larseggert Oct 30, 2023
b23fae3
More cleanup
larseggert Oct 30, 2023
62aaef7
Reduce differences to current view
larseggert Oct 30, 2023
d0fcbdd
Interim commit
larseggert Nov 2, 2023
32586bd
More progress
larseggert Nov 3, 2023
d04c582
Getting close
larseggert Nov 3, 2023
bd848c6
Merge branch 'main' into fix-6528
larseggert Nov 3, 2023
8e401c9
Make page functional again
larseggert Nov 4, 2023
12aca4f
Remove unused variable
larseggert Nov 4, 2023
1219fa0
Suppress mypy warning
larseggert Nov 4, 2023
4e35916
Fix #6553
larseggert Nov 4, 2023
f0e6c39
Merge branch 'main' into fix-6528
larseggert Nov 5, 2023
25c44e4
Log in as secretary to execute new code, and remove redundant check
larseggert Nov 5, 2023
d083c74
Remove unneeded code
larseggert Nov 5, 2023
6b35f41
Fix #6608 by adding link to state description to state heading
larseggert Nov 6, 2023
64f3318
Missed part of this change in last commit.
larseggert Nov 6, 2023
8f781e6
Merge branch 'main' into fix-6528
larseggert Nov 9, 2023
794cd31
Merge branch 'main' into fix-6528
larseggert Nov 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 53 additions & 35 deletions ietf/doc/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,14 @@
from ietf.doc.models import ( Document, DocAlias, DocRelationshipName, RelatedDocument, State,
DocEvent, BallotPositionDocEvent, LastCallDocEvent, WriteupDocEvent, NewRevisionDocEvent, BallotType,
EditedAuthorsDocEvent )
from ietf.doc.factories import ( DocumentFactory, DocEventFactory, CharterFactory,
from ietf.doc.factories import ( DocumentFactory, DocEventFactory, CharterFactory,
ConflictReviewFactory, WgDraftFactory, IndividualDraftFactory, WgRfcFactory,
IndividualRfcFactory, StateDocEventFactory, BallotPositionDocEventFactory,
BallotDocEventFactory, DocumentAuthorFactory, NewRevisionDocEventFactory,
StatusChangeFactory, BofreqFactory, DocExtResourceFactory, RgDraftFactory)
StatusChangeFactory, DocExtResourceFactory, RgDraftFactory)
from ietf.doc.forms import NotifyForm
from ietf.doc.fields import SearchableDocumentsField
from ietf.doc.utils import create_ballot_if_not_open, uppercase_std_abbreviated_name
from ietf.doc.views_search import ad_dashboard_group, ad_dashboard_group_type, shorten_group_name # TODO: red flag that we're importing from views in tests. Move these to utils.
from ietf.group.models import Group, Role
from ietf.group.factories import GroupFactory, RoleFactory
from ietf.ipr.factories import HolderIprDisclosureFactory
Expand All @@ -60,6 +59,7 @@
from ietf.utils.test_utils import TestCase
from ietf.utils.text import normalize_text
from ietf.utils.timezone import date_today, datetime_today, DEADLINE_TZINFO, RPC_TZINFO
from ietf.doc.utils_search import AD_WORKLOAD


class SearchTests(TestCase):
Expand Down Expand Up @@ -279,43 +279,61 @@ def test_frontpage(self):
self.assertContains(r, "Document Search")

def test_ad_workload(self):
Role.objects.filter(name_id='ad').delete()
ad = RoleFactory(name_id='ad',group__type_id='area',group__state_id='active',person__name='Example Areadirector').person
doc_type_names = ['bofreq', 'charter', 'conflrev', 'draft', 'statchg']
expected = defaultdict(lambda :0)
for doc_type_name in doc_type_names:
if doc_type_name=='draft':
states = State.objects.filter(type='draft-iesg', used=True).values_list('slug', flat=True)
else:
states = State.objects.filter(type=doc_type_name, used=True).values_list('slug', flat=True)

for state in states:
target_num = random.randint(0,2)
Role.objects.filter(name_id="ad").delete()
ad = RoleFactory(
name_id="ad",
group__type_id="area",
group__state_id="active",
person__name="Example Areadirector",
).person
expected = defaultdict(lambda: 0)
for doc_type_slug in AD_WORKLOAD:
for state in AD_WORKLOAD[doc_type_slug]:
target_num = random.randint(0, 2)
for _ in range(target_num):
if doc_type_name == 'draft':
doc = IndividualDraftFactory(ad=ad,states=[('draft-iesg', state),('draft','rfc' if state=='pub' else 'active')])
elif doc_type_name == 'charter':
doc = CharterFactory(ad=ad, states=[(doc_type_name, state)])
elif doc_type_name == 'bofreq':
# Note that the view currently doesn't handle bofreqs
doc = BofreqFactory(states=[(doc_type_name, state)], bofreqresponsibledocevent__responsible=[ad])
elif doc_type_name == 'conflrev':
doc = ConflictReviewFactory(ad=ad, states=State.objects.filter(type_id=doc_type_name, slug=state))
elif doc_type_name == 'statchg':
doc = StatusChangeFactory(ad=ad, states=State.objects.filter(type_id=doc_type_name, slug=state))
else:
# Currently unreachable
doc = DocumentFactory(type_id=doc_type_name, ad=ad, states=[(doc_type_name, state)])

if not slugify(ad_dashboard_group_type(doc)) in ('document', 'none'):
expected[(slugify(ad_dashboard_group_type(doc)), slugify(ad.full_name_as_key()), slugify(shorten_group_name(ad_dashboard_group(doc))))] += 1

url = urlreverse('ietf.doc.views_search.ad_workload')
if (
doc_type_slug == "draft"
or doc_type_slug == "rfc"
and state == "rfcqueue"
):
IndividualDraftFactory(
ad=ad,
states=[
("draft-iesg", state),
("draft", "rfc" if state == "pub" else "active"),
],
)
elif doc_type_slug == "rfc":
WgRfcFactory.create(
states=[("draft", "rfc"), ("draft-iesg", "pub")]
)

elif doc_type_slug == "charter":
CharterFactory(ad=ad, states=[(doc_type_slug, state)])
elif doc_type_slug == "conflrev":
ConflictReviewFactory(
ad=ad,
states=State.objects.filter(
type_id=doc_type_slug, slug=state
),
)
elif doc_type_slug == "statchg":
StatusChangeFactory(
ad=ad,
states=State.objects.filter(
type_id=doc_type_slug, slug=state
),
)
self.client.login(username="ad", password="ad+password")
url = urlreverse("ietf.doc.views_search.ad_workload")
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
for group_type, ad, group in expected:
self.assertEqual(int(q(f'#{group_type}-{ad}-{group}').text()),expected[(group_type, ad, group)])
self.assertEqual(
int(q(f"#{group_type}-{ad}-{group}").text()),
expected[(group_type, ad, group)],
)

def test_docs_for_ad(self):
ad = RoleFactory(name_id='ad',group__type_id='area',group__state_id='active').person
Expand Down
89 changes: 86 additions & 3 deletions ietf/doc/utils_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

from django.conf import settings

from ietf.doc.models import Document, DocAlias, RelatedDocument, DocEvent, TelechatDocEvent, BallotDocEvent
from ietf.doc.models import Document, DocAlias, RelatedDocument, DocEvent, TelechatDocEvent, BallotDocEvent, DocTypeName
from ietf.doc.expire import expirable_drafts
from ietf.doc.utils import augment_docs_and_user_with_user_info
from ietf.meeting.models import SessionPresentation, Meeting, Session
Expand All @@ -26,7 +26,7 @@ def fill_in_telechat_date(docs, doc_dict=None, doc_ids=None):
doc_dict = dict((d.pk, d) for d in docs)
doc_ids = list(doc_dict.keys())
if doc_ids is None:
doc_ids = list(doc_dict.keys())
doc_ids = list(doc_dict.keys())

seen = set()
for e in TelechatDocEvent.objects.filter(doc__id__in=doc_ids, type="scheduled_for_telechat").order_by('-time'):
Expand Down Expand Up @@ -181,7 +181,7 @@ def augment_docs_with_related_docs_info(docs):
continue
originalDoc = d.related_that_doc('conflrev')[0].document
d.pages = originalDoc.pages

def prepare_document_table(request, docs, query=None, max_results=200):
"""Take a queryset of documents and a QueryDict with sorting info
and return list of documents with attributes filled in for
Expand Down Expand Up @@ -283,3 +283,86 @@ def num(i):
h["sort_url"] = "?" + d.urlencode()

return (docs, meta)


# The document types and state slugs to include in the AD dashboard
# and AD doc list, in the order they should be shown.
#
# "rfc" is a custom subset of "draft" that we special-case in the code
# to break out these docs into a separate table.
#
AD_WORKLOAD = {
"draft": [
"pub-req",
"ad-eval",
"lc-req",
"lc",
"writeupw",
# "defer", # probably not a useful state to show, since it's rare
"iesg-eva",
"goaheadw",
"approved",
"ann",
],
"rfc": [
"rfcqueue",
"rfc",
],
"conflrev": [
"needshep",
"adrev",
"iesgeval",
"approved", # synthesized state for all the "appr-" states
# "withdraw", # probably not a useful state to show
],
"statchg": [
"needshep",
"adrev",
"lc-req",
"in-lc",
"iesgeval",
"goahead",
"appr-sent",
# "dead", # probably not a useful state to show
],
"charter": [
"notrev",
"infrev",
"intrev",
"extrev",
"iesgrev",
"approved",
# "replaced", # probably not a useful state to show
],
}


def doc_type(doc):
dt = doc.type.slug
if (
doc.get_state_slug("draft") == "rfc"
or doc.get_state_slug("draft-iesg") == "rfcqueue"
):
dt = "rfc"
return dt


def doc_state(doc):
dt = doc.type.slug
ds = doc.get_state(dt)
if dt == "draft":
dis = doc.get_state("draft-iesg")
if ds.slug == "active" and dis:
return dis.slug
elif dt == "conflrev":
if ds.slug.startswith("appr"):
return "approved"
return ds.slug


def doc_type_name(doc_type):
if doc_type == "rfc":
return "RFC"
if doc_type == "draft":
return "Internet-Draft"
return DocTypeName.objects.get(slug=doc_type).name
Loading