1
0
mirror of https://github.com/peeringdb/peeringdb.git synced 2024-05-11 05:55:09 +00:00
Files
peeringdb-peeringdb/peeringdb_server/deskpro.py
Matt Griswold aed211418d Fix typos1 conflicts resolved (#842)
* Update 0006_network_allow_ixp_update.py

fixes 'Sepcifies' typo in 0006_network_allow_ixp_update.py

* Update 0029_auto_20200401_1006.py

fixes 'Sepcifies' typo in 0029_auto_20200401_1006.py

* Update models.py

fixes 'Sepcifies' typo in models.py

* Update org_admin_views.py

fixes 'afiliation' typos in org_admin_views.py

* Update serializers.py

fix use of "it's" when it should instead be "its" in 'serializers.py'

* Update 0004_geocode_fields.py

correct use of "it's" to be "its" in '0004_geocode_fields.py', also fix spelling of 'syncronized'

* Update 0029_auto_20200401_1006.py

correct use of "it's" to be "its" in '0029_auto_20200401_1006.py', also fix spelling of 'syncronized'

* Update models.py

correct use of "it's" to be "its" in 'models.py', also fix spelling of 'syncronized'

* Update email_confirm.html

correct 're-initate' in email_confirm.html

* Update notify-pdb-admin-user-affil.txt

correct 'organzation' in 'notify-pdb-admin-user-affil.txt'

* Update op_create.md

correct 'organzation' in 'ip_create.md'

* Update notify-pdb-admin-asnauto-skipvq.txt

correct 'organzation' in 'notify-pdb-admin-asnauto-skipvq.txt'

* Update models.py

correct 'organzation' in 'models.py'

* Update notify-pdb-admin-asnauto-skipvq.txt

fix 'succesfully' in 'notify-pdb-admin-asnauto-skipvq.txt'

* Update views.py

fix 'succesfully' in 'views.py'

* Update pdb_migrate_ixlans.py

* Update models.py

several more replacements of "it's" with "its"

* Update rest.py

one more replacement of "it's" with "its"

* Update op_retrieve.md

replace "dont" with "don't"

* Update notify-org-admin-merge.txt

fix "dont" with "don't"

* Update error.html

fix "dont" with "don't"

* Update op_list.md

fix "dont" with "don't"

* Update serializers.py

fix "dont" with "don't"

* Update deskpro.py

fix "dont" with "don't"

* Update mock.py

fix "dont" with "don't"

* Update ixf.py

fix "dont" with "don't"

* Update admin.py

fix "dont" with "don't"

* Update api_schema.py

fix "dont" with "don't"

* Update signals.py

fix "dont" with "don't"

* Update views.py

fix "dont" with "don't"

* Update test_admin.py

fix "dont" with "don't"

* Update pdb_api_test.py

fix "dont" with "don't"

* Update models.py

fix "dont" with "don't"

* revert to "IXP" in help text

Co-authored-by: Theo Baschak <tbaschak@users.noreply.github.com>
Co-authored-by: Stefan Pratter <stefan@20c.com>
2020-09-29 15:01:47 -05:00

281 lines
7.3 KiB
Python

"""
DeskPro API Client
"""
import uuid
import re
import requests
import datetime
from django.template import loader
from django.conf import settings
import django.urls
from peeringdb_server.models import DeskProTicket
from peeringdb_server.inet import RdapNotFoundError
def ticket_queue(subject, body, user):
""" queue a deskpro ticket for creation """
ticket = DeskProTicket.objects.create(
subject=f"{settings.EMAIL_SUBJECT_PREFIX}{subject}", body=body, user=user,
)
class APIError(IOError):
def __init__(self, msg, data):
super().__init__(msg)
self.data = data
def ticket_queue_asnauto_skipvq(user, org, net, rir_data):
"""
queue deskro ticket creation for asn automation action: skip vq
"""
if isinstance(net, dict):
net_name = net.get("name")
else:
net_name = net.name
if isinstance(org, dict):
org_name = org.get("name")
else:
org_name = org.name
ticket_queue(
f"[ASNAUTO] Network '{net_name}' approved for existing Org '{org_name}'",
loader.get_template("email/notify-pdb-admin-asnauto-skipvq.txt").render(
{"user": user, "org": org, "net": net, "rir_data": rir_data}
),
user,
)
def ticket_queue_asnauto_affil(user, org, net, rir_data):
"""
queue deskro ticket creation for asn automation action: affil
"""
ticket_queue(
"[ASNAUTO] Ownership claim granted to Org '%s' for user '%s'"
% (org.name, user.username),
loader.get_template("email/notify-pdb-admin-asnauto-affil.txt").render(
{"user": user, "org": org, "net": net, "rir_data": rir_data}
),
user,
)
def ticket_queue_asnauto_create(
user, org, net, rir_data, asn, org_created=False, net_created=False
):
"""
queue deskro ticket creation for asn automation action: create
"""
subject = []
if org_created:
subject.append("Organization '%s'" % org.name)
if net_created:
subject.append("Network '%s'" % net.name)
if not subject:
return
subject = ", ".join(subject)
ticket_queue(
"[ASNAUTO] %s created" % subject,
loader.get_template(
"email/notify-pdb-admin-asnauto-entity-creation.txt"
).render(
{
"user": user,
"org": org,
"net": net,
"asn": asn,
"org_created": org_created,
"net_created": net_created,
"rir_data": rir_data,
}
),
user,
)
def ticket_queue_rdap_error(user, asn, error):
if isinstance(error, RdapNotFoundError):
return
error_message = f"{error}"
if re.match("(.+) returned 400", error_message):
return
subject = f"[RDAP_ERR] {user.username} - AS{asn}"
ticket_queue(
subject,
loader.get_template("email/notify-pdb-admin-rdap-error.txt").render(
{"user": user, "asn": asn, "error_details": error_message}
),
user,
)
class APIClient:
def __init__(self, url, key):
self.key = key
self.url = url
@property
def auth_headers(self):
return {"Authorization": f"key {self.key}"}
def parse_response(self, response, many=False):
r_json = response.json()
if "status" in r_json:
if r_json["status"] >= 400:
raise APIError(r_json["message"], r_json)
else:
response.raise_for_status()
data = r_json["data"]
if isinstance(data, list):
if many:
return r_json["data"]
elif data:
return data[0]
else:
return data
def get(self, endpoint, param):
response = requests.get(
f"{self.url}/{endpoint}", params=param, headers=self.auth_headers
)
return self.parse_response(response)
def create(self, endpoint, param):
response = requests.post(
f"{self.url}/{endpoint}", json=param, headers=self.auth_headers
)
return self.parse_response(response)
def require_person(self, user):
person = self.get("people", {"primary_email": user.email})
if not person:
person = self.create(
"people",
{
"primary_email": user.email,
"first_name": user.first_name,
"last_name": user.last_name,
"name": user.full_name,
},
)
return person
def create_ticket(self, ticket):
person = self.require_person(ticket.user)
if not ticket.deskpro_id:
ticket_response = self.create(
"tickets",
{
"subject": ticket.subject,
"person": {"id": person["id"]},
"status": "awaiting_agent",
},
)
ticket.deskpro_ref = ticket_response["ref"]
ticket.deskpro_id = ticket_response["id"]
self.create(
"tickets/{}/messages".format(ticket.deskpro_id),
{
"message": ticket.body.replace("\n", "<br />\n"),
"person": person["id"],
"format": "html",
},
)
class MockAPIClient(APIClient):
"""
A mock api client for the deskpro API
The IX-F importer uses this when
IXF_SEND_TICKETS=False
"""
def __init__(self, *args, **kwargs):
self.ticket_count = 0
def get(self, endpoint, param):
if endpoint == "people":
return {"id": 1}
return {}
def create(self, endpoint, param):
if endpoint == "tickets":
self.ticket_count += 1
ref = "{}".format(uuid.uuid4())
return {"ref": ref[:16], "id": self.ticket_count}
return {}
def ticket_queue_deletion_prevented(user, instance):
"""
queue deskpro ticket to notify about the prevented
deletion of an object #696
"""
subject = (
f"[PROTECTED] Deletion prevented: "
f"{instance.HandleRef.tag}-{instance.id} "
f"{instance}"
)
# we don't want to spam DeskPRO with tickets when a user
# repeatedly clicks the delete button for an object
#
# so we check if a ticket has recently been sent for it
# and opt out if it falls with in the spam protection
# period defined in settings
period = settings.PROTECTED_OBJECT_NOTIFICATION_PERIOD
now = datetime.datetime.now(datetime.timezone.utc)
max_age = now - datetime.timedelta(hours=period)
ticket = DeskProTicket.objects.filter(
subject=f"{settings.EMAIL_SUBJECT_PREFIX}{subject}"
)
ticket = ticket.filter(created__gt=max_age)
# recent ticket for object exists, bail
if ticket.exists():
return
model_name = instance.__class__.__name__.lower()
# create ticket
ticket_queue(
subject,
loader.get_template("email/notify-pdb-admin-deletion-prevented.txt").render(
{
"user": user,
"instance": instance,
"admin_url": settings.BASE_URL
+ django.urls.reverse(
f"admin:peeringdb_server_{model_name}_change", args=(instance.id,)
),
}
),
user,
)