mirror of
https://github.com/peeringdb/peeringdb.git
synced 2024-05-11 05:55:09 +00:00
Support 202009 (#841)
* Add EmailMultiAlternatives import * Add strip_tags import * Add settings imports and new email test * Add email increment to ixf and tests * IX-F Importer: suggested update when it should be add + remove #832 * Take email increment out of if-else * Add max and min speed settings * Change validation check for models * new speed validation * Add basic user command * Add pdb cleanup users tool * Add pretty printing for speed * Add users as a subparser * add translation override to signals * Add parser as parent of subparser * refactor and change test * Move override to cover single variable * Add tooltip option for individual checkboxes * address 'fix me' issue with field_help helper func * Add zipcode validator and black format * Make website required input but zipcode dependent on country * Add net POC requirement to Netixlan serializer * Website is now blank=False ie required in all forms * refine error message * Require email is not blank and add test * Change error message * add website and zipcode test, edit zipcode error message * change placement of tooltip * add question mark * Add comment * Add runtime error logging for ixp member import * add uncaught error test * delete two unused methods * Rename test file and add different tests * Add missing email imports (reproduces changes in hot_fix_gh_831) * add resend methods * Add missing email imports (reproduces changes in hot_fix_gh_831) * Add pytest-mock to pipfile * Add resend email mechanism * Add email resending * remove failing assertion * fix for ticket_aged_proposals * Wrap resending emails in conditional for commit * Add resend email tests * fix mail_Debug bug * Figure out production mailing and resending settings * Add stale info field * default IXF_RESEND_FAILED_EMAILS to False fix issue with sent being set even if email was not sent fix issue with output stating resending of emails even if it wasnt * IX-F Preview - shows the consolidated delete operation when it shouldn't (#824) * black format (v 19.10) * black formatting * black formatting * pipfile relock * make changes from #825 play nice with changes from #833 * black to pipenv dev packages Co-authored-by: Elliot Frank <elliot@20c.com> Co-authored-by: Stefan Pratter <stefan@20c.com>
This commit is contained in:
@@ -571,6 +571,7 @@ class TestJSON(unittest.TestCase):
|
||||
|
||||
with pytest.raises(InvalidRequestException) as excinfo:
|
||||
r = db.create(typ, data_invalid, return_response=True)
|
||||
|
||||
assert "400 Bad Request" in str(excinfo.value)
|
||||
|
||||
# we test fail because of parent entity status
|
||||
@@ -1161,7 +1162,10 @@ class TestJSON(unittest.TestCase):
|
||||
"fac",
|
||||
data,
|
||||
test_failures={
|
||||
"invalid": {"name": "",},
|
||||
"invalid": [
|
||||
{"name": ""},
|
||||
{"name": self.make_name("Test"), "website": ""},
|
||||
],
|
||||
"perms": {
|
||||
# need to set name again so it doesnt fail unique validation
|
||||
"name": self.make_name("Test"),
|
||||
@@ -1222,6 +1226,30 @@ class TestJSON(unittest.TestCase):
|
||||
|
||||
##########################################################################
|
||||
|
||||
def test_org_admin_002_POST_PUT_DELETE_fac_zipcode(self):
|
||||
data = self.make_data_fac()
|
||||
|
||||
# Requires a zipcode if country is a country
|
||||
# with postal codes (ie US)
|
||||
r_data = self.assert_create(
|
||||
self.db_org_admin,
|
||||
"fac",
|
||||
data,
|
||||
test_failures={
|
||||
"invalid": [{"name": self.make_name("Test"), "zipcode": ""},],
|
||||
},
|
||||
test_success=False,
|
||||
)
|
||||
|
||||
# Change to country w/o postal codes
|
||||
data["country"] = "ZW"
|
||||
data["zipcode"] = ""
|
||||
|
||||
r_data = self.assert_create(self.db_org_admin, "fac", data,)
|
||||
assert r_data["zipcode"] == ""
|
||||
|
||||
##########################################################################
|
||||
|
||||
def test_org_admin_002_POST_PUT_DELETE_net(self):
|
||||
data = self.make_data_net(asn=9000900)
|
||||
|
||||
@@ -1647,6 +1675,49 @@ class TestJSON(unittest.TestCase):
|
||||
|
||||
##########################################################################
|
||||
|
||||
def test_org_admin_002_POST_netixlan_no_net_contact(self):
|
||||
network = SHARED["net_rw_ok"]
|
||||
|
||||
for poc in network.poc_set_active.all():
|
||||
poc.delete()
|
||||
|
||||
data = self.make_data_netixlan(
|
||||
net_id=SHARED["net_rw_ok"].id,
|
||||
ixlan_id=SHARED["ixlan_rw_ok"].id,
|
||||
asn=SHARED["net_rw_ok"].asn,
|
||||
)
|
||||
|
||||
# When we create this netixlan it should fail with a
|
||||
# non-field-error.
|
||||
|
||||
r_data = self.assert_create(
|
||||
self.db_org_admin,
|
||||
"netixlan",
|
||||
data,
|
||||
test_failures={"invalid": {"n/a": "n/a"}},
|
||||
test_success=False,
|
||||
)
|
||||
|
||||
# Undelete poc but blank email
|
||||
poc = network.poc_set.first()
|
||||
poc.status = "ok"
|
||||
poc.email = ""
|
||||
poc.visible = "Public"
|
||||
poc.save()
|
||||
network.refresh_from_db()
|
||||
|
||||
# Also fails with network contact that is
|
||||
# missing an email
|
||||
r_data = self.assert_create(
|
||||
self.db_org_admin,
|
||||
"netixlan",
|
||||
data,
|
||||
test_failures={"invalid": {"n/a": "n/a"}},
|
||||
test_success=False,
|
||||
)
|
||||
|
||||
##########################################################################
|
||||
|
||||
def test_org_admin_002_POST_PUT_netixlan_validation(self):
|
||||
data = self.make_data_netixlan(
|
||||
net_id=SHARED["net_rw_ok"].id, ixlan_id=SHARED["ixlan_rw_ok"].id
|
||||
@@ -1657,6 +1728,12 @@ class TestJSON(unittest.TestCase):
|
||||
{"invalid": {"ipaddr4": self.get_ip4(SHARED["ixlan_r_ok"])}},
|
||||
# test failure if ip6 not in prefix
|
||||
{"invalid": {"ipaddr6": self.get_ip6(SHARED["ixlan_r_ok"])}},
|
||||
# test failure if speed is below limit
|
||||
{"invalid": {"speed": 1}},
|
||||
# test failure if speed is above limit
|
||||
{"invalid": {"speed": 1250000}},
|
||||
# test failure if speed is None
|
||||
{"invalid": {"speed": None}},
|
||||
]
|
||||
|
||||
for test_failure in test_failures:
|
||||
@@ -1893,7 +1970,9 @@ class TestJSON(unittest.TestCase):
|
||||
with fields parameter set would raise a 500 error for
|
||||
unauthenticated users
|
||||
"""
|
||||
data = self.db_guest.get("ixlan", SHARED["ixlan_rw_ok"].id, fields="ixpfx_set", depth=2)
|
||||
data = self.db_guest.get(
|
||||
"ixlan", SHARED["ixlan_rw_ok"].id, fields="ixpfx_set", depth=2
|
||||
)
|
||||
assert len(data) == 1
|
||||
row = data[0]
|
||||
assert list(row.keys()) == ["ixpfx_set"]
|
||||
|
||||
17
peeringdb_server/management/commands/pdb_base_command.py
Normal file
17
peeringdb_server/management/commands/pdb_base_command.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
class PeeringDBBaseCommand(BaseCommand):
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
"--commit", action="store_true", help="Commit the changes."
|
||||
)
|
||||
|
||||
def log(self, msg):
|
||||
if self.commit:
|
||||
self.stdout.write(msg)
|
||||
else:
|
||||
self.stdout.write("[pretend] {}".format(msg))
|
||||
|
||||
def handle(self, *args, **options):
|
||||
self.commit = options.get("commit")
|
||||
53
peeringdb_server/management/commands/pdb_cleanup_vq.py
Normal file
53
peeringdb_server/management/commands/pdb_cleanup_vq.py
Normal file
@@ -0,0 +1,53 @@
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.conf import settings
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.utils import timezone
|
||||
|
||||
from peeringdb_server.models import VerificationQueueItem, User
|
||||
from peeringdb_server.management.commands.pdb_base_command import PeeringDBBaseCommand
|
||||
|
||||
class Command(PeeringDBBaseCommand):
|
||||
|
||||
help = "Use this tool to clean up the Verification Queue"
|
||||
|
||||
def add_arguments(self, parser):
|
||||
super().add_arguments(parser)
|
||||
subparsers = parser.add_subparsers()
|
||||
parser_users = subparsers.add_parser(
|
||||
'users',
|
||||
parents=[parser],
|
||||
add_help=False,
|
||||
help='Tool to remove outdated user verification requests')
|
||||
parser_users.set_defaults(func=self._clean_users)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
super().handle(*args, **options)
|
||||
|
||||
if options.get("func"):
|
||||
options["func"]()
|
||||
|
||||
def _clean_users(self):
|
||||
model = User
|
||||
content_type = ContentType.objects.get_for_model(model)
|
||||
date = datetime.now(timezone.utc) - timedelta(days=settings.VQUEUE_USER_MAX_AGE)
|
||||
|
||||
qset = VerificationQueueItem.objects.filter(
|
||||
content_type=content_type,
|
||||
created__lte=date
|
||||
)
|
||||
count = qset.count()
|
||||
|
||||
self.log(f"Deleting VerificationQueueItems for Users created before {date:%x}")
|
||||
self.log(f"Items flagged for deletion: {count}")
|
||||
|
||||
counter = 0
|
||||
|
||||
for vqi in qset:
|
||||
counter += 1
|
||||
self.log(f"Deleting VerificationQueueItem for {vqi.content_type} "
|
||||
f"id #{vqi.object_id}... {counter} / {count}")
|
||||
|
||||
if self.commit:
|
||||
vqi.delete()
|
||||
@@ -1,5 +1,6 @@
|
||||
import traceback
|
||||
import json
|
||||
import sys
|
||||
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.db import transaction
|
||||
@@ -75,11 +76,14 @@ class Command(BaseCommand):
|
||||
else:
|
||||
self.stdout.write("[Pretend] {}".format(msg))
|
||||
|
||||
def release_env_check(self, flag):
|
||||
if settings.RELEASE_ENV != "prod":
|
||||
return True
|
||||
else:
|
||||
raise PermissionError("Flag {} is not permitted to be used in production.")
|
||||
def store_runtime_error(self, error):
|
||||
error_str = "ERROR: {}".format(error) + "\n"
|
||||
error_str += traceback.format_exc()
|
||||
self.runtime_errors.append(error_str)
|
||||
|
||||
def write_runtime_errors(self):
|
||||
for error in self.runtime_errors:
|
||||
self.stderr.write(error)
|
||||
|
||||
def initiate_reset_flags(self, **options):
|
||||
flags = [
|
||||
@@ -161,6 +165,12 @@ class Command(BaseCommand):
|
||||
),
|
||||
)
|
||||
|
||||
def resend_emails(self, importer):
|
||||
num_emails_to_resend = len(importer.emails_to_resend)
|
||||
self.log(f"Attemping to resend {num_emails_to_resend} emails.")
|
||||
resent_emails = importer.resend_emails()
|
||||
self.log(f"RE-SENT EMAILS: {len(resent_emails)}.")
|
||||
|
||||
def handle(self, *args, **options):
|
||||
self.commit = options.get("commit", False)
|
||||
self.debug = options.get("debug", False)
|
||||
@@ -170,6 +180,8 @@ class Command(BaseCommand):
|
||||
|
||||
self.active_reset_flags = self.initiate_reset_flags(**options)
|
||||
|
||||
self.runtime_errors = []
|
||||
|
||||
if self.reset or self.reset_hints:
|
||||
self.reset_all_hints()
|
||||
if self.reset or self.reset_dismisses:
|
||||
@@ -237,8 +249,7 @@ class Command(BaseCommand):
|
||||
total_notifications += importer.notifications
|
||||
|
||||
except Exception as inst:
|
||||
self.log("ERROR: {}".format(inst))
|
||||
self.log(traceback.format_exc())
|
||||
self.store_runtime_error(inst)
|
||||
|
||||
if self.preview:
|
||||
self.stdout.write(json.dumps(total_log, indent=2))
|
||||
@@ -249,6 +260,13 @@ class Command(BaseCommand):
|
||||
importer = ixf.Importer()
|
||||
importer.reset(save=self.commit)
|
||||
importer.notifications = total_notifications
|
||||
importer.notify_proposals()
|
||||
importer.notify_proposals(error_handler=self.store_runtime_error)
|
||||
|
||||
self.stdout.write(f"Emails: {importer.emails}")
|
||||
self.stdout.write(f"New Emails: {importer.emails}")
|
||||
|
||||
if len(self.runtime_errors) > 0:
|
||||
self.write_runtime_errors()
|
||||
sys.exit(1)
|
||||
|
||||
if self.commit:
|
||||
self.resend_emails(importer)
|
||||
|
||||
Reference in New Issue
Block a user