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

355 lines
13 KiB
Python
Raw Normal View History

2018-11-08 19:45:21 +00:00
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 django.core import urlresolvers
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)
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
"""
instance.usergroup.delete()
instance.admin_usergroup.delete()
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
"""
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(
_(u"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, 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)
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 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 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
# organization has no owners and RDAP information could not verify the user's relationship to the organization, notify pdb staff for review
ticket_queue(
u'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,
urlresolvers.reverse(
"admin:peeringdb_server_organization_add")),
"net_add_url": "%s%s" %
(settings.BASE_URL,
urlresolvers.reverse(
"admin:peeringdb_server_network_add")),
"review_url": "%s%s" %
(settings.BASE_URL,
urlresolvers.reverse(
"admin:peeringdb_server_user_change",
args=(instance.user.id, ))),
"approve_url": "%s%s" % (
settings.BASE_URL,
urlresolvers.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 = u"{} - {}".format(instance.content_type, item)
if is_suggested(item):
title = u"[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)