Merged in [19396] from rjsparks@nostrum.com:

Provide a metadata endpoint to assist rfcdiff.pyht.
 - Legacy-Id: 19397
Note: SVN reference [19396] has been migrated to Git commit 036966da97
This commit is contained in:
Robert Sparks 2021-10-01 22:08:16 +00:00
commit 6a13fd7062
3 changed files with 264 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.factories import PersonFactory, EmailFactory
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.text import normalize_text
@ -2502,3 +2502,126 @@ class Idnits2SupportTests(TestCase):
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
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}-08')
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)
received = self.getJson(dict(name=f'RfC {number}'))
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'^idnits2-rfcs-obsoleted/?$', views_doc.idnits2_rfcs_obsoleted),
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'^active/?$', views_search.index_active_drafts),

View file

@ -1772,8 +1772,142 @@ def idnits2_state(request, name, rev=None):
doc.deststatus="Unknown"
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')