mirror of
https://github.com/peeringdb/peeringdb.git
synced 2024-05-11 05:55:09 +00:00
1647 lines
51 KiB
Python
1647 lines
51 KiB
Python
import os
|
|
import json
|
|
import datetime
|
|
import re
|
|
import uuid
|
|
|
|
from allauth.account.models import EmailAddress
|
|
from django.http import (JsonResponse, HttpResponse, HttpResponseRedirect,
|
|
HttpResponseNotFound, HttpResponseBadRequest,
|
|
HttpResponseForbidden)
|
|
from django.conf import settings as dj_settings
|
|
from django.shortcuts import render
|
|
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
|
|
from django.contrib.auth import authenticate, logout, login
|
|
from django.contrib.auth.decorators import login_required
|
|
from django.views.decorators.csrf import csrf_protect, ensure_csrf_cookie
|
|
from django.views.decorators.http import require_http_methods
|
|
from django.core.urlresolvers import resolve, Resolver404
|
|
from django.template import loader
|
|
from django.utils.crypto import constant_time_compare
|
|
from django_namespace_perms.util import (
|
|
get_perms,
|
|
has_perms,
|
|
load_perms,
|
|
)
|
|
from django_namespace_perms.constants import (
|
|
PERM_CRUD,
|
|
PERM_CREATE,
|
|
PERM_DELETE,
|
|
PERM_WRITE,
|
|
)
|
|
import requests
|
|
|
|
from oauth2_provider.decorators import protected_resource
|
|
from oauth2_provider.oauth2_backends import get_oauthlib_core
|
|
|
|
from peeringdb_server import settings
|
|
from peeringdb_server.search import search
|
|
from peeringdb_server.stats import stats as global_stats
|
|
from peeringdb_server.org_admin_views import load_all_user_permissions
|
|
from peeringdb_server.data_views import BOOL_CHOICE
|
|
from peeringdb_server.models import (
|
|
UserOrgAffiliationRequest, User, UserPasswordReset, Organization, Network,
|
|
NetworkFacility, NetworkIXLan, InternetExchange, InternetExchangeFacility,
|
|
Facility, Sponsorship, Partnership, PARTNERSHIP_LEVELS, REFTAG_MAP, UTC)
|
|
from peeringdb_server.forms import (UserCreationForm, PasswordResetForm,
|
|
PasswordChangeForm, AffiliateToOrgForm,
|
|
UsernameRetrieveForm, UserLocaleForm)
|
|
from peeringdb_server.serializers import (
|
|
OrganizationSerializer, NetworkSerializer, InternetExchangeSerializer,
|
|
FacilitySerializer)
|
|
from peeringdb_server.inet import RdapLookup, RdapException
|
|
from peeringdb_server.mail import mail_username_retrieve
|
|
from peeringdb_server.deskpro import ticket_queue_rdap_error
|
|
|
|
from ratelimit.decorators import ratelimit, is_ratelimited
|
|
|
|
RATELIMITS = dj_settings.RATELIMITS
|
|
|
|
from django.utils.translation import ugettext_lazy as _
|
|
# lazy init for translations
|
|
#_ = lambda s: s
|
|
|
|
BASE_ENV = {
|
|
'RECAPTCHA_PUBLIC_KEY': dj_settings.RECAPTCHA_PUBLIC_KEY,
|
|
'OAUTH_ENABLED': dj_settings.OAUTH_ENABLED,
|
|
'PEERINGDB_VERSION': settings.PEERINGDB_VERSION
|
|
}
|
|
|
|
|
|
def export_permissions(user, entity):
|
|
"""
|
|
returns dict of permission bools for the specified user and entity
|
|
|
|
to be used in template context
|
|
"""
|
|
|
|
if entity.status == "deleted":
|
|
return {}
|
|
|
|
perms = {
|
|
"can_write": has_perms(user, entity, PERM_WRITE),
|
|
"can_create": has_perms(user, entity, PERM_CREATE),
|
|
"can_delete": has_perms(user, entity, PERM_DELETE)
|
|
}
|
|
|
|
if entity.status == "pending":
|
|
perms["can_create"] = False
|
|
perms["can_delete"] = False
|
|
|
|
if perms["can_write"] or perms["can_create"] or perms["can_delete"]:
|
|
perms["can_edit"] = True
|
|
|
|
if hasattr(entity, "nsp_namespace_manage"):
|
|
perms["can_manage"] = has_perms(user, entity.nsp_namespace_manage,
|
|
PERM_CRUD)
|
|
else:
|
|
perms["can_manage"] = False
|
|
|
|
return perms
|
|
|
|
|
|
class DoNotRender(object):
|
|
"""
|
|
Instance of this class is sent when a component attribute does not exist,
|
|
this can then be type checked in the templates to remove non existant attribute
|
|
rows while still allowing attributes with nonetype values to be rendered
|
|
"""
|
|
|
|
def all(self):
|
|
return []
|
|
|
|
|
|
def make_env(**data):
|
|
env = {}
|
|
env.update(**BASE_ENV)
|
|
env.update(**{'global_stats': global_stats()})
|
|
env.update(**data)
|
|
return env
|
|
|
|
|
|
def get_client_ip(request):
|
|
x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR")
|
|
if x_forwarded_for:
|
|
ip = x_forwarded_for.split(",")[0]
|
|
else:
|
|
ip = request.META.get("REMOTE_ADDR")
|
|
return ip
|
|
|
|
|
|
def view_http_error_404(request):
|
|
template = loader.get_template('site/error_404.html')
|
|
return HttpResponseNotFound(template.render({}, request))
|
|
|
|
|
|
def view_http_error_403(request):
|
|
template = loader.get_template('site/error_403.html')
|
|
return HttpResponseForbidden(template.render({}, request))
|
|
|
|
|
|
def view_http_error_csrf(request, reason):
|
|
return JsonResponse({"non_field_errors": [reason]}, status=403)
|
|
|
|
|
|
@login_required
|
|
@ratelimit(key="ip", rate=RATELIMITS["view_request_ownership_GET"],
|
|
method="GET")
|
|
@ratelimit(key="ip", rate=RATELIMITS["view_request_ownership_POST"],
|
|
method="POST")
|
|
def view_request_ownership(request):
|
|
"""
|
|
Renders the form that allows users to request ownership
|
|
to an unclaimed organization
|
|
"""
|
|
|
|
was_limited = getattr(request, "limited", False)
|
|
|
|
if request.method in ["GET", "HEAD"]:
|
|
|
|
# check if reuqest was blocked by rate limiting
|
|
if was_limited:
|
|
return view_index(request, errors=[
|
|
_("Please wait a bit before requesting ownership again.")
|
|
])
|
|
|
|
org_id = request.GET.get("id")
|
|
try:
|
|
org = Organization.objects.get(id=org_id)
|
|
except Organization.DoesNotExist:
|
|
return view_index(request, errors=[_("Invalid organization")])
|
|
|
|
if org.owned:
|
|
return view_index(request, errors=[
|
|
_(u"Organization '%(org_name)s' is already under ownership") %
|
|
{
|
|
'org_name': org.name
|
|
}
|
|
])
|
|
|
|
template = loader.get_template("site/request-ownership.html")
|
|
return HttpResponse(template.render(make_env(org=org), request))
|
|
|
|
elif request.method == "POST":
|
|
|
|
org_id = request.POST.get("id")
|
|
|
|
# check if reuqest was blocked by rate limiting
|
|
if was_limited:
|
|
return JsonResponse({
|
|
"non_field_errors": [
|
|
_("Please wait a bit before requesting ownership again.")
|
|
]
|
|
}, status=400)
|
|
|
|
try:
|
|
org = Organization.objects.get(id=org_id)
|
|
except Organization.DoesNotExist:
|
|
return JsonResponse({
|
|
"non_field_errors": [_("Organization does not exist")]
|
|
}, status=400)
|
|
|
|
if org.owned:
|
|
return JsonResponse({
|
|
"non_field_errors": [
|
|
_("Organization '%(org_name)s' is already under ownership")
|
|
% {
|
|
'org_name': org.name
|
|
}
|
|
]
|
|
}, status=400)
|
|
|
|
if UserOrgAffiliationRequest.objects.filter(user=request.user,
|
|
org=org).exists():
|
|
return JsonResponse({
|
|
"non_field_errors": [
|
|
_("You already have an ownership request pending for this organization"
|
|
)
|
|
]
|
|
}, status=400)
|
|
|
|
uoar = UserOrgAffiliationRequest.objects.create(
|
|
user=request.user, org=org, status="pending")
|
|
return JsonResponse({"status": "ok", "ownership_status": uoar.status})
|
|
|
|
|
|
@csrf_protect
|
|
@ensure_csrf_cookie
|
|
@ratelimit(key="ip", method="POST",
|
|
rate=RATELIMITS["view_affiliate_to_org_POST"])
|
|
def view_affiliate_to_org(request):
|
|
"""
|
|
Allows the user to request affiliation with an organization through
|
|
an ASN they provide
|
|
"""
|
|
|
|
if not request.user.is_authenticated():
|
|
return view_login(request)
|
|
|
|
if request.method == "POST":
|
|
|
|
# check if request was blocked by rate limiting
|
|
was_limited = getattr(request, "limited", False)
|
|
if was_limited:
|
|
return JsonResponse({
|
|
"non_field_errors": [
|
|
_("Please wait a bit before requesting affiliation again.")
|
|
]
|
|
}, status=400)
|
|
|
|
form = AffiliateToOrgForm(request.POST)
|
|
if not form.is_valid():
|
|
return JsonResponse(form.errors, status=400)
|
|
|
|
if not form.cleaned_data.get("org") and not form.cleaned_data.get(
|
|
"asn") and not form.cleaned_data.get("org_name"):
|
|
return JsonResponse({
|
|
"asn": _("Either ASN or Organization required"),
|
|
"org": _("Either ASN or Organization required")
|
|
}, status=400)
|
|
|
|
asn = form.cleaned_data.get("asn")
|
|
|
|
# remove all deleted uoars for user
|
|
UserOrgAffiliationRequest.objects.filter(user=request.user,
|
|
status="denied").delete()
|
|
|
|
try:
|
|
|
|
uoar, created = UserOrgAffiliationRequest.objects.get_or_create(
|
|
user=request.user, asn=form.cleaned_data.get("asn"),
|
|
org_id=form.cleaned_data.get("org") or None,
|
|
org_name=form.cleaned_data.get("org_name") or None,
|
|
status="pending")
|
|
|
|
except RdapException as exc:
|
|
ticket_queue_rdap_error(request.user, asn, exc)
|
|
return JsonResponse({
|
|
"asn": _("RDAP Lookup Error: {}").format(exc)
|
|
}, status=400)
|
|
|
|
except MultipleObjectsReturned:
|
|
pass
|
|
|
|
return JsonResponse({"status": "ok"})
|
|
|
|
return view_verify(request)
|
|
|
|
|
|
@csrf_protect
|
|
@ensure_csrf_cookie
|
|
@ratelimit(key='ip', rate=RATELIMITS["resend_confirmation_mail"])
|
|
def resend_confirmation_mail(request):
|
|
was_limited = getattr(request, 'limited', False)
|
|
if was_limited:
|
|
return view_index(request, errors=[
|
|
_("Please wait a bit before trying to resend the confirmation email again"
|
|
)
|
|
])
|
|
|
|
if not request.user.is_authenticated():
|
|
return view_login(request)
|
|
|
|
request.user.send_email_confirmation(request=request)
|
|
return view_index(request,
|
|
errors=[_("We have resent your confirmation email")])
|
|
|
|
|
|
@csrf_protect
|
|
@ensure_csrf_cookie
|
|
def view_profile(request):
|
|
return view_verify(request)
|
|
|
|
|
|
@csrf_protect
|
|
@ensure_csrf_cookie
|
|
def view_set_user_locale(request):
|
|
|
|
if not request.user.is_authenticated():
|
|
return view_login(request)
|
|
|
|
if request.method in ["GET", "HEAD"]:
|
|
return view_verify(request)
|
|
elif request.method == "POST":
|
|
|
|
form = UserLocaleForm(request.POST)
|
|
if not form.is_valid():
|
|
return JsonResponse(form.errors, status=400)
|
|
|
|
loc = form.cleaned_data.get("locale")
|
|
request.user.set_locale(loc)
|
|
|
|
from django.utils import translation
|
|
translation.activate(loc)
|
|
request.session[translation.LANGUAGE_SESSION_KEY] = loc
|
|
|
|
return JsonResponse({"status": "ok"})
|
|
|
|
|
|
@protected_resource(scopes=['profile'])
|
|
def view_profile_v1(request):
|
|
# if not request.user.is_authenticated():
|
|
# return view_login(request)
|
|
oauth = get_oauthlib_core()
|
|
scope_email, _request = oauth.verify_request(request, scopes=["email"])
|
|
scope_networks, _request = oauth.verify_request(request,
|
|
scopes=["networks"])
|
|
|
|
json_params = {}
|
|
if "pretty" in request.GET:
|
|
json_params['indent'] = 2
|
|
|
|
user = request.user
|
|
data = dict(
|
|
id=request.user.id,
|
|
given_name=request.user.first_name,
|
|
family_name=request.user.last_name,
|
|
name=request.user.full_name,
|
|
verified_user=user.is_verified,
|
|
)
|
|
|
|
# only add email fields if email scope is present
|
|
if scope_email:
|
|
data.update(
|
|
dict(
|
|
email=request.user.email,
|
|
verified_email=user.email_confirmed,
|
|
))
|
|
|
|
# only add ddnetworks if networks scope is present
|
|
if scope_networks:
|
|
networks = []
|
|
load_perms(user)
|
|
for net in user.networks:
|
|
crud = get_perms(user._nsp_perms_struct,
|
|
net.nsp_namespace.split(".")).value
|
|
networks.append(
|
|
dict(
|
|
id=net.id,
|
|
name=net.name,
|
|
asn=net.asn,
|
|
perms=crud,
|
|
))
|
|
|
|
data['networks'] = networks
|
|
|
|
return JsonResponse(data, json_dumps_params=json_params)
|
|
|
|
|
|
@csrf_protect
|
|
@ensure_csrf_cookie
|
|
@ratelimit(key='ip', rate=RATELIMITS["view_verify_POST"], method="POST")
|
|
def view_verify(request):
|
|
|
|
if not request.user.is_authenticated():
|
|
return view_login(request)
|
|
|
|
if request.method in ["GET", "HEAD"]:
|
|
template = loader.get_template("site/verify.html")
|
|
env = BASE_ENV.copy()
|
|
env.update({
|
|
'affiliation_request':
|
|
request.user.affiliation_requests.order_by("-created").first(),
|
|
'affiliations': request.user.organizations,
|
|
'global_stats': global_stats(),
|
|
})
|
|
return HttpResponse(template.render(env, request))
|
|
elif request.method == "POST":
|
|
|
|
# change email address
|
|
|
|
password = request.POST.get("password")
|
|
|
|
was_limited = getattr(request, "limited", False)
|
|
|
|
if was_limited:
|
|
return JsonResponse({
|
|
"non_field_errors": [
|
|
_("Please wait a bit before requesting another email change"
|
|
)
|
|
]
|
|
}, status=400)
|
|
|
|
if not request.user.has_oauth:
|
|
if not authenticate(username=request.user.username,
|
|
password=password):
|
|
return JsonResponse({"status": "auth"}, status=401)
|
|
|
|
if EmailAddress.objects.filter(user=request.user).exists():
|
|
EmailAddress.objects.filter(user=request.user).delete()
|
|
|
|
request.user.email = request.POST.get("email")
|
|
|
|
if User.objects.filter(email=request.user.email).exclude(
|
|
id=request.user.id).exists():
|
|
return JsonResponse({
|
|
"email": _("E-mail already exists in our system")
|
|
}, status=400)
|
|
request.user.clean()
|
|
request.user.save()
|
|
|
|
request.user.send_email_confirmation(request=request)
|
|
|
|
return JsonResponse({"status": "ok"})
|
|
|
|
|
|
@csrf_protect
|
|
@ensure_csrf_cookie
|
|
def view_password_change(request):
|
|
|
|
if not request.user.is_authenticated():
|
|
return view_login(request)
|
|
|
|
if request.method in ["GET", "HEAD"]:
|
|
return view_verify(request)
|
|
elif request.method == "POST":
|
|
|
|
password_c = request.POST.get("password_c")
|
|
|
|
if not request.user.has_oauth:
|
|
if not authenticate(username=request.user.username,
|
|
password=password_c):
|
|
return JsonResponse({
|
|
"status": "auth",
|
|
"password_c": _("Wrong password")
|
|
}, status=400)
|
|
else:
|
|
return JsonResponse({"status": "auth"}, status=401)
|
|
|
|
form = PasswordChangeForm(request.POST)
|
|
if not form.is_valid():
|
|
return JsonResponse(form.errors, status=400)
|
|
|
|
request.user.set_password(form.cleaned_data.get("password"))
|
|
request.user.save()
|
|
|
|
return JsonResponse({"status": "ok"})
|
|
|
|
|
|
@ensure_csrf_cookie
|
|
@require_http_methods(["GET"])
|
|
def view_username_retrieve(request):
|
|
"""
|
|
username retrieval view
|
|
"""
|
|
env = BASE_ENV.copy()
|
|
env.update({
|
|
'global_stats': global_stats(),
|
|
})
|
|
return render(request, "site/username-retrieve.html", env)
|
|
|
|
|
|
@csrf_protect
|
|
@ensure_csrf_cookie
|
|
@require_http_methods(["POST"])
|
|
@ratelimit(key='ip', rate=RATELIMITS["view_username_retrieve_initiate"])
|
|
def view_username_retrieve_initiate(request):
|
|
"""
|
|
username retrieval initiate view
|
|
"""
|
|
|
|
was_limited = getattr(request, "limited", False)
|
|
if was_limited:
|
|
return JsonResponse({
|
|
"non_field_errors": [
|
|
_("Please wait a bit before requesting your usernames again.")
|
|
]
|
|
}, status=400)
|
|
|
|
# clean form and get email address
|
|
form = UsernameRetrieveForm(request.POST)
|
|
if not form.is_valid():
|
|
return JsonResponse(form.errors, status=400)
|
|
|
|
email = form.cleaned_data.get("email")
|
|
|
|
# generate secret and store in user's django sessions
|
|
secret = str(uuid.uuid4())
|
|
request.session["username_retrieve_secret"] = secret
|
|
request.session["username_retrieve_email"] = email
|
|
|
|
# send email
|
|
if User.objects.filter(email=email).exists():
|
|
mail_username_retrieve(email, secret)
|
|
|
|
return JsonResponse({"status": "ok"})
|
|
|
|
|
|
@ensure_csrf_cookie
|
|
@require_http_methods(["GET"])
|
|
def view_username_retrieve_complete(request):
|
|
"""
|
|
username retrieval completion view
|
|
|
|
show the list of usernames associated to an email if
|
|
the correct secret is provided
|
|
"""
|
|
|
|
secret = request.GET.get("secret")
|
|
secret_expected = request.session.get("username_retrieve_secret")
|
|
email = request.session.get("username_retrieve_email")
|
|
env = BASE_ENV.copy()
|
|
env.update({
|
|
"secret": secret,
|
|
"secret_expected": secret_expected,
|
|
"users": User.objects.filter(email=email),
|
|
"email": email
|
|
})
|
|
|
|
if secret_expected and constant_time_compare(secret, secret_expected):
|
|
# invalidate the username retrieve session
|
|
del request.session["username_retrieve_email"]
|
|
del request.session["username_retrieve_secret"]
|
|
request.session.modified = True
|
|
|
|
return render(request, "site/username-retrieve-complete.html", env)
|
|
|
|
|
|
@csrf_protect
|
|
@ensure_csrf_cookie
|
|
def view_password_reset(request):
|
|
"""
|
|
password reset initiation view
|
|
"""
|
|
|
|
if request.method in ["GET", "HEAD"]:
|
|
env = BASE_ENV.copy()
|
|
env.update({
|
|
'global_stats': global_stats(),
|
|
})
|
|
|
|
env["token"] = token = request.GET.get("token")
|
|
env["target"] = target = request.GET.get("target")
|
|
|
|
if token and target:
|
|
pr = UserPasswordReset.objects.filter(user_id=target).first()
|
|
env["pr"] = pr
|
|
|
|
if pr and pr.match(token) and pr.is_valid():
|
|
env["username"] = pr.user.username
|
|
env["token_valid"] = True
|
|
|
|
template = loader.get_template("site/password-reset.html")
|
|
|
|
return HttpResponse(template.render(env, request))
|
|
|
|
elif request.method == "POST":
|
|
|
|
token = request.POST.get("token")
|
|
target = request.POST.get("target")
|
|
if token and target:
|
|
form = PasswordChangeForm(request.POST)
|
|
if not form.is_valid():
|
|
return JsonResponse(form.errors, status=400)
|
|
|
|
user = User.objects.filter(id=target).first()
|
|
|
|
err_invalid_token_msg = _("Invalid Security Token")
|
|
err_expired_msg = ('{} <a href="/reset-password">{}</a>').format(
|
|
_("Password Reset Process has expired, please"),
|
|
_("initiate again"))
|
|
|
|
if user:
|
|
try:
|
|
if not user.password_reset.match(token):
|
|
return JsonResponse({
|
|
"non_field_errors": [err_invalid_token_msg]
|
|
}, status=400)
|
|
|
|
if not user.password_reset.is_valid():
|
|
return JsonResponse({
|
|
"non_field_errors": [err_expired_msg]
|
|
}, status=400)
|
|
|
|
except UserPasswordReset.DoesNotExist:
|
|
return JsonResponse({
|
|
"non_field_errors": [err_expired_msg]
|
|
}, status=400)
|
|
|
|
user.password_reset_complete(token,
|
|
form.cleaned_data.get("password"))
|
|
|
|
else:
|
|
return JsonResponse({
|
|
"non_field_errors": [err_expired_msg]
|
|
}, status=400)
|
|
|
|
else:
|
|
form = PasswordResetForm(request.POST)
|
|
|
|
if not form.is_valid():
|
|
return JsonResponse(form.errors, status=400)
|
|
|
|
user = User.objects.filter(
|
|
email=form.cleaned_data["email"]).first()
|
|
if user:
|
|
user.password_reset_initiate()
|
|
return JsonResponse({"status": "ok"})
|
|
|
|
|
|
@csrf_protect
|
|
@ensure_csrf_cookie
|
|
def view_registration(request):
|
|
"""
|
|
user registration page view
|
|
"""
|
|
if request.user.is_authenticated():
|
|
return view_index(request, errors=[
|
|
_('Please log out of your current session before trying to register. Notice, multiple accounts are no longer needed.'
|
|
)
|
|
])
|
|
|
|
if request.method in ["GET", "HEAD"]:
|
|
template = loader.get_template("site/register.html")
|
|
env = BASE_ENV.copy()
|
|
env.update({
|
|
'global_stats': global_stats(),
|
|
})
|
|
return HttpResponse(template.render(env, request))
|
|
|
|
elif request.method == "POST":
|
|
form = UserCreationForm(request.POST)
|
|
|
|
if not form.is_valid():
|
|
return JsonResponse(form.errors, status=400)
|
|
|
|
cpt = request.POST.get("recaptcha", "")
|
|
cpt_params = {
|
|
"secret": dj_settings.RECAPTCHA_SECRET_KEY,
|
|
"response": cpt,
|
|
"remoteip": get_client_ip(request)
|
|
}
|
|
cpt_response = requests.post(dj_settings.RECAPTCHA_VERIFY_URL,
|
|
params=cpt_params).json()
|
|
if not cpt_response.get("success"):
|
|
return JsonResponse({
|
|
"non_field_errors": [_("reCAPTCHA invalid")]
|
|
}, status=400)
|
|
|
|
email = form.cleaned_data["email"]
|
|
if EmailAddress.objects.filter(email=email).count() > 0:
|
|
return JsonResponse({
|
|
"email": _("This email address has already been used")
|
|
}, status=400)
|
|
|
|
# require min password length
|
|
# FIXME: impl password strength validation
|
|
if len(form.cleaned_data["password1"]) < 10:
|
|
return JsonResponse({
|
|
"password1": _("Needs to be at least 10 characters long")
|
|
}, status=400)
|
|
|
|
# create the user
|
|
user = form.save()
|
|
|
|
user.set_unverified()
|
|
|
|
# log the user in
|
|
login(request,
|
|
authenticate(username=request.POST["username"],
|
|
password=request.POST["password1"]))
|
|
|
|
user.send_email_confirmation(signup=True, request=request)
|
|
|
|
return JsonResponse({"status": "ok"})
|
|
|
|
|
|
@ensure_csrf_cookie
|
|
def view_login(request, errors=None):
|
|
"""
|
|
login page view
|
|
"""
|
|
if not errors:
|
|
errors = []
|
|
|
|
if request.user.is_authenticated():
|
|
return view_index(request, errors=[_('Already logged in')])
|
|
|
|
template = loader.get_template('site/login.html')
|
|
|
|
env = BASE_ENV.copy()
|
|
env.update({'errors': errors})
|
|
return HttpResponse(template.render(env, request))
|
|
|
|
|
|
@ensure_csrf_cookie
|
|
def view_index(request, errors=None):
|
|
"""
|
|
landing page view
|
|
"""
|
|
if not errors:
|
|
errors = []
|
|
|
|
template = loader.get_template('site/index.html')
|
|
|
|
recent = {
|
|
"net": Network.handleref.filter(status="ok").order_by("-updated")[:5],
|
|
"fac": Facility.handleref.filter(status="ok").order_by("-updated")[:5],
|
|
"ix": InternetExchange.handleref.filter(status="ok")
|
|
.order_by("-updated")[:5]
|
|
}
|
|
|
|
env = BASE_ENV.copy()
|
|
env.update({
|
|
'errors': errors,
|
|
'global_stats': global_stats(),
|
|
'recent': recent
|
|
})
|
|
return HttpResponse(template.render(env, request))
|
|
|
|
|
|
def view_component(request, component, data, title, perms=None, instance=None,
|
|
**kwargs):
|
|
"""
|
|
Generic component view
|
|
"""
|
|
if not perms:
|
|
perms = {}
|
|
|
|
template = loader.get_template('site/view.html')
|
|
|
|
env = BASE_ENV.copy()
|
|
env.update({
|
|
'data': data,
|
|
'permissions': perms,
|
|
'title': title,
|
|
'component': component,
|
|
'instance': instance,
|
|
'ref_tag': instance._handleref.tag,
|
|
'global_stats': global_stats(),
|
|
'asset_template_name': 'site/view_%s_assets.html' % component,
|
|
'tools_template_name': 'site/view_%s_tools.html' % component,
|
|
'side_template_name': 'site/view_%s_side.html' % component,
|
|
'bottom_template_name': 'site/view_%s_bottom.html' % component
|
|
})
|
|
env.update(**kwargs)
|
|
return HttpResponse(template.render(env, request))
|
|
|
|
|
|
@ensure_csrf_cookie
|
|
def view_organization(request, id):
|
|
"""
|
|
View organization data for org specified by id
|
|
"""
|
|
|
|
try:
|
|
org = OrganizationSerializer.prefetch_related(
|
|
Organization.objects, request, depth=2).get(
|
|
id=id, status__in=["ok", "pending"])
|
|
except ObjectDoesNotExist:
|
|
return view_http_error_404(request)
|
|
|
|
data = OrganizationSerializer(org, context={"user": request.user}).data
|
|
|
|
if not data:
|
|
return view_http_error_403(request)
|
|
|
|
perms = export_permissions(request.user, org)
|
|
|
|
tags = ["fac", "net", "ix"]
|
|
for tag in tags:
|
|
model = REFTAG_MAP.get(tag)
|
|
perms["can_create_%s" % tag] = has_perms(request.user,
|
|
model.nsp_namespace_from_id(
|
|
org.id, "create"),
|
|
PERM_CREATE)
|
|
perms["can_delete_%s" % tag] = has_perms(request.user,
|
|
model.nsp_namespace_from_id(
|
|
org.id, "_").strip("_"),
|
|
PERM_DELETE)
|
|
|
|
# if the organization being viewed is the one used
|
|
# to store suggested entities, we dont want to show the editorial
|
|
# tools
|
|
if org.id == dj_settings.SUGGEST_ENTITY_ORG:
|
|
perms["can_create"] = False
|
|
perms["can_manage"] = False
|
|
for tag in tags:
|
|
perms["can_create_%s" % tag] = False
|
|
perms["can_delete_%s" % tag] = False
|
|
|
|
# if user has writing perms to entity, we want to load sub entities
|
|
# that have status pending so we dont use the ones kicked back
|
|
# by the serializer
|
|
if perms.get("can_delete_ix") or perms.get("can_create_ix"):
|
|
exchanges = org.ix_set.filter(status__in=["ok", "pending"])
|
|
else:
|
|
exchanges = data["ix_set"]
|
|
|
|
if perms.get("can_delete_fac") or perms.get("can_create_fac"):
|
|
facilities = org.fac_set.filter(status__in=["ok", "pending"])
|
|
else:
|
|
facilities = data["fac_set"]
|
|
|
|
if perms.get("can_delete_net") or perms.get("can_create_net"):
|
|
networks = org.net_set.filter(status__in=["ok", "pending"])
|
|
else:
|
|
networks = data["net_set"]
|
|
|
|
dismiss = DoNotRender()
|
|
|
|
data = {
|
|
"title": data.get("name", dismiss),
|
|
"exchanges": exchanges,
|
|
"networks": networks,
|
|
"facilities": facilities,
|
|
"fields": [{
|
|
"name": "website",
|
|
"type": "url",
|
|
"notify_incomplete": True,
|
|
"value": data.get("website", dismiss),
|
|
"label": _("Website")
|
|
}, {
|
|
"name": "address1",
|
|
"label": _("Address 1"),
|
|
"notify_incomplete": True,
|
|
"value": data.get("address1", dismiss)
|
|
}, {
|
|
"name": "address2",
|
|
"label": _("Address 2"),
|
|
"value": data.get("address2", dismiss)
|
|
}, {
|
|
"name": "location",
|
|
"label": _("Location"),
|
|
"type": "location",
|
|
"notify_incomplete": True,
|
|
"value": data
|
|
}, {
|
|
"name": "country",
|
|
"type": "list",
|
|
"data": "countries_b",
|
|
"label": _("Country Code"),
|
|
"notify_incomplete": True,
|
|
"value": data.get("country", dismiss)
|
|
}, {
|
|
"name": "notes",
|
|
"label": _("Notes"),
|
|
"help_text": _("Markdown enabled"),
|
|
"type": "fmt-text",
|
|
"value": data.get("notes", dismiss)
|
|
}]
|
|
}
|
|
|
|
users = {}
|
|
if perms.get("can_manage"):
|
|
users.update(
|
|
dict([(user.id, user)
|
|
for user in org.admin_usergroup.user_set.all()]))
|
|
users.update(
|
|
dict([(user.id, user) for user in org.usergroup.user_set.all()]))
|
|
users = sorted(users.values(), key=lambda x: x.full_name)
|
|
|
|
# if user has rights to create sub entties or manage users, allow them
|
|
# to view the tools
|
|
if perms.get("can_manage") or perms.get("can_create"):
|
|
perms["can_use_tools"] = True
|
|
|
|
active_tab = None
|
|
tab_init = {}
|
|
for tag in tags:
|
|
tab_init[tag] = "inactive"
|
|
if perms.get("can_create_%s" % tag):
|
|
perms["can_use_tools"] = True
|
|
if not active_tab:
|
|
tab_init[tag] = "active"
|
|
active_tab = tag
|
|
if perms.get("can_delete_%s" % tag):
|
|
perms["can_edit"] = True
|
|
|
|
if perms.get("can_manage") and org.pending_affiliations.count() > 0:
|
|
tab_init = {"users": "active"}
|
|
|
|
return view_component(
|
|
request, "organization", data, "Organization", tab_init=tab_init,
|
|
users=users, user_perms=load_all_user_permissions(org), instance=org,
|
|
perms=perms)
|
|
|
|
|
|
@ensure_csrf_cookie
|
|
def view_facility(request, id):
|
|
"""
|
|
View facility data for facility specified by id
|
|
"""
|
|
|
|
try:
|
|
facility = Facility.objects.get(id=id, status__in=["ok", "pending"])
|
|
except ObjectDoesNotExist:
|
|
return view_http_error_404(request)
|
|
|
|
data = FacilitySerializer(facility, context={"user": request.user}).data
|
|
|
|
if not data:
|
|
return view_http_error_403(request)
|
|
|
|
perms = export_permissions(request.user, facility)
|
|
|
|
org = OrganizationSerializer(facility.org, context={
|
|
"user": request.user
|
|
}).data
|
|
|
|
exchanges = InternetExchangeFacility.handleref.undeleted().filter(
|
|
facility=facility).select_related("ix").order_by("ix__name").all()
|
|
peers = NetworkFacility.handleref.undeleted().filter(
|
|
facility=facility).select_related("network").order_by("network__name")
|
|
|
|
dismiss = DoNotRender()
|
|
|
|
data = {
|
|
"title": data.get("name", dismiss),
|
|
"exchanges": exchanges,
|
|
"peers": peers,
|
|
"fields": [{
|
|
"name": "org",
|
|
"label": _("Organization"),
|
|
"value": org.get("name", dismiss),
|
|
"type": "entity_link",
|
|
"link": "/%s/%d" % (Organization._handleref.tag, org.get("id"))
|
|
}, {
|
|
"name": "website",
|
|
"type": "url",
|
|
"value": data.get("website", dismiss),
|
|
"label": _("Website")
|
|
}, {
|
|
"name": "address1",
|
|
"label": _("Address 1"),
|
|
"value": data.get("address1", dismiss)
|
|
}, {
|
|
"name": "address2",
|
|
"label": _("Address 2"),
|
|
"value": data.get("address2", dismiss)
|
|
}, {
|
|
"name": "location",
|
|
"label": _("Location"),
|
|
"type": "location",
|
|
"value": data
|
|
}, {
|
|
"name": "country",
|
|
"type": "list",
|
|
"data": "countries_b",
|
|
"label": _("Country Code"),
|
|
"value": data.get("country", dismiss)
|
|
}, {
|
|
"name": "geocode",
|
|
"label": _("Geocode"),
|
|
"type": "geocode",
|
|
"value": data
|
|
}, {
|
|
"name": "clli",
|
|
"label": _("CLLI Code"),
|
|
"value": data.get("clli", dismiss)
|
|
}, {
|
|
"name": "npanxx",
|
|
"label": _("NPA-NXX"),
|
|
"value": data.get("npanxx", dismiss)
|
|
}, {
|
|
"name": "notes",
|
|
"label": _("Notes"),
|
|
"help_text": _("Markdown enabled"),
|
|
"type": "fmt-text",
|
|
"value": data.get("notes", dismiss)
|
|
}]
|
|
}
|
|
|
|
return view_component(request, "facility", data, "Facility", perms=perms,
|
|
instance=facility)
|
|
|
|
|
|
@ensure_csrf_cookie
|
|
def view_exchange(request, id):
|
|
"""
|
|
View exchange data for exchange specified by id
|
|
"""
|
|
|
|
try:
|
|
exchange = InternetExchange.objects.get(id=id,
|
|
status__in=["ok", "pending"])
|
|
except ObjectDoesNotExist:
|
|
return view_http_error_404(request)
|
|
|
|
data = InternetExchangeSerializer(exchange, context={
|
|
"user": request.user
|
|
}).data
|
|
|
|
# find out if user can write to object
|
|
perms = export_permissions(request.user, exchange)
|
|
|
|
if not data:
|
|
return view_http_error_403(request)
|
|
networks = NetworkIXLan.handleref.undeleted().select_related(
|
|
'network',
|
|
'ixlan').order_by('network__name').filter(ixlan__ix=exchange)
|
|
dismiss = DoNotRender()
|
|
|
|
facilities = InternetExchangeFacility.handleref.undeleted().select_related(
|
|
'ix', 'facility').filter(ix=exchange).order_by("facility__name")
|
|
|
|
org = data.get("org")
|
|
|
|
data = {
|
|
"id": exchange.id,
|
|
"title": data.get("name", dismiss),
|
|
"facilities": facilities,
|
|
"networks": networks,
|
|
"ixlans": exchange.ixlan_set_active_or_pending,
|
|
"fields": [{
|
|
"name": "org",
|
|
"label": _("Organization"),
|
|
"value": org.get("name", dismiss),
|
|
"type": "entity_link",
|
|
"link": "/%s/%d" % (Organization._handleref.tag, org.get("id"))
|
|
}, {
|
|
"name": "name_long",
|
|
"label": _("Long Name"),
|
|
"value": data.get("name_long", dismiss)
|
|
}, {
|
|
"name": "city",
|
|
"label": _("City"),
|
|
"value": data.get("city", dismiss)
|
|
}, {
|
|
"name": "country",
|
|
"type": "list",
|
|
"data": "countries_b",
|
|
"label": _("Country"),
|
|
"value": data.get("country", dismiss)
|
|
}, {
|
|
"name": "region_continent",
|
|
"type": "list",
|
|
"data": "enum/regions",
|
|
"label": _("Continental Region"),
|
|
"value": data.get("region_continent", dismiss)
|
|
}, {
|
|
"name": "media",
|
|
"type": "list",
|
|
"data": "enum/media",
|
|
"label": _("Media Type"),
|
|
"value": data.get("media", dismiss)
|
|
}, {
|
|
"type": "flags",
|
|
"label": _("Protocols Supported"),
|
|
"value": [{
|
|
"name": "proto_unicast",
|
|
"label": _("Unicast IPv4"),
|
|
"value": int(data.get("proto_unicast", False))
|
|
}, {
|
|
"name": "proto_multicast",
|
|
"label": _("Multicast"),
|
|
"value": int(data.get("proto_multicast", False))
|
|
}, {
|
|
"name": "proto_ipv6",
|
|
"label": _("IPv6"),
|
|
"value": int(data.get("proto_ipv6", False))
|
|
}]
|
|
}, {
|
|
"name": "notes",
|
|
"label": _("Notes"),
|
|
"help_text": _("Markdown enabled"),
|
|
"type": "fmt-text",
|
|
"value": data.get("notes", dismiss)
|
|
}, {
|
|
"type": "sub",
|
|
"label": _("Contact Information")
|
|
}, {
|
|
"type": "url",
|
|
"name": "website",
|
|
"label": _("Company Website"),
|
|
"value": data.get("website", dismiss)
|
|
}, {
|
|
"type": "url",
|
|
"name": "url_stats",
|
|
"label": _("Traffic Stats Website"),
|
|
"value": data.get("url_stats", dismiss)
|
|
}, {
|
|
"type": "email",
|
|
"name": "tech_email",
|
|
"label": _("Technical Email"),
|
|
"value": data.get("tech_email", dismiss)
|
|
}, {
|
|
"type": "string",
|
|
"name": "tech_phone",
|
|
"label": _("Technical Phone"),
|
|
"value": data.get("tech_phone", dismiss)
|
|
}, {
|
|
"type": "email",
|
|
"name": "policy_email",
|
|
"label": _("Policy Email"),
|
|
"value": data.get("policy_email", dismiss)
|
|
}, {
|
|
"type": "string",
|
|
"name": "policy_phone",
|
|
"label": _("Policy Phone"),
|
|
"value": data.get("policy_phone", dismiss)
|
|
}]
|
|
}
|
|
|
|
ixlan_num = data["ixlans"].count()
|
|
|
|
if ixlan_num < 2 and not perms.get("can_edit"):
|
|
# if there is less than one LAN connected to this ix
|
|
# we want to render a simplified view to read-only
|
|
# viewers
|
|
|
|
data["lan_simple_view"] = True
|
|
|
|
if ixlan_num == 1:
|
|
|
|
ixlan = data["ixlans"].first()
|
|
|
|
data["fields"].extend([{
|
|
"type": "sub",
|
|
"label": _("LAN")
|
|
}, {
|
|
"type": "number",
|
|
"name": "mtu",
|
|
"label": _("MTU"),
|
|
"value": ixlan.mtu or ""
|
|
}, {
|
|
"type": "bool",
|
|
"name": "dot1q_support",
|
|
"label": _("DOT1Q"),
|
|
"value": ixlan.dot1q_support
|
|
}])
|
|
|
|
data["fields"].extend([{
|
|
"type": "string",
|
|
"name": "prefix_%d" % prefix.id,
|
|
"label": _(prefix.protocol),
|
|
"value": prefix.prefix
|
|
} for prefix in ixlan.ixpfx_set_active])
|
|
|
|
return view_component(request, "exchange", data, "Exchange", perms=perms,
|
|
instance=exchange)
|
|
|
|
|
|
@ensure_csrf_cookie
|
|
def view_network_by_query(request):
|
|
if "asn" in request.GET:
|
|
try:
|
|
return view_network_by_asn(request, request.GET.get("asn"))
|
|
except ValueError:
|
|
return view_http_error_404(request)
|
|
else:
|
|
return view_http_error_404(request)
|
|
|
|
|
|
@ensure_csrf_cookie
|
|
def view_network_by_asn(request, asn):
|
|
try:
|
|
network = Network.objects.get(asn=int(asn))
|
|
# FIXME: should be able to just pass existing network object here to avoid
|
|
# having to query again
|
|
return view_network(request, network.id)
|
|
except ObjectDoesNotExist:
|
|
return view_http_error_404(request)
|
|
|
|
|
|
@ensure_csrf_cookie
|
|
def view_network(request, id):
|
|
"""
|
|
View network data for network specified by id
|
|
"""
|
|
|
|
try:
|
|
network = NetworkSerializer.prefetch_related(
|
|
Network.objects, request, depth=2).get(
|
|
id=id, status__in=["ok", "pending"])
|
|
except ObjectDoesNotExist:
|
|
return view_http_error_404(request)
|
|
|
|
network_d = NetworkSerializer(network, context={"user": request.user}).data
|
|
|
|
if not network_d:
|
|
return view_http_error_403(request)
|
|
|
|
perms = export_permissions(request.user, network)
|
|
|
|
facilities = NetworkFacility.handleref.undeleted().select_related(
|
|
"facility").filter(network=network).order_by("facility__name")
|
|
|
|
exchanges = NetworkIXLan.handleref.undeleted().select_related(
|
|
"ixlan", "ixlan__ix",
|
|
"network").filter(network=network).order_by("ixlan__ix__name")
|
|
|
|
# This will be passed as default value for keys that dont exist - causing
|
|
# them not to be rendered in the template - also it is fairly
|
|
# safe to assume that no existing keys have been dropped because permission
|
|
# requirements to view them were not met.
|
|
dismiss = DoNotRender()
|
|
|
|
org = network_d.get("org")
|
|
|
|
data = {
|
|
"title": network_d.get("name", dismiss),
|
|
"facilities": facilities,
|
|
"exchanges": exchanges,
|
|
"fields": [{
|
|
"name": "org",
|
|
"label": _("Organization"),
|
|
"value": org.get("name", dismiss),
|
|
"type": "entity_link",
|
|
"link": "/%s/%d" % (Organization._handleref.tag, org.get("id"))
|
|
}, {
|
|
"name": "aka",
|
|
"label": _("Also Known As"),
|
|
"notify_incomplete": True,
|
|
"value": network_d.get("aka", dismiss)
|
|
}, {
|
|
"name": "website",
|
|
"label": _("Company Website"),
|
|
"type": "url",
|
|
"notify_incomplete": True,
|
|
"value": network_d.get("website", dismiss)
|
|
}, {
|
|
"name": "asn",
|
|
"label": _("Primary ASN"),
|
|
"notify_incomplete": True,
|
|
"value": network_d.get("asn", dismiss)
|
|
}, {
|
|
"name": "irr_as_set",
|
|
"label": _("IRR Record"),
|
|
"notify_incomplete": True,
|
|
"value": network_d.get("irr_as_set", dismiss)
|
|
}, {
|
|
"name": "route_server",
|
|
"type": "url",
|
|
"label": _("Route Server URL"),
|
|
"notify_incomplete": True,
|
|
"value": network_d.get("route_server", dismiss)
|
|
}, {
|
|
"name": "looking_glass",
|
|
"type": "url",
|
|
"label": _("Looking Glass URL"),
|
|
"notify_incomplete": True,
|
|
"value": network_d.get("looking_glass", dismiss)
|
|
}, {
|
|
"name": "info_type",
|
|
"type": "list",
|
|
"data": "enum/net_types",
|
|
"blank": _("Not Disclosed"),
|
|
"label": _("Network Type"),
|
|
"notify_incomplete": True,
|
|
"value": network_d.get("info_type", dismiss)
|
|
}, {
|
|
"name": "info_prefixes4",
|
|
"label": _("IPv4 Prefixes"),
|
|
"type": "number",
|
|
"notify_incomplete": True,
|
|
"value": int(network_d.get("info_prefixes4") or 0)
|
|
}, {
|
|
"name": "info_prefixes6",
|
|
"label": _("IPv6 Prefixes"),
|
|
"type": "number",
|
|
"notify_incomplete": True,
|
|
"value": int(network_d.get("info_prefixes6") or 0)
|
|
}, {
|
|
"name": "info_traffic",
|
|
"type": "list",
|
|
"data": "enum/traffic",
|
|
"blank": _("Not Disclosed"),
|
|
"label": _("Traffic Levels"),
|
|
"value": network_d.get("info_traffic", dismiss)
|
|
}, {
|
|
"name": "info_ratio",
|
|
"type": "list",
|
|
"data": "enum/ratios",
|
|
"label": _("Traffic Ratios"),
|
|
"blank": _("Not Disclosed"),
|
|
"value": network_d.get("info_ratio", dismiss)
|
|
}, {
|
|
"name": "info_scope",
|
|
"type": "list",
|
|
"data": "enum/scopes",
|
|
"blank": _("Not Disclosed"),
|
|
"label": _("Geographic Scope"),
|
|
"value": network_d.get("info_scope", dismiss)
|
|
}, {
|
|
"type": "flags",
|
|
"label": _("Protocols Supported"),
|
|
"value": [{
|
|
"name": "info_unicast",
|
|
"label": _("Unicast IPv4"),
|
|
"value": network_d.get("info_unicast", False)
|
|
}, {
|
|
"name": "info_multicast",
|
|
"label": _("Multicast"),
|
|
"value": network_d.get("info_multicast", False)
|
|
}, {
|
|
"name": "info_ipv6",
|
|
"label": _("IPv6"),
|
|
"value": network_d.get("info_ipv6", False)
|
|
}]
|
|
}, {
|
|
"readonly": True,
|
|
"name": "updated",
|
|
"label": _("Last Updated"),
|
|
"value": network_d.get("updated", dismiss)
|
|
}, {
|
|
"name": "notes",
|
|
"label": _("Notes"),
|
|
"help_text": _("Markdown enabled"),
|
|
"type": "fmt-text",
|
|
"value": network_d.get("notes", dismiss)
|
|
}, {
|
|
"type": "sub",
|
|
"admin": True,
|
|
"label": _("PeeringDB Configuration")
|
|
}, {
|
|
"type": "flags",
|
|
"admin": True,
|
|
"label": _("Allow IXP Update"),
|
|
"help_text": _(
|
|
"If enabled, an ixp may manage this network's entry in their peering list"
|
|
),
|
|
"value": [{
|
|
"name": "allow_ixp_update",
|
|
"label": "",
|
|
"value": network.allow_ixp_update
|
|
}]
|
|
}, {
|
|
"type": "sub",
|
|
"label": _("Peering Policy Information")
|
|
}, {
|
|
"name": "policy_url",
|
|
"label": _("Peering Policy"),
|
|
"value": network_d.get("policy_url", dismiss),
|
|
"notify_incomplete": True,
|
|
"type": "url"
|
|
}, {
|
|
"name": "policy_general",
|
|
"type": "list",
|
|
"data": "enum/policy_general",
|
|
"label": _("General Policy"),
|
|
"value": network_d.get("policy_general", dismiss)
|
|
}, {
|
|
"name": "policy_locations",
|
|
"type": "list",
|
|
"data": "enum/policy_locations",
|
|
"label": _("Multiple Locations"),
|
|
"value": network_d.get("policy_locations", dismiss)
|
|
}, {
|
|
"name": "policy_ratio",
|
|
"type": "list",
|
|
"data": "enum/bool_choice_str",
|
|
"label": _("Ratio Requirement"),
|
|
"value": network_d.get("policy_ratio", dismiss),
|
|
"value_label": dict(BOOL_CHOICE).get(
|
|
network_d.get("policy_ratio"))
|
|
}, {
|
|
"name": "policy_contracts",
|
|
"type": "list",
|
|
"data": "enum/policy_contracts",
|
|
"label": _("Contract Requirement"),
|
|
"value": network_d.get("policy_contracts", dismiss)
|
|
}]
|
|
}
|
|
|
|
# Add POC data to dataset
|
|
data["poc_set"] = network_d.get("poc_set")
|
|
|
|
if not request.user.is_authenticated() or not request.user.is_verified:
|
|
cnt = network.poc_set.filter(status="ok", visible="Users").count()
|
|
data["poc_hidden"] = (cnt > 0)
|
|
else:
|
|
data["poc_hidden"] = False
|
|
|
|
return view_component(request, "network", data, "Network", perms=perms,
|
|
instance=network)
|
|
|
|
|
|
def view_suggest(request, reftag):
|
|
if reftag not in ["net", "ix", "fac"]:
|
|
return HttpResponseRedirect("/")
|
|
|
|
template = loader.get_template("site/view_suggest_{}.html".format(reftag))
|
|
env = make_env()
|
|
return HttpResponse(template.render(env, request))
|
|
|
|
|
|
def view_simple_content(request, content_name):
|
|
"""
|
|
Renders the content in templates/{{ content_name }} inside
|
|
the peeringdb layout
|
|
"""
|
|
|
|
template = loader.get_template("site/simple_content.html")
|
|
|
|
env = make_env(content_name=content_name)
|
|
|
|
return HttpResponse(template.render(env, request))
|
|
|
|
|
|
def view_aup(request):
|
|
"""
|
|
Render page containing acceptable use policy
|
|
"""
|
|
|
|
return view_simple_content(request, "site/aup.html")
|
|
|
|
|
|
def view_sponsorships(request):
|
|
"""
|
|
View current sponsorships
|
|
"""
|
|
|
|
template = loader.get_template("site/sponsorships.html")
|
|
now = datetime.datetime.now().replace(tzinfo=UTC())
|
|
|
|
qset = Sponsorship.objects.filter(start_date__lte=now, end_date__gte=now,
|
|
logo__isnull=False)
|
|
|
|
sponsorships = {
|
|
"diamond": qset.filter(level=4),
|
|
"platinum": qset.filter(level=3),
|
|
"gold": qset.filter(level=2),
|
|
"silver": qset.filter(level=1)
|
|
}
|
|
|
|
env = make_env(sponsorships=sponsorships)
|
|
return HttpResponse(template.render(env, request))
|
|
|
|
|
|
def view_partnerships(request):
|
|
"""
|
|
View current partners
|
|
"""
|
|
|
|
template = loader.get_template("site/partnerships.html")
|
|
qset = Partnership.objects.filter(logo__isnull=False)
|
|
|
|
partnerships = {}
|
|
for row in qset:
|
|
if row.level not in partnerships:
|
|
partnerships[row.level] = []
|
|
partnerships[row.level].append(row)
|
|
|
|
env = make_env(
|
|
partnership_levels=dict(PARTNERSHIP_LEVELS), partnerships=partnerships)
|
|
return HttpResponse(template.render(env, request))
|
|
|
|
|
|
def view_advanced_search(request):
|
|
"""
|
|
View for advanced search
|
|
"""
|
|
|
|
template = loader.get_template("site/advanced-search.html")
|
|
env = make_env(row_limit=getattr(dj_settings, "API_DEPTH_ROW_LIMIT", 250))
|
|
|
|
reftag = request.GET.get("reftag")
|
|
|
|
if reftag == "net":
|
|
try:
|
|
env["ix_name"] = InternetExchange.objects.get(
|
|
id=request.GET.get("ix")).name
|
|
except (ObjectDoesNotExist, ValueError):
|
|
env["ix_name"] = ""
|
|
|
|
try:
|
|
env["not_ix_name"] = InternetExchange.objects.get(
|
|
id=request.GET.get("not_ix")).name
|
|
except (ObjectDoesNotExist, ValueError):
|
|
env["not_ix_name"] = ""
|
|
|
|
try:
|
|
env["fac_name"] = Facility.objects.get(
|
|
id=request.GET.get("fac")).name
|
|
except (ObjectDoesNotExist, ValueError):
|
|
env["fac_name"] = ""
|
|
|
|
try:
|
|
env["not_fac_name"] = Facility.objects.get(
|
|
id=request.GET.get("not_fac")).name
|
|
except (ObjectDoesNotExist, ValueError):
|
|
env["not_fac_name"] = ""
|
|
|
|
return HttpResponse(template.render(env, request))
|
|
|
|
|
|
def request_api_search(request):
|
|
q = request.GET.get('q')
|
|
|
|
if not q:
|
|
return HttpResponseBadRequest()
|
|
|
|
result = search(q)
|
|
|
|
return HttpResponse(json.dumps(result), content_type='application/json')
|
|
|
|
|
|
def request_search(request):
|
|
"""
|
|
XHR search request goes here
|
|
"""
|
|
q = request.GET.get('q')
|
|
|
|
if not q:
|
|
return HttpResponseRedirect("/")
|
|
|
|
# if the user queried for an asn directly via ASXXX or ASNXXX
|
|
# redirect to the result
|
|
m = re.match(r"(asn|as)(\d+)", q.lower())
|
|
if m:
|
|
net = Network.objects.filter(asn=m.group(2), status="ok")
|
|
if net.exists() and net.count() == 1:
|
|
return HttpResponseRedirect('/net/{}'.format(net.first().id))
|
|
|
|
result = search(q)
|
|
|
|
template = loader.get_template('site/search_result.html')
|
|
env = make_env(
|
|
**{
|
|
'search_ixp': result.get(InternetExchange._handleref.tag),
|
|
'search_net': result.get(Network._handleref.tag),
|
|
'search_fac': result.get(Facility._handleref.tag),
|
|
'count_ixp': len(result.get(InternetExchange._handleref.tag, [])),
|
|
'count_net': len(result.get(Network._handleref.tag, [])),
|
|
'count_fac': len(result.get(Facility._handleref.tag, []))
|
|
})
|
|
return HttpResponse(template.render(env, request))
|
|
|
|
|
|
def request_logout(request):
|
|
logout(request)
|
|
return view_index(request)
|
|
|
|
|
|
@csrf_protect
|
|
@ensure_csrf_cookie
|
|
@ratelimit(key="ip", rate=RATELIMITS["request_login_POST"], method="POST")
|
|
def request_login(request):
|
|
|
|
if request.user.is_authenticated():
|
|
return view_index(request)
|
|
|
|
if request.method in ["GET", "HEAD"]:
|
|
return view_login(request)
|
|
|
|
was_limited = getattr(request, "limited", False)
|
|
if was_limited:
|
|
return view_login(request, errors=[
|
|
_("Please wait a bit before trying to login again.")
|
|
])
|
|
|
|
username = request.POST['username']
|
|
password = request.POST['password']
|
|
redir = request.POST.get("next") or "/"
|
|
if redir == "/logout":
|
|
redir = "/"
|
|
|
|
try:
|
|
resolve(redir)
|
|
except Resolver404:
|
|
redir = "/"
|
|
|
|
user = authenticate(username=username, password=password)
|
|
if user is not None:
|
|
if user.is_active:
|
|
login(request, user)
|
|
|
|
from django.utils import translation
|
|
user_language = user.get_locale()
|
|
translation.activate(user_language)
|
|
request.session[translation.LANGUAGE_SESSION_KEY] = user_language
|
|
|
|
return HttpResponseRedirect(redir)
|
|
return view_login(request, errors=[_("Account disabled.")])
|
|
return view_login(request, errors=[_("Invalid username/password.")])
|
|
|
|
|
|
@require_http_methods(["POST"])
|
|
@ratelimit(key="ip", rate=RATELIMITS["request_translation"], method="POST")
|
|
def request_translation(request, data_type):
|
|
|
|
if not request.user.is_authenticated():
|
|
return JsonResponse({
|
|
"status": 'error',
|
|
"error": "Please login to use translation service"
|
|
})
|
|
|
|
user_language = request.user.get_locale()
|
|
if not user_language:
|
|
user_language = 'en'
|
|
|
|
note = request.POST.get("note")
|
|
target = user_language
|
|
|
|
if note and target:
|
|
|
|
translationURL = 'https://translation.googleapis.com/language/translate/v2'
|
|
call_params = {
|
|
'key': dj_settings.GOOGLE_GEOLOC_API_KEY,
|
|
'q': note,
|
|
'target': target
|
|
}
|
|
reply = requests.post(translationURL, params=call_params).json()
|
|
|
|
if not "data" in reply:
|
|
return JsonResponse({"status": request.POST, "error": reply})
|
|
|
|
return JsonResponse({
|
|
"status": request.POST,
|
|
"translation": reply["data"]["translations"][0]
|
|
})
|
|
|
|
return JsonResponse({
|
|
"status": 'error',
|
|
"error": "No text or no language specified"
|
|
})
|