1
0
mirror of https://github.com/peeringdb/peeringdb.git synced 2024-05-11 05:55:09 +00:00
* use new peeringdb client (1.0.0) for pdb_load_data sync (#599)

* drop django-mobi for lack of py3/dj2 support (#492)
remove django-forms-bootstrap for lack of py3/dj2 support (#492)

* black formatted

* django2.2 and py3 upgrade (#492)

* drop ixlans (#21) ui and api changes

* drop local_asn (#168)

* org search (#193)

* phone number validation (#50)

* implement help text tooltips (#228)

* Mark own ASN as transit-free (#394)

* py3 fix for `pdb_migrate_ixlans` command when writing migration report

* pdb_migrate_ixlans: properly handle py3 Runtime error if ixlan dict changes during iteration

* set rest DEFAULT_SCHEMA_CLASS to coreapi to fix swagger apidocs
fix migration 0027 missing from facsimile manifest

* fix swagger doc strings

* fix tests that were broken from api doc fixes

* fix UniqueFieldValidator for netixlan ipaddress validation that broke during django/drf upgrade

* fix org merge tool layout issues

* travis config

* update pipfile and lock

* black formatting

* update travis dist

* beta mode banner (#411)

* add beta banner template (#411)

* automatically scheduled sync may not always be on, add a flag that lets us reflect that state in the beta banner message
clean up beta banner implementation (#411)

* add tests for beta banner (#411)
This commit is contained in:
Matt Griswold
2020-01-08 13:29:58 -06:00
committed by GitHub
parent cf56acbfc4
commit ba6f9b6432
160 changed files with 4205 additions and 2098 deletions

View File

@@ -2,21 +2,21 @@ import datetime
import time
import json
import ipaddress
import forms
from . import forms
from operator import or_
import django.urls
from django.conf.urls import url
from django.shortcuts import redirect, Http404
from django.contrib.contenttypes.models import ContentType
from django.contrib import admin
from django.contrib import admin, messages
from django.contrib.auth import forms
from django.contrib.admin import helpers
from django.contrib.admin.actions import delete_selected
from django.contrib.admin.views.main import ChangeList
from django import forms as baseForms
from django.utils import html
from django.core import urlresolvers
from django.core.exceptions import ValidationError
from django.conf import settings
from django.template import loader
@@ -28,6 +28,7 @@ from django_namespace_perms.admin import (
UserPermissionInlineAdd,
UserAdmin,
)
from django.utils.safestring import mark_safe
import reversion
from reversion.admin import VersionAdmin
@@ -67,7 +68,7 @@ from peeringdb_server.models import (
from peeringdb_server.mail import mail_users_entity_merge
from peeringdb_server.inet import RdapLookup, RdapException
delete_selected.short_description = u"HARD DELETE - Proceed with caution"
delete_selected.short_description = "HARD DELETE - Proceed with caution"
from django.utils.translation import ugettext_lazy as _
@@ -294,6 +295,16 @@ rollback.short_description = _("ROLLBACK")
def soft_delete(modeladmin, request, queryset):
if request.user:
reversion.set_user(request.user)
if queryset.model.handleref.tag == "ixlan":
messages.error(
request,
_(
"Ixlans can no longer be directly deleted as they are now synced to the parent exchange"
),
)
return
for row in queryset:
row.delete()
@@ -385,13 +396,13 @@ class ModelAdminWithVQCtrl(object):
).first()
if vq:
return (
u'<a class="grp-button" href="{}">{}</a> &nbsp; &nbsp; <a class="grp-button grp-delete-link" href="{}">{}</a>'
).format(vq.approve_admin_url, _("APPROVE"), vq.deny_admin_url, _("DENY"))
return mark_safe(
'<a class="grp-button" href="{}">{}</a> &nbsp; &nbsp; <a class="grp-button grp-delete-link" href="{}">{}</a>'.format(
vq.approve_admin_url, _("APPROVE"), vq.deny_admin_url, _("DENY")
)
)
return _("APPROVED")
verification_queue.allow_tags = True
class IXLanPrefixInline(SanitizedAdmin, admin.TabularInline):
model = IXLanPrefix
@@ -404,15 +415,19 @@ class IXLanInline(SanitizedAdmin, admin.StackedInline):
extra = 0
form = StatusForm
exclude = ["arp_sponge"]
readonly_fields = ["ixf_import_attempt_info", "prefixes"]
readonly_fields = ["id", "ixf_import_attempt_info", "prefixes"]
def has_add_permission(self, request):
return False
def has_delete_permission(self, request, obj):
return False
def ixf_import_attempt_info(self, obj):
if obj.ixf_import_attempt:
return "<pre>{}</pre>".format(obj.ixf_import_attempt.info)
return mark_safe("<pre>{}</pre>".format(obj.ixf_import_attempt.info))
return ""
ixf_import_attempt_info.allow_tags = True
def prefixes(self, obj):
return ", ".join(
[str(ixpfx.prefix) for ixpfx in obj.ixpfx_set_active_or_pending]
@@ -535,16 +550,16 @@ class InternetExchangeAdmin(ModelAdminWithVQCtrl, SoftDeleteAdmin):
form = InternetExchangeAdminForm
def ixf_import_history(self, obj):
return (u'<a href="{}?q={}">{}</a>').format(
urlresolvers.reverse(
"admin:peeringdb_server_ixlanixfmemberimportlog_changelist"
),
obj.id,
_("IXF Import History"),
return mark_safe(
'<a href="{}?q={}">{}</a>'.format(
django.urls.reverse(
"admin:peeringdb_server_ixlanixfmemberimportlog_changelist"
),
obj.id,
_("IXF Import History"),
)
)
ixf_import_history.allow_tags = True
class IXLanAdminForm(StatusForm):
def __init__(self, *args, **kwargs):
@@ -553,6 +568,7 @@ class IXLanAdminForm(StatusForm):
class IXLanAdmin(SoftDeleteAdmin):
actions = []
list_display = ("ix", "name", "descr", "status")
search_fields = ("name",)
list_filter = (StatusFilter,)
@@ -609,7 +625,7 @@ class IXLanIXFMemberImportLogEntryInline(admin.TabularInline):
if not vb:
return _("Initial creation of netixlan")
rv = {}
for k, v in va.field_dict.items():
for k, v in list(va.field_dict.items()):
if k in ["created", "updated", "version"]:
continue
v2 = vb.field_dict.get(k)
@@ -631,12 +647,12 @@ class IXLanIXFMemberImportLogEntryInline(admin.TabularInline):
text = _("CAN BE ROLLED BACK")
color = "#e5f3d6"
elif rs == 1:
text = (u"{}<br><small>{}</small>").format(
text = ("{}<br><small>{}</small>").format(
_("CANNOT BE ROLLED BACK"), _("Has been changed since")
)
color = "#f3ded6"
elif rs == 2:
text = (u"{}<br><small>{}</small>").format(
text = ("{}<br><small>{}</small>").format(
_("CANNOT BE ROLLED BACK"),
_("Netixlan with conflicting ipaddress now exists elsewhere"),
)
@@ -644,9 +660,9 @@ class IXLanIXFMemberImportLogEntryInline(admin.TabularInline):
elif rs == -1:
text = _("HAS BEEN ROLLED BACK")
color = "#d6f0f3"
return '<div style="background-color:{}">{}</div>'.format(color, text)
rollback_status.allow_tags = True
return mark_safe(
'<div style="background-color:{}">{}</div>'.format(color, text)
)
class IXLanIXFMemberImportLogAdmin(admin.ModelAdmin):
@@ -663,28 +679,28 @@ class IXLanIXFMemberImportLogAdmin(admin.ModelAdmin):
return obj.entries.count()
def ix(self, obj):
return '<a href="{}">{} (ID: {})</a>'.format(
urlresolvers.reverse(
"admin:peeringdb_server_internetexchange_change",
args=(obj.ixlan.ix.id,),
),
obj.ixlan.ix.name,
obj.ixlan.ix.id,
return mark_safe(
'<a href="{}">{} (ID: {})</a>'.format(
django.urls.reverse(
"admin:peeringdb_server_internetexchange_change",
args=(obj.ixlan.ix.id,),
),
obj.ixlan.ix.name,
obj.ixlan.ix.id,
)
)
ix.allow_tags = True
def ixlan_name(self, obj):
return '<a href="{}">{} (ID: {})</a>'.format(
urlresolvers.reverse(
"admin:peeringdb_server_ixlan_change", args=(obj.ixlan.id,)
),
obj.ixlan.name or "",
obj.ixlan.id,
return mark_safe(
'<a href="{}">{} (ID: {})</a>'.format(
django.urls.reverse(
"admin:peeringdb_server_ixlan_change", args=(obj.ixlan.id,)
),
obj.ixlan.name or "",
obj.ixlan.id,
)
)
ixlan_name.allow_tags = True
def source(self, obj):
return obj.ixlan.ixf_ixp_member_list_url
@@ -724,15 +740,11 @@ class SponsorshipAdmin(admin.ModelAdmin):
else:
return _("Waiting")
status.allow_tags = True
def organizations(self, obj):
qset = obj.orgs.all().order_by("name")
if not qset.count():
return _("No organization(s) set")
return "<br>\n".join([html.escape(org.name) for org in qset])
organizations.allow_tags = True
return mark_safe("<br>\n".join([html.escape(org.name) for org in qset]))
class PartnershipAdminForm(baseForms.ModelForm):
@@ -759,8 +771,6 @@ class PartnershipAdmin(admin.ModelAdmin):
return _("Logo Missing")
return _("Active")
status.allow_tags = True
class OrganizationAdmin(ModelAdminWithVQCtrl, SoftDeleteAdmin):
list_display = ("handle", "name", "status", "created", "updated")
@@ -803,7 +813,7 @@ class OrganizationAdmin(ModelAdminWithVQCtrl, SoftDeleteAdmin):
return redirect("admin:login")
context = dict(
self.admin_site.each_context(request),
undo_url=urlresolvers.reverse(
undo_url=django.urls.reverse(
"admin:peeringdb_server_organizationmerge_changelist"
),
title=_("Organization Merging Tool"),
@@ -832,11 +842,11 @@ class OrganizationMergeLog(ModelAdminWithUrlActions):
inlines = (OrganizationMergeEntities,)
def undo_merge(self, obj):
return (
u'<a class="grp-button grp-delete-link" href="action/undo">{}</a>'
).format(_("Undo merge"))
undo_merge.allow_tags = True
return mark_safe(
'<a class="grp-button grp-delete-link" href="action/undo">{}</a>'.format(
_("Undo merge")
)
)
@reversion.create_revision()
def undo(modeladmin, request, queryset):
@@ -949,7 +959,7 @@ class NetworkIXLanAdmin(SoftDeleteAdmin):
return obj.ixlan.ix
def net(self, obj):
return u"{} (AS{})".format(obj.network.name, obj.network.asn)
return "{} (AS{})".format(obj.network.name, obj.network.asn)
class NetworkContactAdmin(SoftDeleteAdmin):
@@ -970,7 +980,7 @@ class NetworkContactAdmin(SoftDeleteAdmin):
form = StatusForm
def net(self, obj):
return u"{} (AS{})".format(obj.network.name, obj.network.asn)
return "{} (AS{})".format(obj.network.name, obj.network.asn)
class NetworkFacilityAdmin(SoftDeleteAdmin):
@@ -981,7 +991,7 @@ class NetworkFacilityAdmin(SoftDeleteAdmin):
form = StatusForm
def net(self, obj):
return u"{} (AS{})".format(obj.network.name, obj.network.asn)
return "{} (AS{})".format(obj.network.name, obj.network.asn)
class VerificationQueueAdmin(ModelAdminWithUrlActions):
@@ -1014,7 +1024,7 @@ class VerificationQueueAdmin(ModelAdminWithUrlActions):
if action == "vq_approve":
opts = type(obj.first().item)._meta
return redirect(
urlresolvers.reverse(
django.urls.reverse(
"admin:%s_%s_change" % (opts.app_label, opts.model_name),
args=(obj.first().item.id,),
)
@@ -1039,9 +1049,7 @@ class VerificationQueueAdmin(ModelAdminWithUrlActions):
actions = [vq_approve, vq_deny]
def view(self, obj):
return (u'<a href="{}">{}</a>').format(obj.item_admin_url, _("View"))
view.allow_tags = True
return mark_safe('<a href="{}">{}</a>'.format(obj.item_admin_url, _("View")))
def extra(self, obj):
if hasattr(obj.item, "org") and obj.item.org.id == settings.SUGGEST_ENTITY_ORG:
@@ -1161,41 +1169,39 @@ class UserAdmin(ModelAdminWithVQCtrl, UserAdmin):
return 0
def change_password(self, obj):
return (u'<a href="{}">{}</a>').format(
urlresolvers.reverse("admin:auth_user_password_change", args=(obj.id,)),
_("Change Password"),
return mark_safe(
'<a href="{}">{}</a>'.format(
django.urls.reverse("admin:auth_user_password_change", args=(obj.id,)),
_("Change Password"),
)
)
change_password.allow_tags = True
def view_permissions(self, obj):
url = urlresolvers.reverse(
url = django.urls.reverse(
"admin:%s_%s_change"
% (UserPermission._meta.app_label, UserPermission._meta.model_name),
args=(obj.id,),
)
return (u'<a href="{}">{}</a>').format(url, _("Edit Permissions"))
view_permissions.allow_tags = True
return mark_safe('<a href="{}">{}</a>'.format(url, _("Edit Permissions")))
def email_status(self, obj):
if obj.email_confirmed:
return (u'<span style="color:darkgreen">{}</span>').format(_("VERIFIED"))
return mark_safe(
'<span style="color:darkgreen">{}</span>'.format(_("VERIFIED"))
)
else:
return (u'<span style="color:darkred">{}</span>').format(_("UNVERIFIED"))
email_status.allow_tags = True
return mark_safe(
'<span style="color:darkred">{}</span>'.format(_("UNVERIFIED"))
)
def organizations(self, obj):
return (
return mark_safe(
loader.get_template("admin/user-organizations.html")
.render({"organizations": obj.organizations, "user": obj})
.replace("\n", "")
)
organizations.allow_tags = True
class UserPermission(User):
class Meta:
@@ -1241,14 +1247,12 @@ class UserPermissionAdmin(UserAdmin):
return form
def user(self, obj):
url = urlresolvers.reverse(
url = django.urls.reverse(
"admin:%s_%s_change" % (User._meta.app_label, User._meta.model_name),
args=(obj.id,),
)
return '<a href="%s">%s</a>' % (url, obj.username)
user.allow_tags = True
return mark_safe('<a href="%s">%s</a>' % (url, obj.username))
def clean_password(self):
pass
@@ -1293,7 +1297,7 @@ class DuplicateIPChangeList(ChangeList):
ip4s = {}
ip6s = {}
qs = super(DuplicateIPChangeList, self).get_queryset(request)
sort_keys = qs.query.order_by
sort_keys = list(qs.query.order_by)
if "pk" in sort_keys:
sort_keys.remove("pk")
if "-pk" in sort_keys:
@@ -1327,7 +1331,7 @@ class DuplicateIPChangeList(ChangeList):
ip6s[ip6].append(netixlan)
collisions = []
for ip, netixlans in ip4s.items():
for ip, netixlans in list(ip4s.items()):
if len(netixlans) > 1:
for netixlan in netixlans:
netixlan.ip_dupe = 4
@@ -1336,7 +1340,7 @@ class DuplicateIPChangeList(ChangeList):
netixlan.dt_sorter = int(netixlan.updated.strftime("%s"))
collisions.append(netixlan)
for ip, netixlans in ip6s.items():
for ip, netixlans in list(ip6s.items()):
if len(netixlans) > 1:
for netixlan in netixlans:
netixlan.ip_dupe = 6
@@ -1414,15 +1418,13 @@ class DuplicateIPAdmin(SoftDeleteAdmin):
ip.admin_order_field = "ip_sorter"
def net(self, obj):
return '<a href="/net/%d">%d</a>' % (obj.network_id, obj.network_id)
return mark_safe('<a href="/net/%d">%d</a>' % (obj.network_id, obj.network_id))
net.allow_tags = True
net.admin_order_field = "network_id"
def ix(self, obj):
return '<a href="/ix/%d">%d</a>' % (obj.ixlan.ix.id, obj.ixlan.ix.id)
return mark_safe('<a href="/ix/%d">%d</a>' % (obj.ixlan.ix.id, obj.ixlan.ix.id))
ix.allow_tags = True
ix.admin_order_field = "exchange"
def changelist_view(self, request, extra_context=None):
@@ -1544,7 +1546,7 @@ class CommandLineToolAdmin(admin.ModelAdmin):
action = "run"
tool.run(request.user, commit=False)
else:
print(tool.form_instance.errors)
print((tool.form_instance.errors))
form = tool.form_instance
else:
raise Exception(_("Only POST requests allowed."))