Provide a metadata endpoint to assist rfcdiff.pyht. Commit ready for merge.

- Legacy-Id: 19396
This commit is contained in:
Robert Sparks 2021-10-01 21:31:24 +00:00
parent 58fa3218eb
commit 036966da97
3 changed files with 261 additions and 2 deletions

View file

@ -48,7 +48,7 @@ from ietf.name.models import SessionStatusName, BallotPositionName, DocTypeName
from ietf.person.models import Person from ietf.person.models import Person
from ietf.person.factories import PersonFactory, EmailFactory from ietf.person.factories import PersonFactory, EmailFactory
from ietf.utils.mail import outbox from ietf.utils.mail import outbox
from ietf.utils.test_utils import login_testing_unauthorized, unicontent from ietf.utils.test_utils import login_testing_unauthorized, unicontent, reload_db_objects
from ietf.utils.test_utils import TestCase from ietf.utils.test_utils import TestCase
from ietf.utils.text import normalize_text from ietf.utils.text import normalize_text
@ -2502,3 +2502,123 @@ class Idnits2SupportTests(TestCase):
r = self.client.get(url) r = self.client.get(url)
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
self.assertContains(r,'Proposed') self.assertContains(r,'Proposed')
class RfcdiffSupportTests(TestCase):
def setUp(self):
self.target_view = 'ietf.doc.views_doc.rfcdiff_latest_json'
def getJson(self, view_args):
url = urlreverse(self.target_view, kwargs=view_args)
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
return r.json()
def test_draft(self):
draft = IndividualDraftFactory(name='draft-somebody-did-something',rev='00')
for r in range(0,13):
e = NewRevisionDocEventFactory(doc=draft,rev=f'{r:02d}')
draft.rev = f'{r:02d}'
draft.save_with_history([e])
draft = reload_db_objects(draft)
received = self.getJson(dict(name=draft.name))
self.assertEqual(received, dict(
name=draft.name,
rev=draft.rev,
content_url=draft.get_href(),
previous=f'{draft.name}-{(int(draft.rev)-1):02d}'
))
received = self.getJson(dict(name=draft.name, rev=draft.rev))
self.assertEqual(received, dict(
name=draft.name,
rev=draft.rev,
content_url=draft.get_href(),
previous=f'{draft.name}-{(int(draft.rev)-1):02d}'
))
received = self.getJson(dict(name=draft.name, rev='10'))
self.assertEqual(received, dict(
name=draft.name,
rev='10',
content_url=draft.history_set.get(rev='10').get_href(),
previous=f'{draft.name}-09'
))
received = self.getJson(dict(name=draft.name, rev='00'))
self.assertNotIn('previous', received)
replaced = IndividualDraftFactory()
RelatedDocument.objects.create(relationship_id='replaces',source=draft,target=replaced.docalias.first())
received = self.getJson(dict(name=draft.name, rev='00'))
self.assertEqual(received['previous'], f'{replaced.name}-{replaced.rev}')
def test_draft_with_broken_history(self):
draft = IndividualDraftFactory(rev='10')
received = self.getJson(dict(name=draft.name,rev='09'))
self.assertEqual(received['rev'],'09')
self.assertEqual(received['previous'], f'{draft.name}-09')
self.assertTrue('warning' in received)
def test_draftname_with_numeric_suffix(self):
draft = IndividualDraftFactory(name='draft-someone-did-something-01-02',rev='00')
for r in range(0,4):
e = NewRevisionDocEventFactory(doc=draft,rev=f'{r:02d}')
draft.rev = f'{r:02d}'
draft.save_with_history([e])
received = self.getJson(dict(name=draft.name))
self.assertEqual(received['rev'],'03')
self.assertIn('01-02-03',received['content_url'])
self.assertIn('01-02-02',received['previous'])
received = self.getJson(dict(name=draft.name,rev='02'))
self.assertEqual(received['rev'],'02')
self.assertIn('01-02-02',received['content_url'])
def test_rfc(self):
draft = WgDraftFactory()
for r in range(0,2):
e = NewRevisionDocEventFactory(doc=draft,rev=f'{r:02d}')
draft.rev = f'{r:02d}'
draft.save_with_history([e])
draft.docalias.create(name='rfc8000')
draft.set_state(State.objects.get(type_id='draft',slug='rfc'))
draft.set_state(State.objects.get(type_id='draft-iesg', slug='pub'))
draft = reload_db_objects(draft)
rfc = draft
number = rfc.rfc_number()
received = self.getJson(dict(name=number))
self.assertEqual(received, dict(
content_url=rfc.get_href(),
name=rfc.canonical_name(),
previous=f'{draft.name}-{draft.rev}',
))
num_received = received
received = self.getJson(dict(name=rfc.canonical_name()))
self.assertEqual(num_received, received)
def test_rfc_with_tombstone(self):
draft = WgDraftFactory()
for r in range(0,2):
e = NewRevisionDocEventFactory(doc=draft,rev=f'{r:02d}')
draft.rev = f'{r:02d}'
draft.save_with_history([e])
draft.docalias.create(name='rfc3261') # See views_doc.HAS_TOMBSTONE
draft.set_state(State.objects.get(type_id='draft',slug='rfc'))
draft.set_state(State.objects.get(type_id='draft-iesg', slug='pub'))
draft = reload_db_objects(draft)
rfc = draft
# Some old rfcs had tombstones that shouldn't be used for comparisons
received = self.getJson(dict(name=rfc.canonical_name()))
self.assertTrue(received['previous'].endswith('00'))

View file

@ -71,6 +71,11 @@ urlpatterns = [
url(r'^html/(?P<name>[Rr][Ff][Cc] [0-9]+?)(\.txt|\.html)?/?$', views_doc.document_html), url(r'^html/(?P<name>[Rr][Ff][Cc] [0-9]+?)(\.txt|\.html)?/?$', views_doc.document_html),
url(r'^idnits2-rfcs-obsoleted/?$', views_doc.idnits2_rfcs_obsoleted), url(r'^idnits2-rfcs-obsoleted/?$', views_doc.idnits2_rfcs_obsoleted),
url(r'^idnits2-rfc-status/?$', views_doc.idnits2_rfc_status), url(r'^idnits2-rfc-status/?$', views_doc.idnits2_rfc_status),
# These two are proof-of-concept of a service that would redirect to the latest version
# url(r'^rfcdiff-latest/%(name)s(?:-%(rev)s)?(\.txt|\.html)?/?$' % settings.URL_REGEXPS, views_doc.rfcdiff_latest),
# url(r'^rfcdiff-latest/(?P<name>[Rr][Ff][Cc] [0-9]+?)(\.txt|\.html)?/?$', views_doc.rfcdiff_latest),
url(r'^rfcdiff-latest-json/%(name)s(?:-%(rev)s)?(\.txt|\.html)?/?$' % settings.URL_REGEXPS, views_doc.rfcdiff_latest_json),
url(r'^rfcdiff-latest-json/(?P<name>[Rr][Ff][Cc] [0-9]+?)(\.txt|\.html)?/?$', views_doc.rfcdiff_latest_json),
url(r'^all/?$', views_search.index_all_drafts), url(r'^all/?$', views_search.index_all_drafts),
url(r'^active/?$', views_search.index_active_drafts), url(r'^active/?$', views_search.index_active_drafts),

View file

@ -1772,8 +1772,142 @@ def idnits2_state(request, name, rev=None):
doc.deststatus="Unknown" doc.deststatus="Unknown"
return render(request, 'doc/idnits2-state.txt', context={'doc':doc}, content_type='text/plain;charset=utf-8') return render(request, 'doc/idnits2-state.txt', context={'doc':doc}, content_type='text/plain;charset=utf-8')
def find_doc_for_rfcdiff(name, rev):
if name.startswith('rfc0'):
name = "rfc" + name[3:].lstrip('0')
if name.startswith('review-') and re.search(r'-\d\d\d\d-\d\d$', name):
name = "%s-%s" % (name, rev)
if rev and not name.startswith('charter-') and re.search('[0-9]{1,2}-[0-9]{2}', rev):
name = "%s-%s" % (name, rev[:-3])
rev = rev[-2:]
if re.match("^[0-9]+$", name):
name = f'rfc{name}'
if re.match("^[Rr][Ff][Cc] [0-9]+$",name):
name = f'rfc{name[4:]}'
docs = Document.objects.filter(docalias__name=name, type_id='draft')
if rev and not docs.exists():
# handle some special cases, like draft-ietf-tsvwg-ieee-802-11
name = '%s-%s' % (name, rev)
rev=None
docs = Document.objects.filter(docalias__name=name, type_id='draft')
condition = 'no such document'
if not docs.exists() or docs.count() > 1:
return (condition, None, None)
doc = docs.get()
if not rev or (rev and doc.rev==rev):
condition = 'current version'
return condition, doc, None
else:
candidate = None
for h in doc.history_set.order_by("-time"):
if rev == h.rev:
candidate = h
break
if candidate:
condition = 'historic version'
return condition, doc, candidate
else:
condition = 'version dochistory not found'
return condition, doc, None
# This is a proof of concept of a service that would redirect to the current revision
# def rfcdiff_latest(request, name, rev=None):
# condition, doc, history = find_doc_for_rfcdiff(name, rev)
# if not doc:
# raise Http404
# if history:
# return redirect(history.get_href())
# else:
# return redirect(doc.get_href())
HAS_TOMBSTONE = [
2821, 2822, 2873, 2919, 2961, 3023, 3029, 3031, 3032, 3033, 3034, 3035, 3036,
3037, 3038, 3042, 3044, 3050, 3052, 3054, 3055, 3056, 3057, 3059, 3060, 3061,
3062, 3063, 3064, 3067, 3068, 3069, 3070, 3071, 3072, 3073, 3074, 3075, 3076,
3077, 3078, 3080, 3081, 3082, 3084, 3085, 3086, 3087, 3088, 3089, 3090, 3094,
3095, 3096, 3097, 3098, 3101, 3102, 3103, 3104, 3105, 3106, 3107, 3108, 3109,
3110, 3111, 3112, 3113, 3114, 3115, 3116, 3117, 3118, 3119, 3120, 3121, 3123,
3124, 3126, 3127, 3128, 3130, 3131, 3132, 3133, 3134, 3135, 3136, 3137, 3138,
3139, 3140, 3141, 3142, 3143, 3144, 3145, 3147, 3149, 3150, 3151, 3152, 3153,
3154, 3155, 3156, 3157, 3158, 3159, 3160, 3161, 3162, 3163, 3164, 3165, 3166,
3167, 3168, 3169, 3170, 3171, 3172, 3173, 3174, 3176, 3179, 3180, 3181, 3182,
3183, 3184, 3185, 3186, 3187, 3188, 3189, 3190, 3191, 3192, 3193, 3194, 3197,
3198, 3201, 3202, 3203, 3204, 3205, 3206, 3207, 3208, 3209, 3210, 3211, 3212,
3213, 3214, 3215, 3216, 3217, 3218, 3220, 3221, 3222, 3224, 3225, 3226, 3227,
3228, 3229, 3230, 3231, 3232, 3233, 3234, 3235, 3236, 3237, 3238, 3240, 3241,
3242, 3243, 3244, 3245, 3246, 3247, 3248, 3249, 3250, 3253, 3254, 3255, 3256,
3257, 3258, 3259, 3260, 3261, 3262, 3263, 3264, 3265, 3266, 3267, 3268, 3269,
3270, 3271, 3272, 3273, 3274, 3275, 3276, 3278, 3279, 3280, 3281, 3282, 3283,
3284, 3285, 3286, 3287, 3288, 3289, 3290, 3291, 3292, 3293, 3294, 3295, 3296,
3297, 3298, 3301, 3302, 3303, 3304, 3305, 3307, 3308, 3309, 3310, 3311, 3312,
3313, 3315, 3317, 3318, 3319, 3320, 3321, 3322, 3323, 3324, 3325, 3326, 3327,
3329, 3330, 3331, 3332, 3334, 3335, 3336, 3338, 3340, 3341, 3342, 3343, 3346,
3348, 3349, 3351, 3352, 3353, 3354, 3355, 3356, 3360, 3361, 3362, 3363, 3364,
3366, 3367, 3368, 3369, 3370, 3371, 3372, 3374, 3375, 3377, 3378, 3379, 3383,
3384, 3385, 3386, 3387, 3388, 3389, 3390, 3391, 3394, 3395, 3396, 3397, 3398,
3401, 3402, 3403, 3404, 3405, 3406, 3407, 3408, 3409, 3410, 3411, 3412, 3413,
3414, 3415, 3416, 3417, 3418, 3419, 3420, 3421, 3422, 3423, 3424, 3425, 3426,
3427, 3428, 3429, 3430, 3431, 3433, 3434, 3435, 3436, 3437, 3438, 3439, 3440,
3441, 3443, 3444, 3445, 3446, 3447, 3448, 3449, 3450, 3451, 3452, 3453, 3454,
3455, 3458, 3459, 3460, 3461, 3462, 3463, 3464, 3465, 3466, 3467, 3468, 3469,
3470, 3471, 3472, 3473, 3474, 3475, 3476, 3477, 3480, 3481, 3483, 3485, 3488,
3494, 3495, 3496, 3497, 3498, 3501, 3502, 3503, 3504, 3505, 3506, 3507, 3508,
3509, 3511, 3512, 3515, 3516, 3517, 3518, 3520, 3521, 3522, 3523, 3524, 3525,
3527, 3529, 3530, 3532, 3533, 3534, 3536, 3537, 3538, 3539, 3541, 3543, 3544,
3545, 3546, 3547, 3548, 3549, 3550, 3551, 3552, 3555, 3556, 3557, 3558, 3559,
3560, 3562, 3563, 3564, 3565, 3568, 3569, 3570, 3571, 3572, 3573, 3574, 3575,
3576, 3577, 3578, 3579, 3580, 3581, 3582, 3583, 3584, 3588, 3589, 3590, 3591,
3592, 3593, 3594, 3595, 3597, 3598, 3601, 3607, 3609, 3610, 3612, 3614, 3615,
3616, 3625, 3627, 3630, 3635, 3636, 3637, 3638
]
def rfcdiff_latest_json(request, name, rev=None):
response = dict()
condition, document, history = find_doc_for_rfcdiff(name, rev)
if condition == 'no such document':
raise Http404
elif condition in ('historic version', 'current version'):
doc = history if history else document
if not rev and doc.is_rfc():
response['content_url'] = doc.get_href()
response['name']=doc.canonical_name()
if doc.name != doc.canonical_name():
prev_rev = doc.rev
if int(doc.rfc_number()) in HAS_TOMBSTONE and prev_rev != '00':
prev_rev = f'{(int(doc.rev)-1):02d}'
response['previous'] = f'{doc.name}-{prev_rev}'
else:
doc.is_rfc = lambda: False
response['content_url'] = doc.get_href()
response['rev'] = doc.rev
response['name'] = doc.name
if doc.rev == '00':
replaces_docs = (history.doc if condition=='historic version' else doc).related_that_doc('replaces')
if replaces_docs:
replaces = replaces_docs[0].document
response['previous'] = f'{replaces.name}-{replaces.rev}'
else:
match = re.search("-(rfc)?([0-9][0-9][0-9]+)bis(-.*)?$", name)
if match and match.group(2):
response['previous'] = f'rfc{match.group(2)}'
else:
response['previous'] = f'{doc.name}-{(int(doc.rev)-1):02d}'
elif condition == 'version dochistory not found':
response['warning'] = 'History for this version not found - these results are speculation'
response['name'] = document.name
response['rev'] = rev
document.rev = rev
document.is_rfc = lambda: False
response['content_url'] = document.get_href()
if int(rev)>0:
response['previous'] = f'{document.name}-{(int(rev)-1):02d}'
else:
match = re.search("-(rfc)?([0-9][0-9][0-9]+)bis(-.*)?$", name)
if match and match.group(2):
response['previous'] = f'rfc{match.group(2)}'
if not response:
raise Http404
return HttpResponse(json.dumps(response), content_type='application/json')