Skip to content

Commit 53f7bc3

Browse files
committed
migrated forward
- Legacy-Id: 18144
2 parents 87b6ad9 + 066ee27 commit 53f7bc3

53 files changed

Lines changed: 15981 additions & 15545 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

ietf/doc/admin.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111
StateDocEvent, ConsensusDocEvent, BallotType, BallotDocEvent, WriteupDocEvent, LastCallDocEvent,
1212
TelechatDocEvent, BallotPositionDocEvent, ReviewRequestDocEvent, InitialReviewDocEvent,
1313
AddedMessageEvent, SubmissionDocEvent, DeletedEvent, EditedAuthorsDocEvent, DocumentURL,
14-
ReviewAssignmentDocEvent, IanaExpertDocEvent, IRSGBallotDocEvent )
14+
ReviewAssignmentDocEvent, IanaExpertDocEvent, IRSGBallotDocEvent, DocExtResource )
1515

16+
from ietf.utils.validators import validate_external_resource_value
1617

1718
class StateTypeAdmin(admin.ModelAdmin):
1819
list_display = ["slug", "label"]
@@ -183,3 +184,14 @@ class DocumentUrlAdmin(admin.ModelAdmin):
183184
search_fields = ['doc__name', 'url', ]
184185
raw_id_fields = ['doc', ]
185186
admin.site.register(DocumentURL, DocumentUrlAdmin)
187+
188+
class DocExtResourceAdminForm(forms.ModelForm):
189+
def clean(self):
190+
validate_external_resource_value(self.cleaned_data['name'],self.cleaned_data['value'])
191+
192+
class DocExtResourceAdmin(admin.ModelAdmin):
193+
form = DocExtResourceAdminForm
194+
list_display = ['id', 'doc', 'name', 'display_name', 'value',]
195+
search_fields = ['doc__name', 'value', 'display_name', 'name__slug',]
196+
raw_id_fields = ['doc', ]
197+
admin.site.register(DocExtResource, DocExtResourceAdmin)
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Copyright The IETF Trust 2020, All Rights Reserved
2+
import json
3+
4+
from django.core.management.base import BaseCommand
5+
6+
from ietf.extresource.models import ExtResource
7+
from ietf.doc.models import DocExtResource
8+
from ietf.group.models import GroupExtResource
9+
from ietf.person.models import PersonExtResource
10+
11+
class Command(BaseCommand):
12+
help = ('Locate information about gihub repositories to backup')
13+
14+
def handle(self, *args, **options):
15+
16+
info_dict = {}
17+
for repo in ExtResource.objects.filter(name__slug='github_repo'):
18+
if repo not in info_dict:
19+
info_dict[repo.value] = []
20+
21+
for username in DocExtResource.objects.filter(extresource__name__slug='github_username', doc__name__in=repo.docextresource_set.values_list('doc__name',flat=True).distinct()):
22+
info_dict[repo.value].push(username.value)
23+
24+
for username in GroupExtResource.objects.filter(extresource__name__slug='github_username', group__acronym__in=repo.groupextresource_set.values_list('group__acronym',flat=True).distinct()):
25+
info_dict[repo.value].push(username.value)
26+
27+
for username in PersonExtResource.objects.filter(extresource__name__slug='github_username', person_id__in=repo.personextresource_set.values_list('person__id',flat=True).distinct()):
28+
info_dict[repo.value].push(username.value)
29+
30+
print (json.dumps(info_dict))

ietf/doc/migrations/0033_extres.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# -*- coding: utf-8 -*-
2+
# Generated by Django 1.11.29 on 2020-04-15 10:20
3+
from __future__ import unicode_literals
4+
5+
from django.db import migrations, models
6+
import django.db.models.deletion
7+
import ietf.utils.models
8+
9+
10+
class Migration(migrations.Migration):
11+
12+
dependencies = [
13+
('name', '0013_extres'),
14+
('doc', '0032_auto_20200624_1332'),
15+
]
16+
17+
operations = [
18+
migrations.CreateModel(
19+
name='DocExtResource',
20+
fields=[
21+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
22+
('display_name', models.CharField(blank=True, default='', max_length=255)),
23+
('value', models.CharField(max_length=2083)),
24+
('doc', ietf.utils.models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='doc.Document')),
25+
('name', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='name.ExtResourceName')),
26+
],
27+
),
28+
]
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# Copyright The IETF Trust 2020, All Rights Reserved
2+
# -*- coding: utf-8 -*-
3+
# Generated by Django 1.11.29 on 2020-03-19 13:06
4+
from __future__ import unicode_literals
5+
6+
import re
7+
8+
import debug
9+
10+
from collections import OrderedDict, Counter
11+
12+
from django.db import migrations
13+
14+
from ietf.utils.validators import validate_external_resource_value
15+
from django.core.exceptions import ValidationError
16+
17+
18+
name_map = {
19+
"Issue.*": "tracker",
20+
".*FAQ.*": "faq",
21+
".*Area Web Page": "webpage",
22+
".*Wiki": "wiki",
23+
"Home Page": "webpage",
24+
"Slack.*": "slack",
25+
"Additional .* Web Page": "webpage",
26+
"Additional .* Page": "webpage",
27+
"Yang catalog entry.*": "yc_entry",
28+
"Yang impact analysis.*": "yc_impact",
29+
"GitHub": "github_repo",
30+
"Github page": "github_repo",
31+
"GitHub repo.*": "github_repo",
32+
"Github repository.*": "github_repo",
33+
"GitHub notifications": "github_notify",
34+
"GitHub org.*": "github_org",
35+
"GitHub User.*": "github_username",
36+
"GitLab User": "gitlab_username",
37+
"GitLab User Name": "gitlab_username",
38+
}
39+
40+
# TODO: Review all the None values below and make sure ignoring the URLs they match is really the right thing to do.
41+
url_map = OrderedDict({
42+
"https?://github\\.com": "github_repo",
43+
"https://git.sr.ht/": "repo",
44+
"https://todo.sr.ht/": "tracker",
45+
"https?://trac\\.ietf\\.org/.*/wiki": "wiki",
46+
"ietf\\.org.*/trac/wiki": "wiki",
47+
"trac.*wiki": "wiki",
48+
"www\\.ietf\\.org/mailman" : None,
49+
"www\\.ietf\\.org/mail-archive" : None,
50+
"mailarchive\\.ietf\\.org" : None,
51+
"ietf\\.org/logs": "jabber_log",
52+
"ietf\\.org/jabber/logs": "jabber_log",
53+
"xmpp:.*?join": "jabber_room",
54+
"bell-labs\\.com": None,
55+
"html\\.charters": None,
56+
"datatracker\\.ietf\\.org": None,
57+
})
58+
59+
def forward(apps, schema_editor):
60+
DocExtResource = apps.get_model('doc', 'DocExtResource')
61+
ExtResourceName = apps.get_model('name', 'ExtResourceName')
62+
DocumentUrl = apps.get_model('doc', 'DocumentUrl')
63+
64+
stats = Counter()
65+
66+
for doc_url in DocumentUrl.objects.all():
67+
match_found = False
68+
for regext,slug in name_map.items():
69+
if re.match(regext, doc_url.desc):
70+
match_found = True
71+
stats['mapped'] += 1
72+
name = ExtResourceName.objects.get(slug=slug)
73+
DocExtResource.objects.create(doc=doc_url.doc, name_id=slug, value=doc_url.url, display_name=doc_url.desc) # TODO: validate this value against name.type
74+
break
75+
if not match_found:
76+
for regext, slug in url_map.items():
77+
doc_url.url = doc_url.url.strip()
78+
if re.search(regext, doc_url.url):
79+
match_found = True
80+
if slug:
81+
stats['mapped'] +=1
82+
name = ExtResourceName.objects.get(slug=slug)
83+
# Munge the URL if it's the first github repo match
84+
# Remove "/tree/master" substring if it exists
85+
# Remove trailing "/issues" substring if it exists
86+
# Remove "/blob/master/.*" pattern if present
87+
if regext == "https?://github\\.com":
88+
doc_url.url = doc_url.url.replace("/tree/master","")
89+
doc_url.url = re.sub('/issues$', '', doc_url.url)
90+
doc_url.url = re.sub('/blob/master.*$', '', doc_url.url)
91+
try:
92+
validate_external_resource_value(name, doc_url.url)
93+
DocExtResource.objects.create(doc=doc_url.doc, name=name, value=doc_url.url, display_name=doc_url.desc) # TODO: validate this value against name.type
94+
except ValidationError as e: # pyflakes:ignore
95+
debug.show('("Failed validation:", doc_url.url, e)')
96+
stats['failed_validation'] +=1
97+
else:
98+
stats['ignored'] +=1
99+
break
100+
if not match_found:
101+
debug.show('("Not Mapped:",doc_url.desc, doc_url.tag.slug, doc_url.doc.name, doc_url.url)')
102+
stats['not_mapped'] += 1
103+
print (stats)
104+
105+
def reverse(apps, schema_editor):
106+
DocExtResource = apps.get_model('doc', 'DocExtResource')
107+
DocExtResource.objects.all().delete()
108+
109+
class Migration(migrations.Migration):
110+
111+
dependencies = [
112+
('doc', '0033_extres'),
113+
('name', '0014_populate_extres'),
114+
]
115+
116+
operations = [
117+
migrations.RunPython(forward, reverse)
118+
]

ietf/doc/models.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
from ietf.group.models import Group
2525
from ietf.name.models import ( DocTypeName, DocTagName, StreamName, IntendedStdLevelName, StdLevelName,
2626
DocRelationshipName, DocReminderTypeName, BallotPositionName, ReviewRequestStateName, ReviewAssignmentStateName, FormalLanguageName,
27-
DocUrlTagName)
27+
DocUrlTagName, ExtResourceName)
2828
from ietf.person.models import Email, Person
2929
from ietf.person.utils import get_active_balloters
3030
from ietf.utils import log
@@ -105,6 +105,7 @@ class DocumentInfo(models.Model):
105105
note = models.TextField(blank=True)
106106
internal_comments = models.TextField(blank=True)
107107

108+
108109
def file_extension(self):
109110
if not hasattr(self, '_cached_extension'):
110111
if self.uploaded_filename:
@@ -861,6 +862,15 @@ class DocumentURL(models.Model):
861862
desc = models.CharField(max_length=255, default='', blank=True)
862863
url = models.URLField(max_length=2083) # 2083 is the legal max for URLs
863864

865+
class DocExtResource(models.Model):
866+
doc = ForeignKey(Document) # Should this really be to DocumentInfo rather than Document?
867+
name = models.ForeignKey(ExtResourceName, on_delete=models.CASCADE)
868+
display_name = models.CharField(max_length=255, default='', blank=True)
869+
value = models.CharField(max_length=2083) # 2083 is the maximum legal URL length
870+
def __str__(self):
871+
priority = self.display_name or self.name.name
872+
return u"%s (%s) %s" % (priority, self.name.slug, self.value)
873+
864874
class RelatedDocHistory(models.Model):
865875
source = ForeignKey('DocHistory')
866876
target = ForeignKey('DocAlias', related_name="reversely_related_document_history_set")

ietf/doc/resources.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
InitialReviewDocEvent, DocHistoryAuthor, BallotDocEvent, RelatedDocument,
1818
RelatedDocHistory, BallotPositionDocEvent, AddedMessageEvent, SubmissionDocEvent,
1919
ReviewRequestDocEvent, ReviewAssignmentDocEvent, EditedAuthorsDocEvent, DocumentURL,
20-
IanaExpertDocEvent, IRSGBallotDocEvent )
20+
IanaExpertDocEvent, IRSGBallotDocEvent, DocExtResource )
2121

2222
from ietf.name.resources import BallotPositionNameResource, DocTypeNameResource
2323
class BallotTypeResource(ModelResource):
@@ -767,3 +767,23 @@ class Meta:
767767
"ballotdocevent_ptr": ALL_WITH_RELATIONS,
768768
}
769769
api.doc.register(IRSGBallotDocEventResource())
770+
771+
772+
from ietf.name.resources import ExtResourceNameResource
773+
class DocExtResourceResource(ModelResource):
774+
doc = ToOneField(DocumentResource, 'doc')
775+
name = ToOneField(ExtResourceNameResource, 'name')
776+
class Meta:
777+
queryset = DocExtResource.objects.all()
778+
serializer = api.Serializer()
779+
cache = SimpleCache()
780+
resource_name = 'docextresource'
781+
ordering = ['id', ]
782+
filtering = {
783+
"id": ALL,
784+
"display_name": ALL,
785+
"value": ALL,
786+
"doc": ALL_WITH_RELATIONS,
787+
"name": ALL_WITH_RELATIONS,
788+
}
789+
api.doc.register(DocExtResourceResource())

ietf/doc/tests_draft.py

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,24 +1104,44 @@ def test_doc_change_shepherd_writeup(self):
11041104
q = PyQuery(r.content)
11051105
self.assertTrue(q('textarea')[0].text.strip().startswith("As required by RFC 4858"))
11061106

1107-
def test_doc_change_document_urls(self):
1108-
url = urlreverse('ietf.doc.views_draft.edit_document_urls', kwargs=dict(name=self.docname))
1109-
1110-
# get
1107+
def test_edit_doc_extresources(self):
1108+
url = urlreverse('ietf.doc.views_draft.edit_doc_extresources', kwargs=dict(name=self.docname))
1109+
11111110
login_testing_unauthorized(self, "secretary", url)
11121111

11131112
r = self.client.get(url)
11141113
self.assertEqual(r.status_code,200)
11151114
q = PyQuery(r.content)
1116-
self.assertEqual(len(q('form textarea[id=id_urls]')),1)
1115+
self.assertEqual(len(q('form textarea[id=id_resources]')),1)
11171116

1118-
# direct edit
1119-
r = self.client.post(url, dict(urls='wiki https://wiki.org/ Wiki\nrepository https://repository.org/ Repo\n', submit="1"))
1117+
badlines = (
1118+
'github_repo https://github3.com/some/repo',
1119+
'github_notify badaddr',
1120+
'website /not/a/good/url'
1121+
'notavalidtag blahblahblah'
1122+
)
1123+
1124+
for line in badlines:
1125+
r = self.client.post(url, dict(resources=line, submit="1"))
1126+
self.assertEqual(r.status_code, 200)
1127+
q = PyQuery(r.content)
1128+
self.assertTrue(q('.alert-danger'))
1129+
1130+
goodlines = """
1131+
github_repo https://github.com/some/repo Some display text
1132+
github_notify notify@example.com
1133+
github_username githubuser
1134+
website http://example.com/http/is/fine
1135+
"""
1136+
1137+
r = self.client.post(url, dict(resources=goodlines, submit="1"))
11201138
self.assertEqual(r.status_code,302)
11211139
doc = Document.objects.get(name=self.docname)
1122-
self.assertTrue(doc.latest_event(DocEvent,type="changed_document").desc.startswith('Changed document URLs'))
1123-
self.assertIn('wiki https://wiki.org/', doc.latest_event(DocEvent,type="changed_document").desc)
1124-
self.assertIn('https://wiki.org/', [ u.url for u in doc.documenturl_set.all() ])
1140+
self.assertEqual(doc.latest_event(DocEvent,type="changed_document").desc[:35], 'Changed document external resources')
1141+
self.assertIn('github_username githubuser', doc.latest_event(DocEvent,type="changed_document").desc)
1142+
self.assertEqual(doc.docextresource_set.count(), 4)
1143+
self.assertEqual(doc.docextresource_set.get(name__slug='github_repo').display_name, 'Some display text')
1144+
11251145

11261146
class SubmitToIesgTests(TestCase):
11271147

ietf/doc/urls.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@
128128
url(r'^%(name)s/edit/approveballot/$' % settings.URL_REGEXPS, views_ballot.approve_ballot),
129129
url(r'^%(name)s/edit/approvedownrefs/$' % settings.URL_REGEXPS, views_ballot.approve_downrefs),
130130
url(r'^%(name)s/edit/makelastcall/$' % settings.URL_REGEXPS, views_ballot.make_last_call),
131-
url(r'^%(name)s/edit/urls/$' % settings.URL_REGEXPS, views_draft.edit_document_urls),
131+
url(r'^%(name)s/edit/resources/$' % settings.URL_REGEXPS, views_draft.edit_doc_extresources),
132132
url(r'^%(name)s/edit/issueballot/irsg/$' % settings.URL_REGEXPS, views_ballot.issue_irsg_ballot),
133133
url(r'^%(name)s/edit/closeballot/irsg/$' % settings.URL_REGEXPS, views_ballot.close_irsg_ballot),
134134

0 commit comments

Comments
 (0)