1
0
mirror of https://github.com/peeringdb/peeringdb.git synced 2024-05-11 05:55:09 +00:00
Files
peeringdb-peeringdb/peeringdb_server/signals.py
Matt Griswold ba6f9b6432 Qu1003 (#621)
* 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)
2020-01-08 13:29:58 -06:00

444 lines
15 KiB
Python

import django.urls
from django.db.models.signals import post_save, pre_delete, pre_save
from django.contrib.contenttypes.models import ContentType
from django_namespace_perms.models import Group, GroupPermission
from django_namespace_perms.constants import PERM_CRUD, PERM_READ
from django.template import loader
from django.conf import settings
from django.dispatch import receiver
from allauth.account.signals import user_signed_up
from corsheaders.signals import check_request_enabled
from django_peeringdb.models.abstract import AddressModel
from peeringdb_server.inet import RdapLookup, RdapNotFoundError, RdapException
from peeringdb_server.deskpro import (
ticket_queue,
ticket_queue_asnauto_affil,
ticket_queue_asnauto_create,
)
from peeringdb_server.models import (
QUEUE_ENABLED,
QUEUE_NOTIFY,
UserOrgAffiliationRequest,
is_suggested,
VerificationQueueItem,
Organization,
Facility,
Network,
NetworkContact,
)
import peeringdb_server.settings as pdb_settings
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import override
def addressmodel_save(sender, instance=None, **kwargs):
"""
Mark address model objects for geocode sync if one of the address
fields is updated
"""
if instance.id:
# instance is being updated
old = sender.objects.get(id=instance.id)
for field in AddressModel._meta.get_fields():
if field.name in ["latitude", "longitude"]:
continue
a = getattr(instance, field.name)
b = getattr(old, field.name)
if a != b:
# print("Change in field '%s' - '%s'(%s) to '%s'(%s) - marking %s for geocode sync" % (field.name, a, type(a), b, type(b), instance))
# address model field has changed, mark for geocode sync
instance.geocode_status = False
pre_save.connect(addressmodel_save, sender=Facility)
def org_save(sender, **kwargs):
"""
we want to create a user group for an organization when that
organization is created
"""
inst = kwargs.get("instance")
# make the general member group for the org
try:
group = Group.objects.get(name=inst.group_name)
except Group.DoesNotExist:
group = Group(name=inst.group_name)
group.save()
perm = GroupPermission(
group=group, namespace=inst.nsp_namespace, permissions=PERM_READ
)
perm.save()
GroupPermission(
group=group,
namespace=NetworkContact.nsp_namespace_from_id(inst.id, "*", "private"),
permissions=PERM_READ,
).save()
# make the admin group for the org
try:
group = Group.objects.get(name=inst.admin_group_name)
except Group.DoesNotExist:
group = Group(name=inst.admin_group_name)
group.save()
perm = GroupPermission(
group=group, namespace=inst.nsp_namespace, permissions=PERM_CRUD
)
perm.save()
GroupPermission(
group=group, namespace=inst.nsp_namespace_manage, permissions=PERM_CRUD
).save()
GroupPermission(
group=group,
namespace=NetworkContact.nsp_namespace_from_id(inst.id, "*", "private"),
permissions=PERM_CRUD,
).save()
if inst.status == "deleted":
for ar in inst.affiliation_requests.all():
ar.delete()
post_save.connect(org_save, sender=Organization)
def org_delete(sender, instance, **kwargs):
"""
When an organization is HARD deleted we want to also remove any
usergroups tied to the organization
"""
try:
instance.usergroup.delete()
except Group.DoesNotExist:
pass
try:
instance.admin_usergroup.delete()
except Group.DoesNotExist:
pass
for ar in instance.affiliation_requests.all():
ar.delete()
pre_delete.connect(org_delete, sender=Organization)
@receiver(user_signed_up, dispatch_uid="allauth.user_signed_up")
def new_user_to_guests(request, user, sociallogin=None, **kwargs):
"""
When a user is created via oauth login put them in the guest
group for now.
Unless pdb_settings.AUTO_VERIFY_USERS is toggled on in settings, in which
case users get automatically verified (note that this does
not include email verification, they will still need to do that)
"""
if pdb_settings.AUTO_VERIFY_USERS:
user.set_verified()
else:
user.set_unverified()
# USER TO ORGANIZATION AFFILIATION
def uoar_creation(sender, instance, created=False, **kwargs):
"""
When a user to organization affiliation request is created
we want to notify the approporiate management entity
We also want to attempt to derive the targeted organization
from the ASN the user provided
"""
if created:
if instance.asn and not instance.org_id:
network = Network.objects.filter(asn=instance.asn).first()
if network:
# network with targeted asn found, set org
instance.org = network.org
instance.status = "pending"
instance.save()
if instance.org_id and instance.org.admin_usergroup.user_set.count() > 0:
# check that user is not already a member of that org
if instance.user.groups.filter(name=instance.org.usergroup.name).exists():
instance.approve()
return
# organization exists already and has admins, notify organization
# admins
for user in instance.org.admin_usergroup.user_set.all():
with override(user.locale):
user.email_user(
_(
"User %(u_name)s wishes to be affiliated to your Organization"
)
% {"u_name": instance.user.full_name},
loader.get_template(
"email/notify-org-admin-user-affil.txt"
).render(
{
"user": instance.user,
"org": instance.org,
"org_management_url": "%s/org/%d#users"
% (settings.BASE_URL, instance.org.id),
}
),
)
else:
request_type = "be affiliated to"
rdap_data = {"emails": []}
org_created = False
net_created = False
rdap_lookup = None
if instance.asn and not instance.org_id:
# ASN specified in request, but no network found
# Lookup RDAP information
try:
rdap_lookup = rdap = RdapLookup().get_asn(instance.asn)
ok = rdap_lookup.emails
except RdapException as inst:
instance.deny()
raise
# create organization
instance.org, org_created = Organization.create_from_rdap(
rdap, instance.asn, instance.org_name
)
instance.save()
# create network
net, net_created = Network.create_from_rdap(
rdap, instance.asn, instance.org
)
# if affiliate auto appove is on, auto approve at this point
if pdb_settings.AUTO_APPROVE_AFFILIATION:
instance.approve()
return
ticket_queue_asnauto_create(
instance.user,
instance.org,
net,
rdap,
net.asn,
org_created=org_created,
net_created=net_created,
)
# if user's relationship to network can be validated now
# we can approve the ownership request right away
if instance.user.validate_rdap_relationship(rdap):
instance.approve()
ticket_queue_asnauto_affil(instance.user, instance.org, net, rdap)
return
if instance.org:
# organization has been set on affiliation request
entity_name = instance.org.name
if not instance.org.owned:
# organization is currently not owned
request_type = "request ownership of"
# if affiliate auto appove is on, auto approve at this point
if pdb_settings.AUTO_APPROVE_AFFILIATION:
instance.approve()
return
# if user's relationship to the org can be validated by
# checking the rdap information of the org's networks
# we can approve the affiliation (ownership) request right away
for asn, rdap in list(instance.org.rdap_collect.items()):
rdap_data["emails"].extend(rdap.emails)
if instance.user.validate_rdap_relationship(rdap):
ticket_queue_asnauto_affil(
instance.user,
instance.org,
Network.objects.get(asn=asn),
rdap,
)
instance.approve()
return
else:
entity_name = instance.org_name
if pdb_settings.AUTO_APPROVE_AFFILIATION:
org = Organization.objects.create(
name=instance.org_name, status="ok"
)
instance.org = org
instance.approve()
return
# organization has no owners and RDAP information could not verify the user's relationship to the organization, notify pdb staff for review
ticket_queue(
"User %s wishes to %s %s"
% (instance.user.username, request_type, entity_name),
loader.get_template("email/notify-pdb-admin-user-affil.txt").render(
{
"user": instance.user,
"instance": instance,
"base_url": settings.BASE_URL,
"org_add_url": "%s%s"
% (
settings.BASE_URL,
django.urls.reverse(
"admin:peeringdb_server_organization_add"
),
),
"net_add_url": "%s%s"
% (
settings.BASE_URL,
django.urls.reverse("admin:peeringdb_server_network_add"),
),
"review_url": "%s%s"
% (
settings.BASE_URL,
django.urls.reverse(
"admin:peeringdb_server_user_change",
args=(instance.user.id,),
),
),
"approve_url": "%s%s"
% (
settings.BASE_URL,
django.urls.reverse(
"admin:peeringdb_server_userorgaffiliationrequest_actions",
args=(instance.id, "approve_and_notify"),
),
),
"emails": list(set(rdap_data["emails"])),
"rdap_lookup": rdap_lookup,
}
),
instance.user,
)
elif instance.status == "approved" and instance.org_id:
# uoar was not created, and status is now approved, call approve
# to finalize
instance.approve()
post_save.connect(uoar_creation, sender=UserOrgAffiliationRequest)
# VERIFICATION QUEUE
if getattr(settings, "DISABLE_VERIFICATION_QUEUE", False) is False:
def verification_queue_update(sender, instance, **kwargs):
if instance.status == "pending":
try:
VerificationQueueItem.objects.get(
content_type=ContentType.objects.get_for_model(sender),
object_id=instance.id,
)
except VerificationQueueItem.DoesNotExist:
q = VerificationQueueItem(item=instance)
q.save()
else:
try:
q = VerificationQueueItem.objects.get(
content_type=ContentType.objects.get_for_model(sender),
object_id=instance.id,
)
q.delete()
except VerificationQueueItem.DoesNotExist:
pass
def verification_queue_delete(sender, instance, **kwargs):
try:
q = VerificationQueueItem.objects.get(
content_type=ContentType.objects.get_for_model(sender),
object_id=instance.id,
)
q.delete()
except VerificationQueueItem.DoesNotExist:
pass
def verification_queue_notify(sender, instance, **kwargs):
# notification was already sent
if instance.notified:
return
# we dont sent notifications unless requesting user has been identified
if not instance.user_id:
return
item = instance.item
user = instance.user
if type(item) in QUEUE_NOTIFY and not getattr(
settings, "DISABLE_VERIFICATION_QUEUE_EMAILS", False
):
if type(item) == Network:
rdap = RdapLookup().get_asn(item.asn)
else:
rdap = None
title = "{} - {}".format(instance.content_type, item)
if is_suggested(item):
title = "[SUGGEST] {}".format(title)
ticket_queue(
title,
loader.get_template("email/notify-pdb-admin-vq.txt").render(
{
"entity_type_name": str(instance.content_type),
"suggested": is_suggested(item),
"item": item,
"user": user,
"rdap": rdap,
"edit_url": "%s%s"
% (settings.BASE_URL, instance.item_admin_url),
}
),
instance.user,
)
instance.notified = True
instance.save()
post_save.connect(verification_queue_notify, sender=VerificationQueueItem)
for model in QUEUE_ENABLED:
post_save.connect(verification_queue_update, sender=model)
pre_delete.connect(verification_queue_delete, sender=model)
def cors_allow_api_get_to_everyone(sender, request, **kwargs):
# FIXME: path name to look for should come from config
return (
request.path == "/api" or request.path.startswith("/api/")
) and request.method in ["GET", "OPTIONS"]
check_request_enabled.connect(cors_allow_api_get_to_everyone)