From cdfc9840a7b658563b94d45a8cb54972f267656d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C4=93teris=20Caune?= Date: Wed, 15 May 2019 14:27:50 +0300 Subject: [PATCH] Source formatted with Black --- hc/accounts/admin.py | 91 +++-- hc/accounts/backends.py | 6 +- hc/accounts/forms.py | 13 +- .../commands/senddeletionnotices.py | 5 +- hc/accounts/migrations/0001_initial.py | 32 +- .../migrations/0002_profile_ping_log_limit.py | 10 +- hc/accounts/migrations/0003_profile_token.py | 10 +- .../migrations/0004_profile_api_key.py | 10 +- .../migrations/0005_auto_20160509_0801.py | 38 +- .../migrations/0006_profile_current_team.py | 16 +- .../migrations/0007_profile_check_limit.py | 10 +- .../migrations/0008_profile_bill_to.py | 10 +- .../migrations/0009_auto_20170714_1734.py | 16 +- .../migrations/0010_profile_team_limit.py | 10 +- hc/accounts/migrations/0011_profile_sort.py | 12 +- .../migrations/0012_auto_20171014_1002.py | 21 +- ...0013_remove_profile_team_access_allowed.py | 9 +- .../migrations/0014_auto_20171227_1530.py | 16 +- .../migrations/0015_auto_20181029_1858.py | 12 +- .../migrations/0016_remove_profile_bill_to.py | 11 +- .../migrations/0017_auto_20190112_1426.py | 53 ++- .../migrations/0018_auto_20190112_1426.py | 8 +- .../migrations/0019_project_badge_key.py | 10 +- .../migrations/0020_auto_20190112_1950.py | 8 +- .../migrations/0021_auto_20190112_2005.py | 10 +- .../migrations/0022_auto_20190114_0857.py | 14 +- .../migrations/0023_auto_20190117_1419.py | 19 +- .../migrations/0024_auto_20190119_1540.py | 14 +- .../migrations/0025_remove_member_team.py | 11 +- .../migrations/0026_auto_20190204_2042.py | 16 +- .../0027_profile_deletion_notice_date.py | 10 +- hc/accounts/models.py | 29 +- hc/accounts/tests/test_add_project.py | 1 - hc/accounts/tests/test_admin.py | 1 - hc/accounts/tests/test_change_email.py | 1 - hc/accounts/tests/test_check_token.py | 1 - hc/accounts/tests/test_close_account.py | 1 - hc/accounts/tests/test_login.py | 32 +- hc/accounts/tests/test_notifications.py | 1 - hc/accounts/tests/test_profile.py | 5 +- hc/accounts/tests/test_project.py | 11 +- hc/accounts/tests/test_project_model.py | 1 - hc/accounts/tests/test_remove_project.py | 1 - hc/accounts/tests/test_set_password.py | 1 - hc/accounts/tests/test_signup.py | 1 - .../tests/test_team_access_middleware.py | 1 - hc/accounts/tests/test_unsubscribe_reports.py | 1 - hc/accounts/urls.py | 49 +-- hc/accounts/views.py | 61 +-- hc/api/admin.py | 85 ++-- hc/api/decorators.py | 5 + .../management/commands/prunenotifications.py | 7 +- hc/api/management/commands/prunepings.py | 2 +- hc/api/management/commands/prunepingsslow.py | 5 +- .../management/commands/prunetokenbucket.py | 2 +- hc/api/management/commands/sendalerts.py | 18 +- hc/api/management/commands/sendreports.py | 20 +- .../management/commands/settelegramwebhook.py | 2 +- hc/api/management/commands/smtpd.py | 21 +- hc/api/migrations/0001_initial.py | 29 +- hc/api/migrations/0002_auto_20150616_0732.py | 43 ++- hc/api/migrations/0003_auto_20150616_1249.py | 16 +- hc/api/migrations/0004_auto_20150616_1319.py | 18 +- hc/api/migrations/0005_auto_20150630_2021.py | 17 +- hc/api/migrations/0006_check_grace.py | 10 +- hc/api/migrations/0007_ping.py | 30 +- hc/api/migrations/0008_auto_20150801_1213.py | 10 +- hc/api/migrations/0009_auto_20150801_1250.py | 18 +- hc/api/migrations/0010_channel.py | 45 ++- hc/api/migrations/0011_notification.py | 31 +- hc/api/migrations/0012_auto_20150930_1922.py | 20 +- hc/api/migrations/0013_auto_20151001_2029.py | 21 +- hc/api/migrations/0014_auto_20151019_2039.py | 10 +- hc/api/migrations/0015_auto_20151022_1008.py | 9 +- hc/api/migrations/0016_auto_20151030_1107.py | 21 +- hc/api/migrations/0017_auto_20151117_1032.py | 22 +- hc/api/migrations/0018_remove_ping_body.py | 11 +- hc/api/migrations/0019_check_tags.py | 10 +- hc/api/migrations/0020_check_n_pings.py | 10 +- hc/api/migrations/0021_ping_n.py | 10 +- hc/api/migrations/0022_auto_20160130_2042.py | 13 +- hc/api/migrations/0023_auto_20160131_1919.py | 9 +- hc/api/migrations/0024_auto_20160203_2227.py | 23 +- hc/api/migrations/0025_auto_20160216_1214.py | 23 +- hc/api/migrations/0026_auto_20160415_1824.py | 10 +- hc/api/migrations/0027_auto_20161213_1059.py | 45 ++- hc/api/migrations/0028_auto_20170305_1907.py | 28 +- hc/api/migrations/0029_auto_20170507_1251.py | 10 +- .../migrations/0030_check_last_ping_body.py | 10 +- hc/api/migrations/0031_auto_20170509_1320.py | 10 +- hc/api/migrations/0032_auto_20170608_1158.py | 27 +- hc/api/migrations/0033_auto_20170714_1715.py | 28 +- hc/api/migrations/0034_auto_20171227_1530.py | 29 +- hc/api/migrations/0035_auto_20171229_2008.py | 30 +- hc/api/migrations/0036_auto_20180116_2243.py | 11 +- hc/api/migrations/0037_auto_20180127_1215.py | 10 +- hc/api/migrations/0038_auto_20180318_1306.py | 12 +- .../0039_remove_check_last_ping_body.py | 11 +- hc/api/migrations/0040_auto_20180517_1336.py | 12 +- hc/api/migrations/0041_check_desc.py | 10 +- hc/api/migrations/0042_auto_20181029_1522.py | 31 +- hc/api/migrations/0043_channel_name.py | 10 +- hc/api/migrations/0044_auto_20181120_2004.py | 10 +- hc/api/migrations/0045_flip.py | 58 ++- hc/api/migrations/0046_auto_20181218_1245.py | 12 +- hc/api/migrations/0047_auto_20181225_2315.py | 10 +- hc/api/migrations/0048_auto_20190102_0737.py | 8 +- hc/api/migrations/0049_auto_20190102_0743.py | 16 +- hc/api/migrations/0050_ping_kind.py | 10 +- hc/api/migrations/0051_auto_20190104_0908.py | 10 +- hc/api/migrations/0052_auto_20190104_1122.py | 14 +- hc/api/migrations/0053_check_subject.py | 10 +- hc/api/migrations/0054_auto_20190112_1427.py | 24 +- hc/api/migrations/0055_auto_20190112_1427.py | 8 +- hc/api/migrations/0056_auto_20190114_0857.py | 20 +- hc/api/migrations/0057_auto_20190118_1319.py | 14 +- hc/api/migrations/0058_auto_20190312_1716.py | 32 +- hc/api/migrations/0059_auto_20190314_1744.py | 33 +- hc/api/migrations/0060_tokenbucket.py | 24 +- hc/api/models.py | 71 ++-- hc/api/schemas.py | 6 +- hc/api/tests/__init__.py | 4 +- hc/api/tests/test_admin.py | 11 +- hc/api/tests/test_badge.py | 1 - hc/api/tests/test_bounce.py | 1 - hc/api/tests/test_check_going_down_after.py | 1 - hc/api/tests/test_check_model.py | 1 - hc/api/tests/test_create_check.py | 132 ++++--- hc/api/tests/test_delete_check.py | 6 +- hc/api/tests/test_list_channels.py | 9 +- hc/api/tests/test_list_checks.py | 15 +- hc/api/tests/test_notify.py | 59 ++- hc/api/tests/test_pause.py | 26 +- hc/api/tests/test_ping.py | 34 +- hc/api/tests/test_sendalerts.py | 4 +- hc/api/tests/test_sendreports.py | 1 - hc/api/tests/test_tokenbucket.py | 1 - hc/api/tests/test_update_check.py | 60 ++- hc/api/transports.py | 72 ++-- hc/api/urls.py | 64 +-- hc/api/views.py | 17 +- hc/front/forms.py | 30 +- hc/front/management/commands/pygmentize.py | 3 +- hc/front/schemas.py | 10 +- hc/front/templatetags/hc_extras.py | 10 +- hc/front/tests/test_add_discord.py | 5 +- hc/front/tests/test_add_pushover.py | 4 +- hc/front/tests/test_add_slack_btn.py | 14 +- hc/front/tests/test_add_telegram.py | 32 +- hc/front/tests/test_add_trello.py | 16 +- hc/front/tests/test_add_webhook.py | 26 +- hc/front/tests/test_badges.py | 1 - hc/front/tests/test_basics.py | 1 - hc/front/tests/test_channel_checks.py | 1 - hc/front/tests/test_channels.py | 30 +- hc/front/tests/test_cron_preview.py | 17 +- hc/front/tests/test_details.py | 1 - hc/front/tests/test_hc_extras.py | 3 +- hc/front/tests/test_log.py | 10 +- hc/front/tests/test_my_checks.py | 1 - hc/front/tests/test_pause.py | 1 - hc/front/tests/test_ping_details.py | 1 - hc/front/tests/test_remove_channel.py | 1 - hc/front/tests/test_remove_check.py | 1 - hc/front/tests/test_send_test_notification.py | 1 - hc/front/tests/test_status.py | 1 - hc/front/tests/test_status_single.py | 1 - hc/front/tests/test_switch_channel.py | 6 +- hc/front/tests/test_transfer.py | 6 +- hc/front/tests/test_unsubscribe_email.py | 4 +- hc/front/tests/test_update_channel.py | 18 +- hc/front/tests/test_update_channel_name.py | 1 - hc/front/tests/test_update_name.py | 1 - hc/front/tests/test_update_timeout.py | 31 +- hc/front/tests/test_verify_email.py | 1 - hc/front/urls.py | 113 +++--- hc/front/views.py | 365 +++++++++--------- hc/lib/badges.py | 82 +++- hc/lib/emails.py | 19 +- hc/lib/jsonschema.py | 3 +- hc/lib/tests/test_badges.py | 1 - hc/lib/tests/test_date.py | 1 - hc/lib/tests/test_jsonschema.py | 41 +- hc/payments/admin.py | 35 +- hc/payments/context_processors.py | 2 +- hc/payments/invoices.py | 4 +- hc/payments/migrations/0001_initial.py | 34 +- .../migrations/0002_subscription_plan_id.py | 10 +- .../0003_subscription_address_id.py | 10 +- .../0004_subscription_send_invoices.py | 10 +- .../migrations/0005_subscription_plan_name.py | 10 +- .../0006_subscription_invoice_email.py | 10 +- hc/payments/models.py | 68 ++-- hc/payments/tests/test_address.py | 1 - hc/payments/tests/test_billing.py | 1 - hc/payments/tests/test_billing_history.py | 1 - hc/payments/tests/test_charge_webhook.py | 1 - hc/payments/tests/test_get_client_token.py | 1 - hc/payments/tests/test_payment_method.py | 1 - hc/payments/tests/test_pdf_invoice.py | 1 - hc/payments/tests/test_pricing.py | 1 - hc/payments/tests/test_set_plan.py | 1 - hc/payments/urls.py | 54 +-- hc/payments/views.py | 22 +- hc/settings.py | 135 +++---- hc/test.py | 1 - hc/urls.py | 26 +- 207 files changed, 2053 insertions(+), 1921 deletions(-) diff --git a/hc/accounts/admin.py b/hc/accounts/admin.py index 8aaf0de8..a7422583 100644 --- a/hc/accounts/admin.py +++ b/hc/accounts/admin.py @@ -20,35 +20,58 @@ class Fieldset: class ProfileFieldset(Fieldset): name = "User Profile" - fields = ("email", "current_project", "reports_allowed", - "next_report_date", "nag_period", "next_nag_date", - "deletion_notice_date", - "token", "sort") + fields = ( + "email", + "current_project", + "reports_allowed", + "next_report_date", + "nag_period", + "next_nag_date", + "deletion_notice_date", + "token", + "sort", + ) class TeamFieldset(Fieldset): name = "Team" - fields = ("team_limit", "check_limit", "ping_log_limit", "sms_limit", - "sms_sent", "last_sms_date") + fields = ( + "team_limit", + "check_limit", + "ping_log_limit", + "sms_limit", + "sms_sent", + "last_sms_date", + ) @admin.register(Profile) class ProfileAdmin(admin.ModelAdmin): - class Media: - css = { - 'all': ('css/admin/profiles.css',) - } + css = {"all": ("css/admin/profiles.css",)} readonly_fields = ("user", "email") - raw_id_fields = ("current_project", ) + raw_id_fields = ("current_project",) search_fields = ["id", "user__email"] list_per_page = 50 - list_select_related = ("user", ) - list_display = ("id", "email", "engagement", "date_joined", "last_login", - "projects", "invited", "sms", "reports_allowed") - list_filter = ("user__date_joined", "user__last_login", - "reports_allowed", "check_limit") + list_select_related = ("user",) + list_display = ( + "id", + "email", + "engagement", + "date_joined", + "last_login", + "projects", + "invited", + "sms", + "reports_allowed", + ) + list_filter = ( + "user__date_joined", + "user__last_login", + "reports_allowed", + "check_limit", + ) fieldsets = (ProfileFieldset.tuple(), TeamFieldset.tuple()) @@ -83,23 +106,21 @@ class ProfileAdmin(admin.ModelAdmin): @mark_safe def email(self, obj): - s = escape(obj.user.email) - if obj.plan: - return "%s" % (obj.plan, s) + s = escape(obj.user.email) + if obj.plan: + return "%s" % (obj.plan, s) - return s + return s def last_login(self, obj): - return obj.user.last_login + return obj.user.last_login def date_joined(self, obj): - return obj.user.date_joined + return obj.user.date_joined @mark_safe def projects(self, obj): - return render_to_string("admin/profile_list_projects.html", { - "profile": obj - }) + return render_to_string("admin/profile_list_projects.html", {"profile": obj}) def invited(self, obj): return "%d of %d" % (obj.num_members, obj.team_limit) @@ -111,14 +132,12 @@ class ProfileAdmin(admin.ModelAdmin): @admin.register(Project) class ProjectAdmin(admin.ModelAdmin): readonly_fields = ("code", "owner") - list_select_related = ("owner", ) + list_select_related = ("owner",) list_display = ("id", "name_", "users", "engagement", "switch") search_fields = ["id", "name", "owner__email"] class Media: - css = { - 'all': ('css/admin/projects.css',) - } + css = {"all": ("css/admin/projects.css",)} def get_queryset(self, request): qs = super(ProjectAdmin, self).get_queryset(request) @@ -138,9 +157,7 @@ class ProjectAdmin(admin.ModelAdmin): if obj.num_members == 0: return obj.owner.email else: - return render_to_string("admin/project_list_team.html", { - "project": obj - }) + return render_to_string("admin/project_list_team.html", {"project": obj}) def email(self, obj): return obj.owner.email @@ -173,8 +190,14 @@ class ProjectAdmin(admin.ModelAdmin): class HcUserAdmin(UserAdmin): actions = ["send_report"] - list_display = ('id', 'email', 'engagement', 'date_joined', 'last_login', - 'is_staff') + list_display = ( + "id", + "email", + "engagement", + "date_joined", + "last_login", + "is_staff", + ) list_display_links = ("id", "email") list_filter = ("last_login", "date_joined", "is_staff", "is_active") diff --git a/hc/accounts/backends.py b/hc/accounts/backends.py index 9818ab81..f9c74d6c 100644 --- a/hc/accounts/backends.py +++ b/hc/accounts/backends.py @@ -3,11 +3,9 @@ from hc.accounts.models import Profile class BasicBackend(object): - def get_user(self, user_id): try: - q = User.objects.select_related("profile", - "profile__current_project") + q = User.objects.select_related("profile", "profile__current_project") return q.get(pk=user_id) except User.DoesNotExist: @@ -16,7 +14,6 @@ class BasicBackend(object): # Authenticate against the token in user's profile. class ProfileBackend(BasicBackend): - def authenticate(self, request=None, username=None, token=None): try: profiles = Profile.objects.select_related("user") @@ -31,7 +28,6 @@ class ProfileBackend(BasicBackend): class EmailBackend(BasicBackend): - def authenticate(self, request=None, username=None, password=None): try: user = User.objects.get(email=username) diff --git a/hc/accounts/forms.py b/hc/accounts/forms.py index 8c12789c..c62e3246 100644 --- a/hc/accounts/forms.py +++ b/hc/accounts/forms.py @@ -6,7 +6,6 @@ from hc.api.models import TokenBucket class LowercaseEmailField(forms.EmailField): - def clean(self, value): value = super(LowercaseEmailField, self).clean(value) return value.lower() @@ -15,12 +14,16 @@ class LowercaseEmailField(forms.EmailField): class AvailableEmailForm(forms.Form): # Call it "identity" instead of "email" # to avoid some of the dumber bots - identity = LowercaseEmailField(error_messages={'required': 'Please enter your email address.'}) + identity = LowercaseEmailField( + error_messages={"required": "Please enter your email address."} + ) def clean_identity(self): v = self.cleaned_data["identity"] if User.objects.filter(email=v).exists(): - raise forms.ValidationError("An account with this email address already exists.") + raise forms.ValidationError( + "An account with this email address already exists." + ) return v @@ -48,8 +51,8 @@ class PasswordLoginForm(forms.Form): password = forms.CharField() def clean(self): - username = self.cleaned_data.get('email') - password = self.cleaned_data.get('password') + username = self.cleaned_data.get("email") + password = self.cleaned_data.get("password") if username and password: if not TokenBucket.authorize_login_password(username): diff --git a/hc/accounts/management/commands/senddeletionnotices.py b/hc/accounts/management/commands/senddeletionnotices.py index cd344ec1..9a664ee1 100644 --- a/hc/accounts/management/commands/senddeletionnotices.py +++ b/hc/accounts/management/commands/senddeletionnotices.py @@ -51,10 +51,7 @@ class Command(BaseCommand): profile.deletion_notice_date = now() profile.save() - ctx = { - "email": profile.user.email, - "support_email": settings.SUPPORT_EMAIL - } + ctx = {"email": profile.user.email, "support_email": settings.SUPPORT_EMAIL} emails.deletion_notice(profile.user.email, ctx) # Throttle so we don't send too many emails at once: time.sleep(1) diff --git a/hc/accounts/migrations/0001_initial.py b/hc/accounts/migrations/0001_initial.py index 1a85801e..c1c46387 100644 --- a/hc/accounts/migrations/0001_initial.py +++ b/hc/accounts/migrations/0001_initial.py @@ -7,18 +7,32 @@ from django.conf import settings class Migration(migrations.Migration): - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] + dependencies = [migrations.swappable_dependency(settings.AUTH_USER_MODEL)] operations = [ migrations.CreateModel( - name='Profile', + name="Profile", fields=[ - ('id', models.AutoField(auto_created=True, serialize=False, verbose_name='ID', primary_key=True)), - ('next_report_date', models.DateTimeField(null=True, blank=True)), - ('reports_allowed', models.BooleanField(default=True)), - ('user', models.OneToOneField(blank=True, to=settings.AUTH_USER_MODEL, null=True, on_delete=models.CASCADE)), + ( + "id", + models.AutoField( + auto_created=True, + serialize=False, + verbose_name="ID", + primary_key=True, + ), + ), + ("next_report_date", models.DateTimeField(null=True, blank=True)), + ("reports_allowed", models.BooleanField(default=True)), + ( + "user", + models.OneToOneField( + blank=True, + to=settings.AUTH_USER_MODEL, + null=True, + on_delete=models.CASCADE, + ), + ), ], - ), + ) ] diff --git a/hc/accounts/migrations/0002_profile_ping_log_limit.py b/hc/accounts/migrations/0002_profile_ping_log_limit.py index 5c2fd48f..0bdffe36 100644 --- a/hc/accounts/migrations/0002_profile_ping_log_limit.py +++ b/hc/accounts/migrations/0002_profile_ping_log_limit.py @@ -6,14 +6,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0001_initial'), - ] + dependencies = [("accounts", "0001_initial")] operations = [ migrations.AddField( - model_name='profile', - name='ping_log_limit', + model_name="profile", + name="ping_log_limit", field=models.IntegerField(default=100), - ), + ) ] diff --git a/hc/accounts/migrations/0003_profile_token.py b/hc/accounts/migrations/0003_profile_token.py index 02f19ca9..b5933224 100644 --- a/hc/accounts/migrations/0003_profile_token.py +++ b/hc/accounts/migrations/0003_profile_token.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0002_profile_ping_log_limit'), - ] + dependencies = [("accounts", "0002_profile_ping_log_limit")] operations = [ migrations.AddField( - model_name='profile', - name='token', + model_name="profile", + name="token", field=models.CharField(blank=True, max_length=128), - ), + ) ] diff --git a/hc/accounts/migrations/0004_profile_api_key.py b/hc/accounts/migrations/0004_profile_api_key.py index 9ca4ed66..a704ffb9 100644 --- a/hc/accounts/migrations/0004_profile_api_key.py +++ b/hc/accounts/migrations/0004_profile_api_key.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0003_profile_token'), - ] + dependencies = [("accounts", "0003_profile_token")] operations = [ migrations.AddField( - model_name='profile', - name='api_key', + model_name="profile", + name="api_key", field=models.CharField(blank=True, max_length=128), - ), + ) ] diff --git a/hc/accounts/migrations/0005_auto_20160509_0801.py b/hc/accounts/migrations/0005_auto_20160509_0801.py index 63dbb184..b755622a 100644 --- a/hc/accounts/migrations/0005_auto_20160509_0801.py +++ b/hc/accounts/migrations/0005_auto_20160509_0801.py @@ -11,34 +11,46 @@ class Migration(migrations.Migration): dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('accounts', '0004_profile_api_key'), + ("accounts", "0004_profile_api_key"), ] operations = [ migrations.CreateModel( - name='Member', + name="Member", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ) ], ), migrations.AddField( - model_name='profile', - name='team_access_allowed', + model_name="profile", + name="team_access_allowed", field=models.BooleanField(default=False), ), migrations.AddField( - model_name='profile', - name='team_name', + model_name="profile", + name="team_name", field=models.CharField(blank=True, max_length=200), ), migrations.AddField( - model_name='member', - name='team', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='accounts.Profile'), + model_name="member", + name="team", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="accounts.Profile" + ), ), migrations.AddField( - model_name='member', - name='user', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + model_name="member", + name="user", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL + ), ), ] diff --git a/hc/accounts/migrations/0006_profile_current_team.py b/hc/accounts/migrations/0006_profile_current_team.py index 40cf933f..4ab623e4 100644 --- a/hc/accounts/migrations/0006_profile_current_team.py +++ b/hc/accounts/migrations/0006_profile_current_team.py @@ -8,14 +8,16 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0005_auto_20160509_0801'), - ] + dependencies = [("accounts", "0005_auto_20160509_0801")] operations = [ migrations.AddField( - model_name='profile', - name='current_team', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='accounts.Profile'), - ), + model_name="profile", + name="current_team", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="accounts.Profile", + ), + ) ] diff --git a/hc/accounts/migrations/0007_profile_check_limit.py b/hc/accounts/migrations/0007_profile_check_limit.py index 8436c3b2..10dbd387 100644 --- a/hc/accounts/migrations/0007_profile_check_limit.py +++ b/hc/accounts/migrations/0007_profile_check_limit.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0006_profile_current_team'), - ] + dependencies = [("accounts", "0006_profile_current_team")] operations = [ migrations.AddField( - model_name='profile', - name='check_limit', + model_name="profile", + name="check_limit", field=models.IntegerField(default=20), - ), + ) ] diff --git a/hc/accounts/migrations/0008_profile_bill_to.py b/hc/accounts/migrations/0008_profile_bill_to.py index e2d492f9..95d2345b 100644 --- a/hc/accounts/migrations/0008_profile_bill_to.py +++ b/hc/accounts/migrations/0008_profile_bill_to.py @@ -7,14 +7,10 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0007_profile_check_limit'), - ] + dependencies = [("accounts", "0007_profile_check_limit")] operations = [ migrations.AddField( - model_name='profile', - name='bill_to', - field=models.TextField(blank=True), - ), + model_name="profile", name="bill_to", field=models.TextField(blank=True) + ) ] diff --git a/hc/accounts/migrations/0009_auto_20170714_1734.py b/hc/accounts/migrations/0009_auto_20170714_1734.py index 4805ecd3..07e21ed5 100644 --- a/hc/accounts/migrations/0009_auto_20170714_1734.py +++ b/hc/accounts/migrations/0009_auto_20170714_1734.py @@ -7,24 +7,18 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0008_profile_bill_to'), - ] + dependencies = [("accounts", "0008_profile_bill_to")] operations = [ migrations.AddField( - model_name='profile', - name='last_sms_date', + model_name="profile", + name="last_sms_date", field=models.DateTimeField(blank=True, null=True), ), migrations.AddField( - model_name='profile', - name='sms_limit', - field=models.IntegerField(default=0), + model_name="profile", name="sms_limit", field=models.IntegerField(default=0) ), migrations.AddField( - model_name='profile', - name='sms_sent', - field=models.IntegerField(default=0), + model_name="profile", name="sms_sent", field=models.IntegerField(default=0) ), ] diff --git a/hc/accounts/migrations/0010_profile_team_limit.py b/hc/accounts/migrations/0010_profile_team_limit.py index 299fd031..4282a730 100644 --- a/hc/accounts/migrations/0010_profile_team_limit.py +++ b/hc/accounts/migrations/0010_profile_team_limit.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0009_auto_20170714_1734'), - ] + dependencies = [("accounts", "0009_auto_20170714_1734")] operations = [ migrations.AddField( - model_name='profile', - name='team_limit', + model_name="profile", + name="team_limit", field=models.IntegerField(default=2), - ), + ) ] diff --git a/hc/accounts/migrations/0011_profile_sort.py b/hc/accounts/migrations/0011_profile_sort.py index 31c6133f..289aa787 100644 --- a/hc/accounts/migrations/0011_profile_sort.py +++ b/hc/accounts/migrations/0011_profile_sort.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0010_profile_team_limit'), - ] + dependencies = [("accounts", "0010_profile_team_limit")] operations = [ migrations.AddField( - model_name='profile', - name='sort', - field=models.CharField(default='created', max_length=20), - ), + model_name="profile", + name="sort", + field=models.CharField(default="created", max_length=20), + ) ] diff --git a/hc/accounts/migrations/0012_auto_20171014_1002.py b/hc/accounts/migrations/0012_auto_20171014_1002.py index 22174fc6..e2e0c736 100644 --- a/hc/accounts/migrations/0012_auto_20171014_1002.py +++ b/hc/accounts/migrations/0012_auto_20171014_1002.py @@ -8,19 +8,24 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0011_profile_sort'), - ] + dependencies = [("accounts", "0011_profile_sort")] operations = [ migrations.AddField( - model_name='profile', - name='nag_period', - field=models.DurationField(choices=[(datetime.timedelta(0), 'Disabled'), (datetime.timedelta(0, 3600), 'Hourly'), (datetime.timedelta(1), 'Daily')], default=datetime.timedelta(0)), + model_name="profile", + name="nag_period", + field=models.DurationField( + choices=[ + (datetime.timedelta(0), "Disabled"), + (datetime.timedelta(0, 3600), "Hourly"), + (datetime.timedelta(1), "Daily"), + ], + default=datetime.timedelta(0), + ), ), migrations.AddField( - model_name='profile', - name='next_nag_date', + model_name="profile", + name="next_nag_date", field=models.DateTimeField(blank=True, null=True), ), ] diff --git a/hc/accounts/migrations/0013_remove_profile_team_access_allowed.py b/hc/accounts/migrations/0013_remove_profile_team_access_allowed.py index 9915269a..caaa6833 100644 --- a/hc/accounts/migrations/0013_remove_profile_team_access_allowed.py +++ b/hc/accounts/migrations/0013_remove_profile_team_access_allowed.py @@ -7,13 +7,8 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0012_auto_20171014_1002'), - ] + dependencies = [("accounts", "0012_auto_20171014_1002")] operations = [ - migrations.RemoveField( - model_name='profile', - name='team_access_allowed', - ), + migrations.RemoveField(model_name="profile", name="team_access_allowed") ] diff --git a/hc/accounts/migrations/0014_auto_20171227_1530.py b/hc/accounts/migrations/0014_auto_20171227_1530.py index daadefa9..53613570 100644 --- a/hc/accounts/migrations/0014_auto_20171227_1530.py +++ b/hc/accounts/migrations/0014_auto_20171227_1530.py @@ -9,14 +9,16 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0013_remove_profile_team_access_allowed'), - ] + dependencies = [("accounts", "0013_remove_profile_team_access_allowed")] operations = [ migrations.AlterField( - model_name='member', - name='user', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='memberships', to=settings.AUTH_USER_MODEL), - ), + model_name="member", + name="user", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="memberships", + to=settings.AUTH_USER_MODEL, + ), + ) ] diff --git a/hc/accounts/migrations/0015_auto_20181029_1858.py b/hc/accounts/migrations/0015_auto_20181029_1858.py index ae8327cc..bb720b48 100644 --- a/hc/accounts/migrations/0015_auto_20181029_1858.py +++ b/hc/accounts/migrations/0015_auto_20181029_1858.py @@ -5,19 +5,17 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0014_auto_20171227_1530'), - ] + dependencies = [("accounts", "0014_auto_20171227_1530")] operations = [ migrations.AddField( - model_name='profile', - name='api_key_id', + model_name="profile", + name="api_key_id", field=models.CharField(blank=True, max_length=128), ), migrations.AddField( - model_name='profile', - name='api_key_readonly', + model_name="profile", + name="api_key_readonly", field=models.CharField(blank=True, max_length=128), ), ] diff --git a/hc/accounts/migrations/0016_remove_profile_bill_to.py b/hc/accounts/migrations/0016_remove_profile_bill_to.py index a3ffe9e2..3021ad3f 100644 --- a/hc/accounts/migrations/0016_remove_profile_bill_to.py +++ b/hc/accounts/migrations/0016_remove_profile_bill_to.py @@ -5,13 +5,6 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0015_auto_20181029_1858'), - ] + dependencies = [("accounts", "0015_auto_20181029_1858")] - operations = [ - migrations.RemoveField( - model_name='profile', - name='bill_to', - ), - ] + operations = [migrations.RemoveField(model_name="profile", name="bill_to")] diff --git a/hc/accounts/migrations/0017_auto_20190112_1426.py b/hc/accounts/migrations/0017_auto_20190112_1426.py index 4ef23c5d..bb2fb2b6 100644 --- a/hc/accounts/migrations/0017_auto_20190112_1426.py +++ b/hc/accounts/migrations/0017_auto_20190112_1426.py @@ -10,29 +10,54 @@ class Migration(migrations.Migration): dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('accounts', '0016_remove_profile_bill_to'), + ("accounts", "0016_remove_profile_bill_to"), ] operations = [ migrations.CreateModel( - name='Project', + name="Project", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('code', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)), - ('name', models.CharField(blank=True, max_length=200)), - ('api_key', models.CharField(blank=True, max_length=128)), - ('api_key_readonly', models.CharField(blank=True, max_length=128)), - ('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "code", + models.UUIDField(default=uuid.uuid4, editable=False, unique=True), + ), + ("name", models.CharField(blank=True, max_length=200)), + ("api_key", models.CharField(blank=True, max_length=128)), + ("api_key_readonly", models.CharField(blank=True, max_length=128)), + ( + "owner", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), ], ), migrations.AddField( - model_name='member', - name='project', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='accounts.Project'), + model_name="member", + name="project", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="accounts.Project", + ), ), migrations.AddField( - model_name='profile', - name='current_project', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='accounts.Project'), + model_name="profile", + name="current_project", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="accounts.Project", + ), ), ] diff --git a/hc/accounts/migrations/0018_auto_20190112_1426.py b/hc/accounts/migrations/0018_auto_20190112_1426.py index e1d80f10..6817e1f7 100644 --- a/hc/accounts/migrations/0018_auto_20190112_1426.py +++ b/hc/accounts/migrations/0018_auto_20190112_1426.py @@ -28,10 +28,6 @@ def create_projects(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0017_auto_20190112_1426'), - ] + dependencies = [("accounts", "0017_auto_20190112_1426")] - operations = [ - migrations.RunPython(create_projects, migrations.RunPython.noop), - ] + operations = [migrations.RunPython(create_projects, migrations.RunPython.noop)] diff --git a/hc/accounts/migrations/0019_project_badge_key.py b/hc/accounts/migrations/0019_project_badge_key.py index 645918f6..14a5828b 100644 --- a/hc/accounts/migrations/0019_project_badge_key.py +++ b/hc/accounts/migrations/0019_project_badge_key.py @@ -5,14 +5,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0018_auto_20190112_1426'), - ] + dependencies = [("accounts", "0018_auto_20190112_1426")] operations = [ migrations.AddField( - model_name='project', - name='badge_key', + model_name="project", + name="badge_key", field=models.CharField(blank=True, max_length=150, null=True), - ), + ) ] diff --git a/hc/accounts/migrations/0020_auto_20190112_1950.py b/hc/accounts/migrations/0020_auto_20190112_1950.py index 6e6ebe3f..a781a190 100644 --- a/hc/accounts/migrations/0020_auto_20190112_1950.py +++ b/hc/accounts/migrations/0020_auto_20190112_1950.py @@ -12,10 +12,6 @@ def set_badge_key(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0019_project_badge_key'), - ] + dependencies = [("accounts", "0019_project_badge_key")] - operations = [ - migrations.RunPython(set_badge_key, migrations.RunPython.noop), - ] + operations = [migrations.RunPython(set_badge_key, migrations.RunPython.noop)] diff --git a/hc/accounts/migrations/0021_auto_20190112_2005.py b/hc/accounts/migrations/0021_auto_20190112_2005.py index bda9ed3c..0a9056fc 100644 --- a/hc/accounts/migrations/0021_auto_20190112_2005.py +++ b/hc/accounts/migrations/0021_auto_20190112_2005.py @@ -5,14 +5,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0020_auto_20190112_1950'), - ] + dependencies = [("accounts", "0020_auto_20190112_1950")] operations = [ migrations.AlterField( - model_name='project', - name='badge_key', + model_name="project", + name="badge_key", field=models.CharField(max_length=150, unique=True), - ), + ) ] diff --git a/hc/accounts/migrations/0022_auto_20190114_0857.py b/hc/accounts/migrations/0022_auto_20190114_0857.py index 290ffd81..6a5257f5 100644 --- a/hc/accounts/migrations/0022_auto_20190114_0857.py +++ b/hc/accounts/migrations/0022_auto_20190114_0857.py @@ -6,14 +6,14 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0021_auto_20190112_2005'), - ] + dependencies = [("accounts", "0021_auto_20190112_2005")] operations = [ migrations.AlterField( - model_name='member', - name='project', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='accounts.Project'), - ), + model_name="member", + name="project", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="accounts.Project" + ), + ) ] diff --git a/hc/accounts/migrations/0023_auto_20190117_1419.py b/hc/accounts/migrations/0023_auto_20190117_1419.py index 26c264f0..e4e954ac 100644 --- a/hc/accounts/migrations/0023_auto_20190117_1419.py +++ b/hc/accounts/migrations/0023_auto_20190117_1419.py @@ -5,21 +5,10 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0022_auto_20190114_0857'), - ] + dependencies = [("accounts", "0022_auto_20190114_0857")] operations = [ - migrations.RemoveField( - model_name='profile', - name='api_key', - ), - migrations.RemoveField( - model_name='profile', - name='api_key_id', - ), - migrations.RemoveField( - model_name='profile', - name='api_key_readonly', - ), + migrations.RemoveField(model_name="profile", name="api_key"), + migrations.RemoveField(model_name="profile", name="api_key_id"), + migrations.RemoveField(model_name="profile", name="api_key_readonly"), ] diff --git a/hc/accounts/migrations/0024_auto_20190119_1540.py b/hc/accounts/migrations/0024_auto_20190119_1540.py index 1d78032c..4718920e 100644 --- a/hc/accounts/migrations/0024_auto_20190119_1540.py +++ b/hc/accounts/migrations/0024_auto_20190119_1540.py @@ -5,17 +5,9 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0023_auto_20190117_1419'), - ] + dependencies = [("accounts", "0023_auto_20190117_1419")] operations = [ - migrations.RemoveField( - model_name='profile', - name='current_team', - ), - migrations.RemoveField( - model_name='profile', - name='team_name', - ), + migrations.RemoveField(model_name="profile", name="current_team"), + migrations.RemoveField(model_name="profile", name="team_name"), ] diff --git a/hc/accounts/migrations/0025_remove_member_team.py b/hc/accounts/migrations/0025_remove_member_team.py index 402d9bbc..5549403a 100644 --- a/hc/accounts/migrations/0025_remove_member_team.py +++ b/hc/accounts/migrations/0025_remove_member_team.py @@ -5,13 +5,6 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0024_auto_20190119_1540'), - ] + dependencies = [("accounts", "0024_auto_20190119_1540")] - operations = [ - migrations.RemoveField( - model_name='member', - name='team', - ), - ] + operations = [migrations.RemoveField(model_name="member", name="team")] diff --git a/hc/accounts/migrations/0026_auto_20190204_2042.py b/hc/accounts/migrations/0026_auto_20190204_2042.py index af423112..cb640177 100644 --- a/hc/accounts/migrations/0026_auto_20190204_2042.py +++ b/hc/accounts/migrations/0026_auto_20190204_2042.py @@ -6,24 +6,22 @@ import uuid class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0025_remove_member_team'), - ] + dependencies = [("accounts", "0025_remove_member_team")] operations = [ migrations.AlterField( - model_name='project', - name='api_key', + model_name="project", + name="api_key", field=models.CharField(blank=True, db_index=True, max_length=128), ), migrations.AlterField( - model_name='project', - name='api_key_readonly', + model_name="project", + name="api_key_readonly", field=models.CharField(blank=True, db_index=True, max_length=128), ), migrations.AlterField( - model_name='project', - name='code', + model_name="project", + name="code", field=models.UUIDField(default=uuid.uuid4, unique=True), ), ] diff --git a/hc/accounts/migrations/0027_profile_deletion_notice_date.py b/hc/accounts/migrations/0027_profile_deletion_notice_date.py index 939a9b0e..93800573 100644 --- a/hc/accounts/migrations/0027_profile_deletion_notice_date.py +++ b/hc/accounts/migrations/0027_profile_deletion_notice_date.py @@ -5,14 +5,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('accounts', '0026_auto_20190204_2042'), - ] + dependencies = [("accounts", "0026_auto_20190204_2042")] operations = [ migrations.AddField( - model_name='profile', - name='deletion_notice_date', + model_name="profile", + name="deletion_notice_date", field=models.DateTimeField(blank=True, null=True), - ), + ) ] diff --git a/hc/accounts/models.py b/hc/accounts/models.py index 03da63e1..db35b2b5 100644 --- a/hc/accounts/models.py +++ b/hc/accounts/models.py @@ -15,9 +15,11 @@ from hc.lib import emails NO_NAG = timedelta() -NAG_PERIODS = ((NO_NAG, "Disabled"), - (timedelta(hours=1), "Hourly"), - (timedelta(days=1), "Daily")) +NAG_PERIODS = ( + (NO_NAG, "Disabled"), + (timedelta(hours=1), "Hourly"), + (timedelta(days=1), "Daily"), +) def month(dt): @@ -90,26 +92,20 @@ class Profile(models.Model): ctx = { "button_text": "Sign In", "button_url": settings.SITE_ROOT + path, - "inviting_project": inviting_project + "inviting_project": inviting_project, } emails.login(self.user.email, ctx) def send_set_password_link(self): token = self.prepare_token("set-password") path = reverse("hc-set-password", args=[token]) - ctx = { - "button_text": "Set Password", - "button_url": settings.SITE_ROOT + path - } + ctx = {"button_text": "Set Password", "button_url": settings.SITE_ROOT + path} emails.set_password(self.user.email, ctx) def send_change_email_link(self): token = self.prepare_token("change-email") path = reverse("hc-change-email", args=[token]) - ctx = { - "button_text": "Change Email", - "button_url": settings.SITE_ROOT + path - } + ctx = {"button_text": "Change Email", "button_url": settings.SITE_ROOT + path} emails.change_email(self.user.email, ctx) def projects(self): @@ -140,6 +136,7 @@ class Profile(models.Model): project_ids = self.projects().values("id") from hc.api.models import Check + return Check.objects.filter(project_id__in=project_ids) def send_report(self, nag=False): @@ -168,10 +165,7 @@ class Profile(models.Model): unsub_url = self.reports_unsub_url() - headers = { - "List-Unsubscribe": unsub_url, - "X-Bounce-Url": unsub_url - } + headers = {"List-Unsubscribe": unsub_url, "X-Bounce-Url": unsub_url} ctx = { "checks": checks, @@ -181,7 +175,7 @@ class Profile(models.Model): "notifications_url": self.notifications_url(), "nag": nag, "nag_period": self.nag_period.total_seconds(), - "num_down": num_down + "num_down": num_down, } emails.report(self.user.email, ctx, headers) @@ -228,6 +222,7 @@ class Project(models.Model): def num_checks_available(self): from hc.api.models import Check + num_used = Check.objects.filter(project__owner=self.owner).count() return self.owner_profile.check_limit - num_used diff --git a/hc/accounts/tests/test_add_project.py b/hc/accounts/tests/test_add_project.py index 93198678..3e5709c1 100644 --- a/hc/accounts/tests/test_add_project.py +++ b/hc/accounts/tests/test_add_project.py @@ -3,7 +3,6 @@ from hc.test import BaseTestCase class RemoveProjectTestCase(BaseTestCase): - def setUp(self): super(RemoveProjectTestCase, self).setUp() diff --git a/hc/accounts/tests/test_admin.py b/hc/accounts/tests/test_admin.py index 48fb6691..05b13075 100644 --- a/hc/accounts/tests/test_admin.py +++ b/hc/accounts/tests/test_admin.py @@ -2,7 +2,6 @@ from hc.test import BaseTestCase class AccountsAdminTestCase(BaseTestCase): - def setUp(self): super(AccountsAdminTestCase, self).setUp() diff --git a/hc/accounts/tests/test_change_email.py b/hc/accounts/tests/test_change_email.py index a5ad15eb..a4aee609 100644 --- a/hc/accounts/tests/test_change_email.py +++ b/hc/accounts/tests/test_change_email.py @@ -4,7 +4,6 @@ from hc.test import BaseTestCase class ChangeEmailTestCase(BaseTestCase): - def test_it_shows_form(self): self.profile.token = make_password("foo", "change-email") self.profile.save() diff --git a/hc/accounts/tests/test_check_token.py b/hc/accounts/tests/test_check_token.py index 2921540b..5e38593e 100644 --- a/hc/accounts/tests/test_check_token.py +++ b/hc/accounts/tests/test_check_token.py @@ -3,7 +3,6 @@ from hc.test import BaseTestCase class CheckTokenTestCase(BaseTestCase): - def setUp(self): super(CheckTokenTestCase, self).setUp() self.profile.token = make_password("secret-token", "login") diff --git a/hc/accounts/tests/test_close_account.py b/hc/accounts/tests/test_close_account.py index a02666a7..f9f94350 100644 --- a/hc/accounts/tests/test_close_account.py +++ b/hc/accounts/tests/test_close_account.py @@ -6,7 +6,6 @@ from mock import patch class CloseAccountTestCase(BaseTestCase): - @patch("hc.payments.models.Subscription.cancel") def test_it_works(self, mock_cancel): Check.objects.create(project=self.project, tags="foo a-B_1 baz@") diff --git a/hc/accounts/tests/test_login.py b/hc/accounts/tests/test_login.py index cd4b1351..73c53705 100644 --- a/hc/accounts/tests/test_login.py +++ b/hc/accounts/tests/test_login.py @@ -6,7 +6,6 @@ from hc.test import BaseTestCase class LoginTestCase(BaseTestCase): - def setUp(self): super(LoginTestCase, self).setUp() self.checks_url = "/projects/%s/checks/" % self.project.code @@ -63,11 +62,7 @@ class LoginTestCase(BaseTestCase): self.assertIn("login", self.profile.token) def test_it_handles_password(self): - form = { - "action": "login", - "email": "alice@example.org", - "password": "password" - } + form = {"action": "login", "email": "alice@example.org", "password": "password"} r = self.client.post("/accounts/login/", form) self.assertRedirects(r, self.checks_url) @@ -79,11 +74,7 @@ class LoginTestCase(BaseTestCase): obj.tokens = 0 obj.save() - form = { - "action": "login", - "email": "alice@example.org", - "password": "password" - } + form = {"action": "login", "email": "alice@example.org", "password": "password"} r = self.client.post("/accounts/login/", form) self.assertContains(r, "Too many attempts") @@ -91,27 +82,16 @@ class LoginTestCase(BaseTestCase): def test_it_handles_password_login_with_redirect(self): check = Check.objects.create(project=self.project) - form = { - "action": "login", - "email": "alice@example.org", - "password": "password" - } + form = {"action": "login", "email": "alice@example.org", "password": "password"} - samples = [ - "/integrations/add_slack/", - "/checks/%s/details/" % check.code - ] + samples = ["/integrations/add_slack/", "/checks/%s/details/" % check.code] for s in samples: r = self.client.post("/accounts/login/?next=%s" % s, form) self.assertRedirects(r, s) def test_it_handles_bad_next_parameter(self): - form = { - "action": "login", - "email": "alice@example.org", - "password": "password" - } + form = {"action": "login", "email": "alice@example.org", "password": "password"} r = self.client.post("/accounts/login/?next=/evil/", form) self.assertRedirects(r, self.checks_url) @@ -120,7 +100,7 @@ class LoginTestCase(BaseTestCase): form = { "action": "login", "email": "alice@example.org", - "password": "wrong password" + "password": "wrong password", } r = self.client.post("/accounts/login/", form) diff --git a/hc/accounts/tests/test_notifications.py b/hc/accounts/tests/test_notifications.py index 33744bc4..29ba9cd7 100644 --- a/hc/accounts/tests/test_notifications.py +++ b/hc/accounts/tests/test_notifications.py @@ -5,7 +5,6 @@ from hc.test import BaseTestCase class NotificationsTestCase(BaseTestCase): - def test_it_saves_reports_allowed_true(self): self.profile.reports_allowed = False self.profile.save() diff --git a/hc/accounts/tests/test_profile.py b/hc/accounts/tests/test_profile.py index 88a29483..36281bf5 100644 --- a/hc/accounts/tests/test_profile.py +++ b/hc/accounts/tests/test_profile.py @@ -8,7 +8,6 @@ from hc.api.models import Check class ProfileTestCase(BaseTestCase): - def test_it_sends_set_password_link(self): self.client.login(username="alice@example.org", password="password") @@ -38,7 +37,7 @@ class ProfileTestCase(BaseTestCase): self.assertEqual(len(mail.outbox), 1) message = mail.outbox[0] - self.assertEqual(message.subject, 'Monthly Report') + self.assertEqual(message.subject, "Monthly Report") self.assertIn("Test Check", message.body) def test_it_skips_report_if_no_pings(self): @@ -76,7 +75,7 @@ class ProfileTestCase(BaseTestCase): self.assertEqual(len(mail.outbox), 1) message = mail.outbox[0] - self.assertEqual(message.subject, 'Reminder: 1 check still down') + self.assertEqual(message.subject, "Reminder: 1 check still down") self.assertIn("Test Check", message.body) def test_it_skips_nag_if_none_down(self): diff --git a/hc/accounts/tests/test_project.py b/hc/accounts/tests/test_project.py index 101d8f56..7bc1e3e4 100644 --- a/hc/accounts/tests/test_project.py +++ b/hc/accounts/tests/test_project.py @@ -72,8 +72,9 @@ class ProjectTestCase(BaseTestCase): members = self.project.member_set.all() self.assertEqual(members.count(), 2) - member = Member.objects.get(project=self.project, - user__email="frank@example.org") + member = Member.objects.get( + project=self.project, user__email="frank@example.org" + ) profile = member.user.profile self.assertEqual(profile.current_project, self.project) @@ -81,8 +82,10 @@ class ProjectTestCase(BaseTestCase): self.assertFalse(member.user.project_set.exists()) # And an email should have been sent - subj = ("You have been invited to join" - " Alice's Project on %s" % settings.SITE_NAME) + subj = ( + "You have been invited to join" + " Alice's Project on %s" % settings.SITE_NAME + ) self.assertEqual(mail.outbox[0].subject, subj) @override_settings(SECRET_KEY="test-secret") diff --git a/hc/accounts/tests/test_project_model.py b/hc/accounts/tests/test_project_model.py index 4869d064..d6202a14 100644 --- a/hc/accounts/tests/test_project_model.py +++ b/hc/accounts/tests/test_project_model.py @@ -4,7 +4,6 @@ from hc.api.models import Check class ProjectModelTestCase(BaseTestCase): - def test_num_checks_available_handles_multiple_projects(self): # One check in Alice's primary project: Check.objects.create(project=self.project) diff --git a/hc/accounts/tests/test_remove_project.py b/hc/accounts/tests/test_remove_project.py index 2faf6627..73842529 100644 --- a/hc/accounts/tests/test_remove_project.py +++ b/hc/accounts/tests/test_remove_project.py @@ -3,7 +3,6 @@ from hc.test import BaseTestCase class RemoveProjectTestCase(BaseTestCase): - def setUp(self): super(RemoveProjectTestCase, self).setUp() diff --git a/hc/accounts/tests/test_set_password.py b/hc/accounts/tests/test_set_password.py index a8a247db..a53cb354 100644 --- a/hc/accounts/tests/test_set_password.py +++ b/hc/accounts/tests/test_set_password.py @@ -2,7 +2,6 @@ from hc.test import BaseTestCase class SetPasswordTestCase(BaseTestCase): - def test_it_shows_form(self): token = self.profile.prepare_token("set-password") diff --git a/hc/accounts/tests/test_signup.py b/hc/accounts/tests/test_signup.py index fbca78a0..1458c9f7 100644 --- a/hc/accounts/tests/test_signup.py +++ b/hc/accounts/tests/test_signup.py @@ -8,7 +8,6 @@ from django.conf import settings class SignupTestCase(TestCase): - def test_it_sends_link(self): form = {"identity": "alice@example.org"} diff --git a/hc/accounts/tests/test_team_access_middleware.py b/hc/accounts/tests/test_team_access_middleware.py index 4f9ba90d..3cfb04ef 100644 --- a/hc/accounts/tests/test_team_access_middleware.py +++ b/hc/accounts/tests/test_team_access_middleware.py @@ -4,7 +4,6 @@ from hc.accounts.models import Profile class TeamAccessMiddlewareTestCase(TestCase): - def test_it_handles_missing_profile(self): user = User(username="ned", email="ned@example.org") user.set_password("password") diff --git a/hc/accounts/tests/test_unsubscribe_reports.py b/hc/accounts/tests/test_unsubscribe_reports.py index 37e982ba..2cba8964 100644 --- a/hc/accounts/tests/test_unsubscribe_reports.py +++ b/hc/accounts/tests/test_unsubscribe_reports.py @@ -6,7 +6,6 @@ from hc.test import BaseTestCase class UnsubscribeReportsTestCase(BaseTestCase): - def test_it_unsubscribes(self): self.profile.next_report_date = now() self.profile.nag_period = td(hours=1) diff --git a/hc/accounts/urls.py b/hc/accounts/urls.py index 02dbd8ed..f5e417aa 100644 --- a/hc/accounts/urls.py +++ b/hc/accounts/urls.py @@ -2,32 +2,25 @@ from django.urls import path from hc.accounts import views urlpatterns = [ - path('login/', views.login, name="hc-login"), - path('logout/', views.logout, name="hc-logout"), - path('signup/', views.signup, name="hc-signup"), - path('login_link_sent/', - views.login_link_sent, name="hc-login-link-sent"), - - path('link_sent/', - views.link_sent, name="hc-link-sent"), - - path('check_token///', - views.check_token, name="hc-check-token"), - - path('profile/', views.profile, name="hc-profile"), - path('profile/notifications/', views.notifications, name="hc-notifications"), - path('close/', views.close, name="hc-close"), - - path('unsubscribe_reports//', - views.unsubscribe_reports, name="hc-unsubscribe-reports"), - - path('set_password//', - views.set_password, name="hc-set-password"), - - path('change_email/done/', - views.change_email_done, name="hc-change-email-done"), - - path('change_email//', - views.change_email, name="hc-change-email"), - + path("login/", views.login, name="hc-login"), + path("logout/", views.logout, name="hc-logout"), + path("signup/", views.signup, name="hc-signup"), + path("login_link_sent/", views.login_link_sent, name="hc-login-link-sent"), + path("link_sent/", views.link_sent, name="hc-link-sent"), + path( + "check_token///", + views.check_token, + name="hc-check-token", + ), + path("profile/", views.profile, name="hc-profile"), + path("profile/notifications/", views.notifications, name="hc-notifications"), + path("close/", views.close, name="hc-close"), + path( + "unsubscribe_reports//", + views.unsubscribe_reports, + name="hc-unsubscribe-reports", + ), + path("set_password//", views.set_password, name="hc-set-password"), + path("change_email/done/", views.change_email_done, name="hc-change-email-done"), + path("change_email//", views.change_email, name="hc-change-email"), ] diff --git a/hc/accounts/views.py b/hc/accounts/views.py index 6a5eb46e..0b037197 100644 --- a/hc/accounts/views.py +++ b/hc/accounts/views.py @@ -9,28 +9,39 @@ from django.contrib.auth import authenticate from django.contrib.auth.decorators import login_required from django.contrib.auth.models import User from django.core import signing -from django.http import (HttpResponseForbidden, HttpResponseBadRequest, - HttpResponseNotFound) +from django.http import ( + HttpResponseForbidden, + HttpResponseBadRequest, + HttpResponseNotFound, +) from django.shortcuts import get_object_or_404, redirect, render from django.utils.timezone import now from django.urls import resolve, Resolver404 from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_POST -from hc.accounts.forms import (ChangeEmailForm, PasswordLoginForm, - InviteTeamMemberForm, RemoveTeamMemberForm, - ReportSettingsForm, SetPasswordForm, - ProjectNameForm, AvailableEmailForm, - EmailLoginForm) +from hc.accounts.forms import ( + ChangeEmailForm, + PasswordLoginForm, + InviteTeamMemberForm, + RemoveTeamMemberForm, + ReportSettingsForm, + SetPasswordForm, + ProjectNameForm, + AvailableEmailForm, + EmailLoginForm, +) from hc.accounts.models import Profile, Project, Member from hc.api.models import Channel, Check, TokenBucket from hc.payments.models import Subscription -NEXT_WHITELIST = ("hc-checks", - "hc-details", - "hc-log", - "hc-channels", - "hc-add-slack", - "hc-add-pushover") +NEXT_WHITELIST = ( + "hc-checks", + "hc-details", + "hc-log", + "hc-channels", + "hc-add-slack", + "hc-add-pushover", +) def _is_whitelisted(path): @@ -92,7 +103,7 @@ def login(request): form = PasswordLoginForm() magic_form = EmailLoginForm() - if request.method == 'POST': + if request.method == "POST": if request.POST.get("action") == "login": form = PasswordLoginForm(request.POST) if form.is_valid(): @@ -115,7 +126,7 @@ def login(request): "page": "login", "form": form, "magic_form": magic_form, - "bad_link": bad_link + "bad_link": bad_link, } return render(request, "accounts/login.html", ctx) @@ -182,11 +193,7 @@ def check_token(request, username, token): def profile(request): profile = request.profile - ctx = { - "page": "profile", - "profile": profile, - "my_projects_status": "default" - } + ctx = {"page": "profile", "profile": profile, "my_projects_status": "default"} if request.method == "POST": if "change_email" in request.POST: @@ -198,8 +205,7 @@ def profile(request): elif "leave_project" in request.POST: code = request.POST["code"] try: - project = Project.objects.get(code=code, - member__user=request.user) + project = Project.objects.get(code=code, member__user=request.user) except Project.DoesNotExist: return HttpResponseBadRequest() @@ -253,7 +259,7 @@ def project(request, code): "show_api_keys": "show_api_keys" in request.GET, "project_name_status": "default", "api_status": "default", - "team_status": "default" + "team_status": "default", } if request.method == "POST": @@ -308,8 +314,7 @@ def project(request, code): farewell_user.profile.current_project = None farewell_user.profile.save() - Member.objects.filter(project=project, - user=farewell_user).delete() + Member.objects.filter(project=project, user=farewell_user).delete() ctx["team_member_removed"] = form.cleaned_data["email"] ctx["team_status"] = "info" @@ -335,11 +340,7 @@ def project(request, code): def notifications(request): profile = request.profile - ctx = { - "status": "default", - "page": "profile", - "profile": profile - } + ctx = {"status": "default", "page": "profile", "profile": profile} if request.method == "POST": form = ReportSettingsForm(request.POST) diff --git a/hc/api/admin.py b/hc/api/admin.py index d7494be5..6d51b47a 100644 --- a/hc/api/admin.py +++ b/hc/api/admin.py @@ -9,18 +9,23 @@ from hc.lib.date import format_duration @admin.register(Check) class ChecksAdmin(admin.ModelAdmin): - class Media: - css = { - 'all': ('css/admin/checks.css',) - } + css = {"all": ("css/admin/checks.css",)} search_fields = ["name", "code", "project__owner__email"] - raw_id_fields = ("project", ) - list_display = ("id", "name_tags", "email", "created", "n_pings", - "timeout_schedule", "status", "last_start", "last_ping") - list_filter = ("status", "kind", "last_ping", - "last_start") + raw_id_fields = ("project",) + list_display = ( + "id", + "name_tags", + "email", + "created", + "n_pings", + "timeout_schedule", + "status", + "last_start", + "last_ping", + ) + list_filter = ("status", "kind", "last_ping", "last_start") actions = ["send_alert"] @@ -60,14 +65,10 @@ class ChecksAdmin(admin.ModelAdmin): class SchemeListFilter(admin.SimpleListFilter): title = "Scheme" - parameter_name = 'scheme' + parameter_name = "scheme" def lookups(self, request, model_admin): - return ( - ('http', "HTTP"), - ('https', "HTTPS"), - ('email', "Email"), - ) + return (("http", "HTTP"), ("https", "HTTPS"), ("email", "Email")) def queryset(self, request, queryset): if self.value(): @@ -77,7 +78,7 @@ class SchemeListFilter(admin.SimpleListFilter): class MethodListFilter(admin.SimpleListFilter): title = "Method" - parameter_name = 'method' + parameter_name = "method" methods = ["HEAD", "GET", "POST", "PUT", "DELETE"] def lookups(self, request, model_admin): @@ -91,7 +92,7 @@ class MethodListFilter(admin.SimpleListFilter): class KindListFilter(admin.SimpleListFilter): title = "Kind" - parameter_name = 'kind' + parameter_name = "kind" kinds = ["start", "fail"] def lookups(self, request, model_admin): @@ -112,8 +113,10 @@ class LargeTablePaginator(Paginator): def _get_estimate(self): try: cursor = connection.cursor() - cursor.execute("SELECT reltuples FROM pg_class WHERE relname = %s", - [self.object_list.query.model._meta.db_table]) + cursor.execute( + "SELECT reltuples FROM pg_class WHERE relname = %s", + [self.object_list.query.model._meta.db_table], + ) return int(cursor.fetchone()[0]) except: return 0 @@ -138,18 +141,17 @@ class LargeTablePaginator(Paginator): # (i.e. is of type list). self._count = len(self.object_list) return self._count + count = property(_get_count) @admin.register(Ping) class PingsAdmin(admin.ModelAdmin): search_fields = ("owner__name", "owner__code") - readonly_fields = ("owner", ) - list_select_related = ("owner", ) - list_display = ("id", "created", "owner", "scheme", "method", - "ua") - list_filter = ("created", SchemeListFilter, MethodListFilter, - KindListFilter) + readonly_fields = ("owner",) + list_select_related = ("owner",) + list_display = ("id", "created", "owner", "scheme", "method", "ua") + list_filter = ("created", SchemeListFilter, MethodListFilter, KindListFilter) paginator = LargeTablePaginator show_full_result_count = False @@ -158,15 +160,19 @@ class PingsAdmin(admin.ModelAdmin): @admin.register(Channel) class ChannelsAdmin(admin.ModelAdmin): class Media: - css = { - 'all': ('css/admin/channels.css',) - } + css = {"all": ("css/admin/channels.css",)} search_fields = ["value", "project__owner__email"] - list_display = ("id", "name", "email", "formatted_kind", "value", - "num_notifications") - list_filter = ("kind", ) - raw_id_fields = ("project", "checks", ) + list_display = ( + "id", + "name", + "email", + "formatted_kind", + "value", + "num_notifications", + ) + list_filter = ("kind",) + raw_id_fields = ("project", "checks") def get_queryset(self, request): qs = super().get_queryset(request) @@ -196,8 +202,14 @@ class ChannelsAdmin(admin.ModelAdmin): class NotificationsAdmin(admin.ModelAdmin): search_fields = ["owner__name", "owner__code", "channel__value"] list_select_related = ("owner", "channel") - list_display = ("id", "created", "check_status", "owner", - "channel_kind", "channel_value") + list_display = ( + "id", + "created", + "check_status", + "owner", + "channel_kind", + "channel_value", + ) list_filter = ("created", "check_status", "channel__kind") def channel_kind(self, obj): @@ -209,6 +221,5 @@ class NotificationsAdmin(admin.ModelAdmin): @admin.register(Flip) class FlipsAdmin(admin.ModelAdmin): - list_display = ("id", "created", "processed", "owner", "old_status", - "new_status") - raw_id_fields = ("owner", ) + list_display = ("id", "created", "processed", "owner", "old_status", "new_status") + raw_id_fields = ("owner",) diff --git a/hc/api/decorators.py b/hc/api/decorators.py index 939e1056..bf6c5718 100644 --- a/hc/api/decorators.py +++ b/hc/api/decorators.py @@ -28,6 +28,7 @@ def authorize(f): return error("wrong api key", 401) return f(request, *args, **kwds) + return wrapper @@ -50,6 +51,7 @@ def authorize_read(f): return error("wrong api key", 401) return f(request, *args, **kwds) + return wrapper @@ -80,7 +82,9 @@ def validate_json(schema=None): return error("json validation error: %s" % e) return f(request, *args, **kwds) + return wrapper + return decorator @@ -106,4 +110,5 @@ def cors(*methods): return response return wrapper + return decorator diff --git a/hc/api/management/commands/prunenotifications.py b/hc/api/management/commands/prunenotifications.py index dcdcf40b..3c50cfca 100644 --- a/hc/api/management/commands/prunenotifications.py +++ b/hc/api/management/commands/prunenotifications.py @@ -5,7 +5,7 @@ from hc.api.models import Notification, Check class Command(BaseCommand): - help = 'Prune stored notifications' + help = "Prune stored notifications" def handle(self, *args, **options): total = 0 @@ -13,8 +13,9 @@ class Command(BaseCommand): q = Check.objects.filter(n_pings__gt=100) q = q.annotate(min_ping_date=Min("ping__created")) for check in q: - qq = Notification.objects.filter(owner_id=check.id, - created__lt=check.min_ping_date) + qq = Notification.objects.filter( + owner_id=check.id, created__lt=check.min_ping_date + ) num_deleted, _ = qq.delete() total += num_deleted diff --git a/hc/api/management/commands/prunepings.py b/hc/api/management/commands/prunepings.py index 7a233001..a0688cde 100644 --- a/hc/api/management/commands/prunepings.py +++ b/hc/api/management/commands/prunepings.py @@ -6,7 +6,7 @@ from hc.api.models import Ping class Command(BaseCommand): - help = 'Prune pings based on limits in user profiles' + help = "Prune pings based on limits in user profiles" def handle(self, *args, **options): # Create any missing user profiles diff --git a/hc/api/management/commands/prunepingsslow.py b/hc/api/management/commands/prunepingsslow.py index c1700412..20b10c1c 100644 --- a/hc/api/management/commands/prunepingsslow.py +++ b/hc/api/management/commands/prunepingsslow.py @@ -29,7 +29,8 @@ class Command(BaseCommand): q = q.filter(n__gt=0) n_pruned, _ = q.delete() - self.stdout.write("Pruned %d pings for check %s (%s)" % - (n_pruned, check.id, check.name)) + self.stdout.write( + "Pruned %d pings for check %s (%s)" % (n_pruned, check.id, check.name) + ) return "Done!" diff --git a/hc/api/management/commands/prunetokenbucket.py b/hc/api/management/commands/prunetokenbucket.py index 23044a22..7f04d7e8 100644 --- a/hc/api/management/commands/prunetokenbucket.py +++ b/hc/api/management/commands/prunetokenbucket.py @@ -6,7 +6,7 @@ from hc.api.models import TokenBucket class Command(BaseCommand): - help = 'Prune pings based on limits in user profiles' + help = "Prune pings based on limits in user profiles" def handle(self, *args, **options): diff --git a/hc/api/management/commands/sendalerts.py b/hc/api/management/commands/sendalerts.py index 001cf82a..0e81e338 100644 --- a/hc/api/management/commands/sendalerts.py +++ b/hc/api/management/commands/sendalerts.py @@ -35,23 +35,23 @@ def notify_on_thread(flip_id, stdout): class Command(BaseCommand): - help = 'Sends UP/DOWN email alerts' + help = "Sends UP/DOWN email alerts" def add_arguments(self, parser): parser.add_argument( - '--no-loop', - action='store_false', - dest='loop', + "--no-loop", + action="store_false", + dest="loop", default=True, - help='Do not keep running indefinitely in a 2 second wait loop', + help="Do not keep running indefinitely in a 2 second wait loop", ) parser.add_argument( - '--no-threads', - action='store_false', - dest='use_threads', + "--no-threads", + action="store_false", + dest="use_threads", default=False, - help='Send alerts synchronously, without using threads', + help="Send alerts synchronously, without using threads", ) def process_one_flip(self, use_threads=True): diff --git a/hc/api/management/commands/sendreports.py b/hc/api/management/commands/sendreports.py index bcb421cc..3b5e2467 100644 --- a/hc/api/management/commands/sendreports.py +++ b/hc/api/management/commands/sendreports.py @@ -9,13 +9,13 @@ from hc.api.models import Check def num_pinged_checks(profile): - q = Check.objects.filter(user_id=profile.user.id,) + q = Check.objects.filter(user_id=profile.user.id) q = q.filter(last_ping__isnull=False) return q.count() class Command(BaseCommand): - help = 'Send due monthly reports and nags' + help = "Send due monthly reports and nags" tmpl = "Sent monthly report to %s" def pause(self): @@ -23,11 +23,11 @@ class Command(BaseCommand): def add_arguments(self, parser): parser.add_argument( - '--loop', - action='store_true', - dest='loop', + "--loop", + action="store_true", + dest="loop", default=False, - help='Keep running indefinitely in a 300 second wait loop', + help="Keep running indefinitely in a 300 second wait loop", ) def handle_one_monthly_report(self): @@ -48,8 +48,9 @@ class Command(BaseCommand): # A sort of optimistic lock. Try to update next_report_date, # and if does get modified, we're in drivers seat: - qq = Profile.objects.filter(id=profile.id, - next_report_date=profile.next_report_date) + qq = Profile.objects.filter( + id=profile.id, next_report_date=profile.next_report_date + ) num_updated = qq.update(next_report_date=month_after) if num_updated != 1: @@ -72,8 +73,7 @@ class Command(BaseCommand): if profile is None: return False - qq = Profile.objects.filter(id=profile.id, - next_nag_date=profile.next_nag_date) + qq = Profile.objects.filter(id=profile.id, next_nag_date=profile.next_nag_date) num_updated = qq.update(next_nag_date=now + profile.nag_period) if num_updated != 1: diff --git a/hc/api/management/commands/settelegramwebhook.py b/hc/api/management/commands/settelegramwebhook.py index f0f668be..da86d676 100644 --- a/hc/api/management/commands/settelegramwebhook.py +++ b/hc/api/management/commands/settelegramwebhook.py @@ -16,7 +16,7 @@ class Command(BaseCommand): form = { "url": settings.SITE_ROOT + reverse("hc-telegram-webhook"), - "allowed_updates": ["message"] + "allowed_updates": ["message"], } url = SETWEBHOOK_TMPL % settings.TELEGRAM_TOKEN diff --git a/hc/api/management/commands/smtpd.py b/hc/api/management/commands/smtpd.py index bebb83f8..8b894053 100644 --- a/hc/api/management/commands/smtpd.py +++ b/hc/api/management/commands/smtpd.py @@ -7,7 +7,9 @@ from django.core.management.base import BaseCommand from django.db import connections from hc.api.models import Check -RE_UUID = re.compile("^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[8|9|aA|bB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$") +RE_UUID = re.compile( + "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[8|9|aA|bB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$" +) class Listener(SMTPServer): @@ -15,7 +17,9 @@ class Listener(SMTPServer): self.stdout = stdout super(Listener, self).__init__(localaddr, None, decode_data=False) - def process_message(self, peer, mailfrom, rcpttos, data, mail_options=None, rcpt_options=None): + def process_message( + self, peer, mailfrom, rcpttos, data, mail_options=None, rcpt_options=None + ): # get a new db connection in case the old one has timed out: connections.close_all() @@ -53,13 +57,12 @@ class Command(BaseCommand): help = "Listen for ping emails" def add_arguments(self, parser): - parser.add_argument("--host", - help="ip address to listen on, default 0.0.0.0", - default="0.0.0.0") - parser.add_argument('--port', - help="port to listen on, default 25", - type=int, - default=25) + parser.add_argument( + "--host", help="ip address to listen on, default 0.0.0.0", default="0.0.0.0" + ) + parser.add_argument( + "--port", help="port to listen on, default 25", type=int, default=25 + ) def handle(self, host, port, *args, **options): listener = Listener((host, port), self.stdout) diff --git a/hc/api/migrations/0001_initial.py b/hc/api/migrations/0001_initial.py index 084a1b40..35a7ef42 100644 --- a/hc/api/migrations/0001_initial.py +++ b/hc/api/migrations/0001_initial.py @@ -8,18 +8,29 @@ from django.conf import settings class Migration(migrations.Migration): - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] + dependencies = [migrations.swappable_dependency(settings.AUTH_USER_MODEL)] operations = [ migrations.CreateModel( - name='Check', + name="Check", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, verbose_name='ID', serialize=False)), - ('code', models.UUIDField(default=uuid.uuid4, editable=False)), - ('last_ping', models.DateTimeField(null=True, blank=True)), - ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + verbose_name="ID", + serialize=False, + ), + ), + ("code", models.UUIDField(default=uuid.uuid4, editable=False)), + ("last_ping", models.DateTimeField(null=True, blank=True)), + ( + "user", + models.ForeignKey( + to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE + ), + ), ], - ), + ) ] diff --git a/hc/api/migrations/0002_auto_20150616_0732.py b/hc/api/migrations/0002_auto_20150616_0732.py index 2b3881e5..6ad0bc2c 100644 --- a/hc/api/migrations/0002_auto_20150616_0732.py +++ b/hc/api/migrations/0002_auto_20150616_0732.py @@ -7,29 +7,44 @@ import datetime class Migration(migrations.Migration): - dependencies = [ - ('api', '0001_initial'), - ] + dependencies = [("api", "0001_initial")] operations = [ migrations.AddField( - model_name='check', - name='alert_after', + model_name="check", + name="alert_after", field=models.DateTimeField(null=True, blank=True), ), migrations.AddField( - model_name='check', - name='enabled', - field=models.BooleanField(default=True), + model_name="check", name="enabled", field=models.BooleanField(default=True) ), migrations.AddField( - model_name='check', - name='status', - field=models.CharField(max_length=6, choices=[('up', 'Up'), ('down', 'Down'), ('new', 'New')], default='new'), + model_name="check", + name="status", + field=models.CharField( + max_length=6, + choices=[("up", "Up"), ("down", "Down"), ("new", "New")], + default="new", + ), ), migrations.AddField( - model_name='check', - name='timeout', - field=models.DurationField(choices=[(datetime.timedelta(0, 300), '5 minutes'), (datetime.timedelta(0, 600), '10 minutes'), (datetime.timedelta(0, 1800), '30 minutes'), (datetime.timedelta(0, 3600), '1 hour'), (datetime.timedelta(0, 7200), '2 hours'), (datetime.timedelta(0, 21600), '6 hours'), (datetime.timedelta(0, 43200), '12 hours'), (datetime.timedelta(1), '1 day'), (datetime.timedelta(2), '2 days'), (datetime.timedelta(7), '1 week'), (datetime.timedelta(14), '2 weeks')], default=datetime.timedelta(1)), + model_name="check", + name="timeout", + field=models.DurationField( + choices=[ + (datetime.timedelta(0, 300), "5 minutes"), + (datetime.timedelta(0, 600), "10 minutes"), + (datetime.timedelta(0, 1800), "30 minutes"), + (datetime.timedelta(0, 3600), "1 hour"), + (datetime.timedelta(0, 7200), "2 hours"), + (datetime.timedelta(0, 21600), "6 hours"), + (datetime.timedelta(0, 43200), "12 hours"), + (datetime.timedelta(1), "1 day"), + (datetime.timedelta(2), "2 days"), + (datetime.timedelta(7), "1 week"), + (datetime.timedelta(14), "2 weeks"), + ], + default=datetime.timedelta(1), + ), ), ] diff --git a/hc/api/migrations/0003_auto_20150616_1249.py b/hc/api/migrations/0003_auto_20150616_1249.py index 6a9706e0..dc39c7cd 100644 --- a/hc/api/migrations/0003_auto_20150616_1249.py +++ b/hc/api/migrations/0003_auto_20150616_1249.py @@ -7,24 +7,22 @@ import datetime class Migration(migrations.Migration): - dependencies = [ - ('api', '0002_auto_20150616_0732'), - ] + dependencies = [("api", "0002_auto_20150616_0732")] operations = [ migrations.AddField( - model_name='check', - name='name', + model_name="check", + name="name", field=models.CharField(max_length=100, blank=True), ), migrations.AlterField( - model_name='check', - name='alert_after', + model_name="check", + name="alert_after", field=models.DateTimeField(editable=False, null=True, blank=True), ), migrations.AlterField( - model_name='check', - name='timeout', + model_name="check", + name="timeout", field=models.DurationField(default=datetime.timedelta(1)), ), ] diff --git a/hc/api/migrations/0004_auto_20150616_1319.py b/hc/api/migrations/0004_auto_20150616_1319.py index 756c9fd2..1790ca9b 100644 --- a/hc/api/migrations/0004_auto_20150616_1319.py +++ b/hc/api/migrations/0004_auto_20150616_1319.py @@ -8,19 +8,17 @@ import datetime class Migration(migrations.Migration): - dependencies = [ - ('api', '0003_auto_20150616_1249'), - ] + dependencies = [("api", "0003_auto_20150616_1249")] operations = [ - migrations.RemoveField( - model_name='check', - name='enabled', - ), + migrations.RemoveField(model_name="check", name="enabled"), migrations.AddField( - model_name='check', - name='created', - field=models.DateTimeField(auto_now_add=True, default=datetime.datetime(2015, 6, 16, 13, 19, 17, 218278, tzinfo=utc)), + model_name="check", + name="created", + field=models.DateTimeField( + auto_now_add=True, + default=datetime.datetime(2015, 6, 16, 13, 19, 17, 218278, tzinfo=utc), + ), preserve_default=False, ), ] diff --git a/hc/api/migrations/0005_auto_20150630_2021.py b/hc/api/migrations/0005_auto_20150630_2021.py index 40ec1533..3e977444 100644 --- a/hc/api/migrations/0005_auto_20150630_2021.py +++ b/hc/api/migrations/0005_auto_20150630_2021.py @@ -7,14 +7,17 @@ from django.conf import settings class Migration(migrations.Migration): - dependencies = [ - ('api', '0004_auto_20150616_1319'), - ] + dependencies = [("api", "0004_auto_20150616_1319")] operations = [ migrations.AlterField( - model_name='check', - name='user', - field=models.ForeignKey(blank=True, to=settings.AUTH_USER_MODEL, null=True, on_delete=models.CASCADE), - ), + model_name="check", + name="user", + field=models.ForeignKey( + blank=True, + to=settings.AUTH_USER_MODEL, + null=True, + on_delete=models.CASCADE, + ), + ) ] diff --git a/hc/api/migrations/0006_check_grace.py b/hc/api/migrations/0006_check_grace.py index c5180359..1ab35ab8 100644 --- a/hc/api/migrations/0006_check_grace.py +++ b/hc/api/migrations/0006_check_grace.py @@ -7,14 +7,12 @@ import datetime class Migration(migrations.Migration): - dependencies = [ - ('api', '0005_auto_20150630_2021'), - ] + dependencies = [("api", "0005_auto_20150630_2021")] operations = [ migrations.AddField( - model_name='check', - name='grace', + model_name="check", + name="grace", field=models.DurationField(default=datetime.timedelta(0, 3600)), - ), + ) ] diff --git a/hc/api/migrations/0007_ping.py b/hc/api/migrations/0007_ping.py index 9ead6d13..c543b44c 100644 --- a/hc/api/migrations/0007_ping.py +++ b/hc/api/migrations/0007_ping.py @@ -6,21 +6,27 @@ from django.db import models, migrations class Migration(migrations.Migration): - dependencies = [ - ('api', '0006_check_grace'), - ] + dependencies = [("api", "0006_check_grace")] operations = [ migrations.CreateModel( - name='Ping', + name="Ping", fields=[ - ('id', models.AutoField(primary_key=True, serialize=False, auto_created=True, verbose_name='ID')), - ('created', models.DateTimeField(auto_now_add=True)), - ('remote_addr', models.GenericIPAddressField()), - ('method', models.CharField(max_length=10)), - ('ua', models.CharField(max_length=100, blank=True)), - ('body', models.TextField(blank=True)), - ('owner', models.ForeignKey(to='api.Check', on_delete=models.CASCADE)), + ( + "id", + models.AutoField( + primary_key=True, + serialize=False, + auto_created=True, + verbose_name="ID", + ), + ), + ("created", models.DateTimeField(auto_now_add=True)), + ("remote_addr", models.GenericIPAddressField()), + ("method", models.CharField(max_length=10)), + ("ua", models.CharField(max_length=100, blank=True)), + ("body", models.TextField(blank=True)), + ("owner", models.ForeignKey(to="api.Check", on_delete=models.CASCADE)), ], - ), + ) ] diff --git a/hc/api/migrations/0008_auto_20150801_1213.py b/hc/api/migrations/0008_auto_20150801_1213.py index 3858cbac..667cbbac 100644 --- a/hc/api/migrations/0008_auto_20150801_1213.py +++ b/hc/api/migrations/0008_auto_20150801_1213.py @@ -6,14 +6,12 @@ from django.db import models, migrations class Migration(migrations.Migration): - dependencies = [ - ('api', '0007_ping'), - ] + dependencies = [("api", "0007_ping")] operations = [ migrations.AlterField( - model_name='ping', - name='ua', + model_name="ping", + name="ua", field=models.CharField(max_length=200, blank=True), - ), + ) ] diff --git a/hc/api/migrations/0009_auto_20150801_1250.py b/hc/api/migrations/0009_auto_20150801_1250.py index e2c0f33f..3bac185e 100644 --- a/hc/api/migrations/0009_auto_20150801_1250.py +++ b/hc/api/migrations/0009_auto_20150801_1250.py @@ -6,24 +6,22 @@ from django.db import models, migrations class Migration(migrations.Migration): - dependencies = [ - ('api', '0008_auto_20150801_1213'), - ] + dependencies = [("api", "0008_auto_20150801_1213")] operations = [ migrations.AddField( - model_name='ping', - name='scheme', - field=models.CharField(max_length=10, default='http'), + model_name="ping", + name="scheme", + field=models.CharField(max_length=10, default="http"), ), migrations.AlterField( - model_name='ping', - name='method', + model_name="ping", + name="method", field=models.CharField(blank=True, max_length=10), ), migrations.AlterField( - model_name='ping', - name='remote_addr', + model_name="ping", + name="remote_addr", field=models.GenericIPAddressField(blank=True, null=True), ), ] diff --git a/hc/api/migrations/0010_channel.py b/hc/api/migrations/0010_channel.py index 4e03edb0..a36ea5f5 100644 --- a/hc/api/migrations/0010_channel.py +++ b/hc/api/migrations/0010_channel.py @@ -10,21 +10,44 @@ class Migration(migrations.Migration): dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('api', '0009_auto_20150801_1250'), + ("api", "0009_auto_20150801_1250"), ] operations = [ migrations.CreateModel( - name='Channel', + name="Channel", fields=[ - ('id', models.AutoField(primary_key=True, auto_created=True, verbose_name='ID', serialize=False)), - ('code', models.UUIDField(editable=False, default=uuid.uuid4)), - ('created', models.DateTimeField(auto_now_add=True)), - ('kind', models.CharField(choices=[('email', 'Email'), ('webhook', 'Webhook'), ('pd', 'PagerDuty')], max_length=20)), - ('value', models.CharField(max_length=200, blank=True)), - ('email_verified', models.BooleanField(default=False)), - ('checks', models.ManyToManyField(to='api.Check')), - ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)), + ( + "id", + models.AutoField( + primary_key=True, + auto_created=True, + verbose_name="ID", + serialize=False, + ), + ), + ("code", models.UUIDField(editable=False, default=uuid.uuid4)), + ("created", models.DateTimeField(auto_now_add=True)), + ( + "kind", + models.CharField( + choices=[ + ("email", "Email"), + ("webhook", "Webhook"), + ("pd", "PagerDuty"), + ], + max_length=20, + ), + ), + ("value", models.CharField(max_length=200, blank=True)), + ("email_verified", models.BooleanField(default=False)), + ("checks", models.ManyToManyField(to="api.Check")), + ( + "user", + models.ForeignKey( + to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE + ), + ), ], - ), + ) ] diff --git a/hc/api/migrations/0011_notification.py b/hc/api/migrations/0011_notification.py index 7557363f..63cd2ae2 100644 --- a/hc/api/migrations/0011_notification.py +++ b/hc/api/migrations/0011_notification.py @@ -6,20 +6,29 @@ from django.db import models, migrations class Migration(migrations.Migration): - dependencies = [ - ('api', '0010_channel'), - ] + dependencies = [("api", "0010_channel")] operations = [ migrations.CreateModel( - name='Notification', + name="Notification", fields=[ - ('id', models.AutoField(serialize=False, auto_created=True, verbose_name='ID', primary_key=True)), - ('check_status', models.CharField(max_length=6)), - ('created', models.DateTimeField(auto_now_add=True)), - ('status', models.IntegerField(default=0)), - ('channel', models.ForeignKey(to='api.Channel', on_delete=models.CASCADE)), - ('owner', models.ForeignKey(to='api.Check', on_delete=models.CASCADE)), + ( + "id", + models.AutoField( + serialize=False, + auto_created=True, + verbose_name="ID", + primary_key=True, + ), + ), + ("check_status", models.CharField(max_length=6)), + ("created", models.DateTimeField(auto_now_add=True)), + ("status", models.IntegerField(default=0)), + ( + "channel", + models.ForeignKey(to="api.Channel", on_delete=models.CASCADE), + ), + ("owner", models.ForeignKey(to="api.Check", on_delete=models.CASCADE)), ], - ), + ) ] diff --git a/hc/api/migrations/0012_auto_20150930_1922.py b/hc/api/migrations/0012_auto_20150930_1922.py index a84b65d5..21130212 100644 --- a/hc/api/migrations/0012_auto_20150930_1922.py +++ b/hc/api/migrations/0012_auto_20150930_1922.py @@ -6,14 +6,20 @@ from django.db import models, migrations class Migration(migrations.Migration): - dependencies = [ - ('api', '0011_notification'), - ] + dependencies = [("api", "0011_notification")] operations = [ migrations.AlterField( - model_name='channel', - name='kind', - field=models.CharField(choices=[('email', 'Email'), ('webhook', 'Webhook'), ('slack', 'Slack'), ('pd', 'PagerDuty')], max_length=20), - ), + model_name="channel", + name="kind", + field=models.CharField( + choices=[ + ("email", "Email"), + ("webhook", "Webhook"), + ("slack", "Slack"), + ("pd", "PagerDuty"), + ], + max_length=20, + ), + ) ] diff --git a/hc/api/migrations/0013_auto_20151001_2029.py b/hc/api/migrations/0013_auto_20151001_2029.py index 8a045cd4..c9d52a7e 100644 --- a/hc/api/migrations/0013_auto_20151001_2029.py +++ b/hc/api/migrations/0013_auto_20151001_2029.py @@ -6,14 +6,21 @@ from django.db import models, migrations class Migration(migrations.Migration): - dependencies = [ - ('api', '0012_auto_20150930_1922'), - ] + dependencies = [("api", "0012_auto_20150930_1922")] operations = [ migrations.AlterField( - model_name='channel', - name='kind', - field=models.CharField(max_length=20, choices=[('email', 'Email'), ('webhook', 'Webhook'), ('hipchat', 'HipChat'), ('slack', 'Slack'), ('pd', 'PagerDuty')]), - ), + model_name="channel", + name="kind", + field=models.CharField( + max_length=20, + choices=[ + ("email", "Email"), + ("webhook", "Webhook"), + ("hipchat", "HipChat"), + ("slack", "Slack"), + ("pd", "PagerDuty"), + ], + ), + ) ] diff --git a/hc/api/migrations/0014_auto_20151019_2039.py b/hc/api/migrations/0014_auto_20151019_2039.py index 382a7601..1be01837 100644 --- a/hc/api/migrations/0014_auto_20151019_2039.py +++ b/hc/api/migrations/0014_auto_20151019_2039.py @@ -7,14 +7,12 @@ import uuid class Migration(migrations.Migration): - dependencies = [ - ('api', '0013_auto_20151001_2029'), - ] + dependencies = [("api", "0013_auto_20151001_2029")] operations = [ migrations.AlterField( - model_name='check', - name='code', + model_name="check", + name="code", field=models.UUIDField(default=uuid.uuid4, db_index=True, editable=False), - ), + ) ] diff --git a/hc/api/migrations/0015_auto_20151022_1008.py b/hc/api/migrations/0015_auto_20151022_1008.py index 2fc857e9..ad4fda02 100644 --- a/hc/api/migrations/0015_auto_20151022_1008.py +++ b/hc/api/migrations/0015_auto_20151022_1008.py @@ -6,13 +6,10 @@ from django.db import models, migrations class Migration(migrations.Migration): - dependencies = [ - ('api', '0014_auto_20151019_2039'), - ] + dependencies = [("api", "0014_auto_20151019_2039")] operations = [ migrations.AlterIndexTogether( - name='check', - index_together=set([('status', 'user', 'alert_after')]), - ), + name="check", index_together=set([("status", "user", "alert_after")]) + ) ] diff --git a/hc/api/migrations/0016_auto_20151030_1107.py b/hc/api/migrations/0016_auto_20151030_1107.py index 5f527eec..d0fb4fb8 100644 --- a/hc/api/migrations/0016_auto_20151030_1107.py +++ b/hc/api/migrations/0016_auto_20151030_1107.py @@ -6,14 +6,21 @@ from django.db import models, migrations class Migration(migrations.Migration): - dependencies = [ - ('api', '0015_auto_20151022_1008'), - ] + dependencies = [("api", "0015_auto_20151022_1008")] operations = [ migrations.AlterField( - model_name='check', - name='status', - field=models.CharField(default='new', max_length=6, choices=[('up', 'Up'), ('down', 'Down'), ('new', 'New'), ('paused', 'Paused')]), - ), + model_name="check", + name="status", + field=models.CharField( + default="new", + max_length=6, + choices=[ + ("up", "Up"), + ("down", "Down"), + ("new", "New"), + ("paused", "Paused"), + ], + ), + ) ] diff --git a/hc/api/migrations/0017_auto_20151117_1032.py b/hc/api/migrations/0017_auto_20151117_1032.py index 6ed2b6dc..80cfc360 100644 --- a/hc/api/migrations/0017_auto_20151117_1032.py +++ b/hc/api/migrations/0017_auto_20151117_1032.py @@ -6,14 +6,22 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0016_auto_20151030_1107'), - ] + dependencies = [("api", "0016_auto_20151030_1107")] operations = [ migrations.AlterField( - model_name='channel', - name='kind', - field=models.CharField(choices=[('email', 'Email'), ('webhook', 'Webhook'), ('hipchat', 'HipChat'), ('slack', 'Slack'), ('pd', 'PagerDuty'), ('po', 'Pushover')], max_length=20), - ), + model_name="channel", + name="kind", + field=models.CharField( + choices=[ + ("email", "Email"), + ("webhook", "Webhook"), + ("hipchat", "HipChat"), + ("slack", "Slack"), + ("pd", "PagerDuty"), + ("po", "Pushover"), + ], + max_length=20, + ), + ) ] diff --git a/hc/api/migrations/0018_remove_ping_body.py b/hc/api/migrations/0018_remove_ping_body.py index 14930b42..b388941a 100644 --- a/hc/api/migrations/0018_remove_ping_body.py +++ b/hc/api/migrations/0018_remove_ping_body.py @@ -6,13 +6,6 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0017_auto_20151117_1032'), - ] + dependencies = [("api", "0017_auto_20151117_1032")] - operations = [ - migrations.RemoveField( - model_name='ping', - name='body', - ), - ] + operations = [migrations.RemoveField(model_name="ping", name="body")] diff --git a/hc/api/migrations/0019_check_tags.py b/hc/api/migrations/0019_check_tags.py index 9359954a..ebd3d828 100644 --- a/hc/api/migrations/0019_check_tags.py +++ b/hc/api/migrations/0019_check_tags.py @@ -6,14 +6,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0018_remove_ping_body'), - ] + dependencies = [("api", "0018_remove_ping_body")] operations = [ migrations.AddField( - model_name='check', - name='tags', + model_name="check", + name="tags", field=models.CharField(max_length=500, blank=True), - ), + ) ] diff --git a/hc/api/migrations/0020_check_n_pings.py b/hc/api/migrations/0020_check_n_pings.py index b6cdf116..6d01e913 100644 --- a/hc/api/migrations/0020_check_n_pings.py +++ b/hc/api/migrations/0020_check_n_pings.py @@ -7,14 +7,10 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0019_check_tags'), - ] + dependencies = [("api", "0019_check_tags")] operations = [ migrations.AddField( - model_name='check', - name='n_pings', - field=models.IntegerField(default=0), - ), + model_name="check", name="n_pings", field=models.IntegerField(default=0) + ) ] diff --git a/hc/api/migrations/0021_ping_n.py b/hc/api/migrations/0021_ping_n.py index c40ee518..628702de 100644 --- a/hc/api/migrations/0021_ping_n.py +++ b/hc/api/migrations/0021_ping_n.py @@ -7,14 +7,10 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0020_check_n_pings'), - ] + dependencies = [("api", "0020_check_n_pings")] operations = [ migrations.AddField( - model_name='ping', - name='n', - field=models.IntegerField(null=True), - ), + model_name="ping", name="n", field=models.IntegerField(null=True) + ) ] diff --git a/hc/api/migrations/0022_auto_20160130_2042.py b/hc/api/migrations/0022_auto_20160130_2042.py index f1b940d4..44caf17b 100644 --- a/hc/api/migrations/0022_auto_20160130_2042.py +++ b/hc/api/migrations/0022_auto_20160130_2042.py @@ -7,18 +7,13 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0021_ping_n'), - ] + dependencies = [("api", "0021_ping_n")] operations = [ - migrations.RemoveField( - model_name='notification', - name='status', - ), + migrations.RemoveField(model_name="notification", name="status"), migrations.AddField( - model_name='notification', - name='error', + model_name="notification", + name="error", field=models.CharField(blank=True, max_length=200), ), ] diff --git a/hc/api/migrations/0023_auto_20160131_1919.py b/hc/api/migrations/0023_auto_20160131_1919.py index f912a77c..e963fdd9 100644 --- a/hc/api/migrations/0023_auto_20160131_1919.py +++ b/hc/api/migrations/0023_auto_20160131_1919.py @@ -7,13 +7,10 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('api', '0022_auto_20160130_2042'), - ] + dependencies = [("api", "0022_auto_20160130_2042")] operations = [ migrations.AlterModelOptions( - name='notification', - options={'get_latest_by': 'created'}, - ), + name="notification", options={"get_latest_by": "created"} + ) ] diff --git a/hc/api/migrations/0024_auto_20160203_2227.py b/hc/api/migrations/0024_auto_20160203_2227.py index 236a11dd..bb9daf59 100644 --- a/hc/api/migrations/0024_auto_20160203_2227.py +++ b/hc/api/migrations/0024_auto_20160203_2227.py @@ -7,14 +7,23 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0023_auto_20160131_1919'), - ] + dependencies = [("api", "0023_auto_20160131_1919")] operations = [ migrations.AlterField( - model_name='channel', - name='kind', - field=models.CharField(choices=[(b'email', b'Email'), (b'webhook', b'Webhook'), (b'hipchat', b'HipChat'), (b'slack', b'Slack'), (b'pd', b'PagerDuty'), (b'po', b'Pushover'), (b'victorops', b'VictorOps')], max_length=20), - ), + model_name="channel", + name="kind", + field=models.CharField( + choices=[ + (b"email", b"Email"), + (b"webhook", b"Webhook"), + (b"hipchat", b"HipChat"), + (b"slack", b"Slack"), + (b"pd", b"PagerDuty"), + (b"po", b"Pushover"), + (b"victorops", b"VictorOps"), + ], + max_length=20, + ), + ) ] diff --git a/hc/api/migrations/0025_auto_20160216_1214.py b/hc/api/migrations/0025_auto_20160216_1214.py index 2fc02abe..17411fdf 100644 --- a/hc/api/migrations/0025_auto_20160216_1214.py +++ b/hc/api/migrations/0025_auto_20160216_1214.py @@ -7,14 +7,23 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0024_auto_20160203_2227'), - ] + dependencies = [("api", "0024_auto_20160203_2227")] operations = [ migrations.AlterField( - model_name='channel', - name='kind', - field=models.CharField(choices=[('email', 'Email'), ('webhook', 'Webhook'), ('hipchat', 'HipChat'), ('slack', 'Slack'), ('pd', 'PagerDuty'), ('po', 'Pushover'), ('victorops', 'VictorOps')], max_length=20), - ), + model_name="channel", + name="kind", + field=models.CharField( + choices=[ + ("email", "Email"), + ("webhook", "Webhook"), + ("hipchat", "HipChat"), + ("slack", "Slack"), + ("pd", "PagerDuty"), + ("po", "Pushover"), + ("victorops", "VictorOps"), + ], + max_length=20, + ), + ) ] diff --git a/hc/api/migrations/0026_auto_20160415_1824.py b/hc/api/migrations/0026_auto_20160415_1824.py index 729976fe..3dfe47e7 100644 --- a/hc/api/migrations/0026_auto_20160415_1824.py +++ b/hc/api/migrations/0026_auto_20160415_1824.py @@ -7,14 +7,10 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0025_auto_20160216_1214'), - ] + dependencies = [("api", "0025_auto_20160216_1214")] operations = [ migrations.AlterField( - model_name='channel', - name='value', - field=models.TextField(blank=True), - ), + model_name="channel", name="value", field=models.TextField(blank=True) + ) ] diff --git a/hc/api/migrations/0027_auto_20161213_1059.py b/hc/api/migrations/0027_auto_20161213_1059.py index 4232fab5..d65b3d2a 100644 --- a/hc/api/migrations/0027_auto_20161213_1059.py +++ b/hc/api/migrations/0027_auto_20161213_1059.py @@ -7,29 +7,44 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0026_auto_20160415_1824'), - ] + dependencies = [("api", "0026_auto_20160415_1824")] operations = [ migrations.AddField( - model_name='check', - name='kind', - field=models.CharField(choices=[('simple', 'Simple'), ('cron', 'Cron')], default='simple', max_length=10), + model_name="check", + name="kind", + field=models.CharField( + choices=[("simple", "Simple"), ("cron", "Cron")], + default="simple", + max_length=10, + ), ), migrations.AddField( - model_name='check', - name='schedule', - field=models.CharField(default='* * * * *', max_length=100), + model_name="check", + name="schedule", + field=models.CharField(default="* * * * *", max_length=100), ), migrations.AddField( - model_name='check', - name='tz', - field=models.CharField(default='UTC', max_length=36), + model_name="check", + name="tz", + field=models.CharField(default="UTC", max_length=36), ), migrations.AlterField( - model_name='channel', - name='kind', - field=models.CharField(choices=[('email', 'Email'), ('webhook', 'Webhook'), ('hipchat', 'HipChat'), ('slack', 'Slack'), ('pd', 'PagerDuty'), ('po', 'Pushover'), ('pushbullet', 'Pushbullet'), ('opsgenie', 'OpsGenie'), ('victorops', 'VictorOps')], max_length=20), + model_name="channel", + name="kind", + field=models.CharField( + choices=[ + ("email", "Email"), + ("webhook", "Webhook"), + ("hipchat", "HipChat"), + ("slack", "Slack"), + ("pd", "PagerDuty"), + ("po", "Pushover"), + ("pushbullet", "Pushbullet"), + ("opsgenie", "OpsGenie"), + ("victorops", "VictorOps"), + ], + max_length=20, + ), ), ] diff --git a/hc/api/migrations/0028_auto_20170305_1907.py b/hc/api/migrations/0028_auto_20170305_1907.py index 4505d428..e3f3a069 100644 --- a/hc/api/migrations/0028_auto_20170305_1907.py +++ b/hc/api/migrations/0028_auto_20170305_1907.py @@ -8,19 +8,31 @@ import uuid class Migration(migrations.Migration): - dependencies = [ - ('api', '0027_auto_20161213_1059'), - ] + dependencies = [("api", "0027_auto_20161213_1059")] operations = [ migrations.AddField( - model_name='notification', - name='code', + model_name="notification", + name="code", field=models.UUIDField(default=None, editable=False, null=True), ), migrations.AlterField( - model_name='channel', - name='kind', - field=models.CharField(choices=[('email', 'Email'), ('webhook', 'Webhook'), ('hipchat', 'HipChat'), ('slack', 'Slack'), ('pd', 'PagerDuty'), ('po', 'Pushover'), ('pushbullet', 'Pushbullet'), ('opsgenie', 'OpsGenie'), ('victorops', 'VictorOps'), ('discord', 'Discord')], max_length=20), + model_name="channel", + name="kind", + field=models.CharField( + choices=[ + ("email", "Email"), + ("webhook", "Webhook"), + ("hipchat", "HipChat"), + ("slack", "Slack"), + ("pd", "PagerDuty"), + ("po", "Pushover"), + ("pushbullet", "Pushbullet"), + ("opsgenie", "OpsGenie"), + ("victorops", "VictorOps"), + ("discord", "Discord"), + ], + max_length=20, + ), ), ] diff --git a/hc/api/migrations/0029_auto_20170507_1251.py b/hc/api/migrations/0029_auto_20170507_1251.py index 9bfa42dd..d093c193 100644 --- a/hc/api/migrations/0029_auto_20170507_1251.py +++ b/hc/api/migrations/0029_auto_20170507_1251.py @@ -8,14 +8,12 @@ import uuid class Migration(migrations.Migration): - dependencies = [ - ('api', '0028_auto_20170305_1907'), - ] + dependencies = [("api", "0028_auto_20170305_1907")] operations = [ migrations.AlterField( - model_name='notification', - name='code', + model_name="notification", + name="code", field=models.UUIDField(default=uuid.uuid4, editable=False, null=True), - ), + ) ] diff --git a/hc/api/migrations/0030_check_last_ping_body.py b/hc/api/migrations/0030_check_last_ping_body.py index 0979bffe..385c22d9 100644 --- a/hc/api/migrations/0030_check_last_ping_body.py +++ b/hc/api/migrations/0030_check_last_ping_body.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0029_auto_20170507_1251'), - ] + dependencies = [("api", "0029_auto_20170507_1251")] operations = [ migrations.AddField( - model_name='check', - name='last_ping_body', + model_name="check", + name="last_ping_body", field=models.CharField(blank=True, max_length=1000), - ), + ) ] diff --git a/hc/api/migrations/0031_auto_20170509_1320.py b/hc/api/migrations/0031_auto_20170509_1320.py index 51afdd83..67fc6939 100644 --- a/hc/api/migrations/0031_auto_20170509_1320.py +++ b/hc/api/migrations/0031_auto_20170509_1320.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0030_check_last_ping_body'), - ] + dependencies = [("api", "0030_check_last_ping_body")] operations = [ migrations.AlterField( - model_name='check', - name='last_ping_body', + model_name="check", + name="last_ping_body", field=models.CharField(blank=True, max_length=10000), - ), + ) ] diff --git a/hc/api/migrations/0032_auto_20170608_1158.py b/hc/api/migrations/0032_auto_20170608_1158.py index 00c1ac5f..d2fe4930 100644 --- a/hc/api/migrations/0032_auto_20170608_1158.py +++ b/hc/api/migrations/0032_auto_20170608_1158.py @@ -7,14 +7,27 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0031_auto_20170509_1320'), - ] + dependencies = [("api", "0031_auto_20170509_1320")] operations = [ migrations.AlterField( - model_name='channel', - name='kind', - field=models.CharField(choices=[('email', 'Email'), ('webhook', 'Webhook'), ('hipchat', 'HipChat'), ('slack', 'Slack'), ('pd', 'PagerDuty'), ('po', 'Pushover'), ('pushbullet', 'Pushbullet'), ('opsgenie', 'OpsGenie'), ('victorops', 'VictorOps'), ('discord', 'Discord'), ('telegram', 'Telegram')], max_length=20), - ), + model_name="channel", + name="kind", + field=models.CharField( + choices=[ + ("email", "Email"), + ("webhook", "Webhook"), + ("hipchat", "HipChat"), + ("slack", "Slack"), + ("pd", "PagerDuty"), + ("po", "Pushover"), + ("pushbullet", "Pushbullet"), + ("opsgenie", "OpsGenie"), + ("victorops", "VictorOps"), + ("discord", "Discord"), + ("telegram", "Telegram"), + ], + max_length=20, + ), + ) ] diff --git a/hc/api/migrations/0033_auto_20170714_1715.py b/hc/api/migrations/0033_auto_20170714_1715.py index 1e6178f4..2c8e3fbc 100644 --- a/hc/api/migrations/0033_auto_20170714_1715.py +++ b/hc/api/migrations/0033_auto_20170714_1715.py @@ -7,14 +7,28 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0032_auto_20170608_1158'), - ] + dependencies = [("api", "0032_auto_20170608_1158")] operations = [ migrations.AlterField( - model_name='channel', - name='kind', - field=models.CharField(choices=[('email', 'Email'), ('webhook', 'Webhook'), ('hipchat', 'HipChat'), ('slack', 'Slack'), ('pd', 'PagerDuty'), ('po', 'Pushover'), ('pushbullet', 'Pushbullet'), ('opsgenie', 'OpsGenie'), ('victorops', 'VictorOps'), ('discord', 'Discord'), ('telegram', 'Telegram'), ('sms', 'SMS')], max_length=20), - ), + model_name="channel", + name="kind", + field=models.CharField( + choices=[ + ("email", "Email"), + ("webhook", "Webhook"), + ("hipchat", "HipChat"), + ("slack", "Slack"), + ("pd", "PagerDuty"), + ("po", "Pushover"), + ("pushbullet", "Pushbullet"), + ("opsgenie", "OpsGenie"), + ("victorops", "VictorOps"), + ("discord", "Discord"), + ("telegram", "Telegram"), + ("sms", "SMS"), + ], + max_length=20, + ), + ) ] diff --git a/hc/api/migrations/0034_auto_20171227_1530.py b/hc/api/migrations/0034_auto_20171227_1530.py index 57d05263..340b3f15 100644 --- a/hc/api/migrations/0034_auto_20171227_1530.py +++ b/hc/api/migrations/0034_auto_20171227_1530.py @@ -7,14 +7,29 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0033_auto_20170714_1715'), - ] + dependencies = [("api", "0033_auto_20170714_1715")] operations = [ migrations.AlterField( - model_name='channel', - name='kind', - field=models.CharField(choices=[('email', 'Email'), ('webhook', 'Webhook'), ('hipchat', 'HipChat'), ('slack', 'Slack'), ('pd', 'PagerDuty'), ('pagertree', 'PagerTree'), ('po', 'Pushover'), ('pushbullet', 'Pushbullet'), ('opsgenie', 'OpsGenie'), ('victorops', 'VictorOps'), ('discord', 'Discord'), ('telegram', 'Telegram'), ('sms', 'SMS')], max_length=20), - ), + model_name="channel", + name="kind", + field=models.CharField( + choices=[ + ("email", "Email"), + ("webhook", "Webhook"), + ("hipchat", "HipChat"), + ("slack", "Slack"), + ("pd", "PagerDuty"), + ("pagertree", "PagerTree"), + ("po", "Pushover"), + ("pushbullet", "Pushbullet"), + ("opsgenie", "OpsGenie"), + ("victorops", "VictorOps"), + ("discord", "Discord"), + ("telegram", "Telegram"), + ("sms", "SMS"), + ], + max_length=20, + ), + ) ] diff --git a/hc/api/migrations/0035_auto_20171229_2008.py b/hc/api/migrations/0035_auto_20171229_2008.py index 577841c1..a7af4e0a 100644 --- a/hc/api/migrations/0035_auto_20171229_2008.py +++ b/hc/api/migrations/0035_auto_20171229_2008.py @@ -7,14 +7,30 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0034_auto_20171227_1530'), - ] + dependencies = [("api", "0034_auto_20171227_1530")] operations = [ migrations.AlterField( - model_name='channel', - name='kind', - field=models.CharField(choices=[('email', 'Email'), ('webhook', 'Webhook'), ('hipchat', 'HipChat'), ('slack', 'Slack'), ('pd', 'PagerDuty'), ('pagertree', 'PagerTree'), ('po', 'Pushover'), ('pushbullet', 'Pushbullet'), ('opsgenie', 'OpsGenie'), ('victorops', 'VictorOps'), ('discord', 'Discord'), ('telegram', 'Telegram'), ('sms', 'SMS'), ('zendesk', 'Zendesk')], max_length=20), - ), + model_name="channel", + name="kind", + field=models.CharField( + choices=[ + ("email", "Email"), + ("webhook", "Webhook"), + ("hipchat", "HipChat"), + ("slack", "Slack"), + ("pd", "PagerDuty"), + ("pagertree", "PagerTree"), + ("po", "Pushover"), + ("pushbullet", "Pushbullet"), + ("opsgenie", "OpsGenie"), + ("victorops", "VictorOps"), + ("discord", "Discord"), + ("telegram", "Telegram"), + ("sms", "SMS"), + ("zendesk", "Zendesk"), + ], + max_length=20, + ), + ) ] diff --git a/hc/api/migrations/0036_auto_20180116_2243.py b/hc/api/migrations/0036_auto_20180116_2243.py index df4d7748..52ee4a81 100644 --- a/hc/api/migrations/0036_auto_20180116_2243.py +++ b/hc/api/migrations/0036_auto_20180116_2243.py @@ -7,13 +7,6 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('api', '0035_auto_20171229_2008'), - ] + dependencies = [("api", "0035_auto_20171229_2008")] - operations = [ - migrations.AlterIndexTogether( - name='check', - index_together=set([]), - ), - ] + operations = [migrations.AlterIndexTogether(name="check", index_together=set([]))] diff --git a/hc/api/migrations/0037_auto_20180127_1215.py b/hc/api/migrations/0037_auto_20180127_1215.py index 82d631f1..82b5b0e5 100644 --- a/hc/api/migrations/0037_auto_20180127_1215.py +++ b/hc/api/migrations/0037_auto_20180127_1215.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0036_auto_20180116_2243'), - ] + dependencies = [("api", "0036_auto_20180116_2243")] operations = [ migrations.AlterField( - model_name='ping', - name='id', + model_name="ping", + name="id", field=models.BigAutoField(primary_key=True, serialize=False), - ), + ) ] diff --git a/hc/api/migrations/0038_auto_20180318_1306.py b/hc/api/migrations/0038_auto_20180318_1306.py index 403c545f..2e067ee6 100644 --- a/hc/api/migrations/0038_auto_20180318_1306.py +++ b/hc/api/migrations/0038_auto_20180318_1306.py @@ -7,19 +7,17 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0037_auto_20180127_1215'), - ] + dependencies = [("api", "0037_auto_20180127_1215")] operations = [ migrations.AddField( - model_name='check', - name='has_confirmation_link', + model_name="check", + name="has_confirmation_link", field=models.BooleanField(default=False), ), migrations.AddField( - model_name='ping', - name='body', + model_name="ping", + name="body", field=models.CharField(blank=True, max_length=10000, null=True), ), ] diff --git a/hc/api/migrations/0039_remove_check_last_ping_body.py b/hc/api/migrations/0039_remove_check_last_ping_body.py index 2a019462..f7633898 100644 --- a/hc/api/migrations/0039_remove_check_last_ping_body.py +++ b/hc/api/migrations/0039_remove_check_last_ping_body.py @@ -7,13 +7,6 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('api', '0038_auto_20180318_1306'), - ] + dependencies = [("api", "0038_auto_20180318_1306")] - operations = [ - migrations.RemoveField( - model_name='check', - name='last_ping_body', - ), - ] + operations = [migrations.RemoveField(model_name="check", name="last_ping_body")] diff --git a/hc/api/migrations/0040_auto_20180517_1336.py b/hc/api/migrations/0040_auto_20180517_1336.py index 1be49e56..d75b00b3 100644 --- a/hc/api/migrations/0040_auto_20180517_1336.py +++ b/hc/api/migrations/0040_auto_20180517_1336.py @@ -5,19 +5,15 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0039_remove_check_last_ping_body'), - ] + dependencies = [("api", "0039_remove_check_last_ping_body")] operations = [ migrations.AddField( - model_name='check', - name='last_ping_was_fail', + model_name="check", + name="last_ping_was_fail", field=models.NullBooleanField(default=False), ), migrations.AddField( - model_name='ping', - name='fail', - field=models.NullBooleanField(default=False), + model_name="ping", name="fail", field=models.NullBooleanField(default=False) ), ] diff --git a/hc/api/migrations/0041_check_desc.py b/hc/api/migrations/0041_check_desc.py index 5e28682e..c416ec49 100644 --- a/hc/api/migrations/0041_check_desc.py +++ b/hc/api/migrations/0041_check_desc.py @@ -5,14 +5,10 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0040_auto_20180517_1336'), - ] + dependencies = [("api", "0040_auto_20180517_1336")] operations = [ migrations.AddField( - model_name='check', - name='desc', - field=models.TextField(blank=True), - ), + model_name="check", name="desc", field=models.TextField(blank=True) + ) ] diff --git a/hc/api/migrations/0042_auto_20181029_1522.py b/hc/api/migrations/0042_auto_20181029_1522.py index d3322866..b36663b4 100644 --- a/hc/api/migrations/0042_auto_20181029_1522.py +++ b/hc/api/migrations/0042_auto_20181029_1522.py @@ -5,14 +5,31 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0041_check_desc'), - ] + dependencies = [("api", "0041_check_desc")] operations = [ migrations.AlterField( - model_name='channel', - name='kind', - field=models.CharField(choices=[('email', 'Email'), ('webhook', 'Webhook'), ('hipchat', 'HipChat'), ('slack', 'Slack'), ('pd', 'PagerDuty'), ('pagertree', 'PagerTree'), ('po', 'Pushover'), ('pushbullet', 'Pushbullet'), ('opsgenie', 'OpsGenie'), ('victorops', 'VictorOps'), ('discord', 'Discord'), ('telegram', 'Telegram'), ('sms', 'SMS'), ('zendesk', 'Zendesk'), ('trello', 'Trello')], max_length=20), - ), + model_name="channel", + name="kind", + field=models.CharField( + choices=[ + ("email", "Email"), + ("webhook", "Webhook"), + ("hipchat", "HipChat"), + ("slack", "Slack"), + ("pd", "PagerDuty"), + ("pagertree", "PagerTree"), + ("po", "Pushover"), + ("pushbullet", "Pushbullet"), + ("opsgenie", "OpsGenie"), + ("victorops", "VictorOps"), + ("discord", "Discord"), + ("telegram", "Telegram"), + ("sms", "SMS"), + ("zendesk", "Zendesk"), + ("trello", "Trello"), + ], + max_length=20, + ), + ) ] diff --git a/hc/api/migrations/0043_channel_name.py b/hc/api/migrations/0043_channel_name.py index dd2da8d0..43030c31 100644 --- a/hc/api/migrations/0043_channel_name.py +++ b/hc/api/migrations/0043_channel_name.py @@ -5,14 +5,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0042_auto_20181029_1522'), - ] + dependencies = [("api", "0042_auto_20181029_1522")] operations = [ migrations.AddField( - model_name='channel', - name='name', + model_name="channel", + name="name", field=models.CharField(blank=True, max_length=100), - ), + ) ] diff --git a/hc/api/migrations/0044_auto_20181120_2004.py b/hc/api/migrations/0044_auto_20181120_2004.py index c6f10c7b..035e4610 100644 --- a/hc/api/migrations/0044_auto_20181120_2004.py +++ b/hc/api/migrations/0044_auto_20181120_2004.py @@ -6,7 +6,7 @@ from django.db import migrations def combine_channel_names(apps, schema_editor): - Channel = apps.get_model('api', 'Channel') + Channel = apps.get_model("api", "Channel") for channel in Channel.objects.filter(kind="sms"): if channel.value.startswith("{"): doc = json.loads(channel.value) @@ -16,10 +16,6 @@ def combine_channel_names(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ - ('api', '0043_channel_name'), - ] + dependencies = [("api", "0043_channel_name")] - operations = [ - migrations.RunPython(combine_channel_names), - ] + operations = [migrations.RunPython(combine_channel_names)] diff --git a/hc/api/migrations/0045_flip.py b/hc/api/migrations/0045_flip.py index d9348db5..b82067d5 100644 --- a/hc/api/migrations/0045_flip.py +++ b/hc/api/migrations/0045_flip.py @@ -6,20 +6,56 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('api', '0044_auto_20181120_2004'), - ] + dependencies = [("api", "0044_auto_20181120_2004")] operations = [ migrations.CreateModel( - name='Flip', + name="Flip", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created', models.DateTimeField()), - ('processed', models.DateTimeField(blank=True, db_index=True, null=True)), - ('old_status', models.CharField(choices=[('up', 'Up'), ('down', 'Down'), ('new', 'New'), ('paused', 'Paused')], max_length=8)), - ('new_status', models.CharField(choices=[('up', 'Up'), ('down', 'Down'), ('new', 'New'), ('paused', 'Paused')], max_length=8)), - ('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='api.Check')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("created", models.DateTimeField()), + ( + "processed", + models.DateTimeField(blank=True, db_index=True, null=True), + ), + ( + "old_status", + models.CharField( + choices=[ + ("up", "Up"), + ("down", "Down"), + ("new", "New"), + ("paused", "Paused"), + ], + max_length=8, + ), + ), + ( + "new_status", + models.CharField( + choices=[ + ("up", "Up"), + ("down", "Down"), + ("new", "New"), + ("paused", "Paused"), + ], + max_length=8, + ), + ), + ( + "owner", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="api.Check" + ), + ), ], - ), + ) ] diff --git a/hc/api/migrations/0046_auto_20181218_1245.py b/hc/api/migrations/0046_auto_20181218_1245.py index 33c359ae..613939db 100644 --- a/hc/api/migrations/0046_auto_20181218_1245.py +++ b/hc/api/migrations/0046_auto_20181218_1245.py @@ -5,19 +5,17 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0045_flip'), - ] + dependencies = [("api", "0045_flip")] operations = [ migrations.AddField( - model_name='check', - name='last_start', + model_name="check", + name="last_start", field=models.DateTimeField(blank=True, null=True), ), migrations.AddField( - model_name='ping', - name='start', + model_name="ping", + name="start", field=models.NullBooleanField(default=False), ), ] diff --git a/hc/api/migrations/0047_auto_20181225_2315.py b/hc/api/migrations/0047_auto_20181225_2315.py index 24dd6c0c..eb846e23 100644 --- a/hc/api/migrations/0047_auto_20181225_2315.py +++ b/hc/api/migrations/0047_auto_20181225_2315.py @@ -6,14 +6,12 @@ import uuid class Migration(migrations.Migration): - dependencies = [ - ('api', '0046_auto_20181218_1245'), - ] + dependencies = [("api", "0046_auto_20181218_1245")] operations = [ migrations.AlterField( - model_name='channel', - name='code', + model_name="channel", + name="code", field=models.UUIDField(default=uuid.uuid4, editable=False, unique=True), - ), + ) ] diff --git a/hc/api/migrations/0048_auto_20190102_0737.py b/hc/api/migrations/0048_auto_20190102_0737.py index d636f261..86f8c1d2 100644 --- a/hc/api/migrations/0048_auto_20190102_0737.py +++ b/hc/api/migrations/0048_auto_20190102_0737.py @@ -10,10 +10,6 @@ def remove_anon_checks(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ - ('api', '0047_auto_20181225_2315'), - ] + dependencies = [("api", "0047_auto_20181225_2315")] - operations = [ - migrations.RunPython(remove_anon_checks, migrations.RunPython.noop), - ] + operations = [migrations.RunPython(remove_anon_checks, migrations.RunPython.noop)] diff --git a/hc/api/migrations/0049_auto_20190102_0743.py b/hc/api/migrations/0049_auto_20190102_0743.py index e3db9b0a..57a02023 100644 --- a/hc/api/migrations/0049_auto_20190102_0743.py +++ b/hc/api/migrations/0049_auto_20190102_0743.py @@ -8,19 +8,19 @@ import uuid class Migration(migrations.Migration): - dependencies = [ - ('api', '0048_auto_20190102_0737'), - ] + dependencies = [("api", "0048_auto_20190102_0737")] operations = [ migrations.AlterField( - model_name='check', - name='code', + model_name="check", + name="code", field=models.UUIDField(default=uuid.uuid4, editable=False, unique=True), ), migrations.AlterField( - model_name='check', - name='user', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + model_name="check", + name="user", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL + ), ), ] diff --git a/hc/api/migrations/0050_ping_kind.py b/hc/api/migrations/0050_ping_kind.py index 132b343d..06431dcc 100644 --- a/hc/api/migrations/0050_ping_kind.py +++ b/hc/api/migrations/0050_ping_kind.py @@ -5,14 +5,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0049_auto_20190102_0743'), - ] + dependencies = [("api", "0049_auto_20190102_0743")] operations = [ migrations.AddField( - model_name='ping', - name='kind', + model_name="ping", + name="kind", field=models.CharField(blank=True, max_length=6, null=True), - ), + ) ] diff --git a/hc/api/migrations/0051_auto_20190104_0908.py b/hc/api/migrations/0051_auto_20190104_0908.py index f42e70fe..beadfaf3 100644 --- a/hc/api/migrations/0051_auto_20190104_0908.py +++ b/hc/api/migrations/0051_auto_20190104_0908.py @@ -4,7 +4,7 @@ from django.db import migrations def fill_ping_kind(apps, schema_editor): - Ping = apps.get_model('api', 'Ping') + Ping = apps.get_model("api", "Ping") q = Ping.objects.filter(start=True) q.update(kind="start") @@ -15,10 +15,6 @@ def fill_ping_kind(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ - ('api', '0050_ping_kind'), - ] + dependencies = [("api", "0050_ping_kind")] - operations = [ - migrations.RunPython(fill_ping_kind), - ] + operations = [migrations.RunPython(fill_ping_kind)] diff --git a/hc/api/migrations/0052_auto_20190104_1122.py b/hc/api/migrations/0052_auto_20190104_1122.py index 0847e7a6..01ea1daa 100644 --- a/hc/api/migrations/0052_auto_20190104_1122.py +++ b/hc/api/migrations/0052_auto_20190104_1122.py @@ -5,17 +5,9 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('api', '0051_auto_20190104_0908'), - ] + dependencies = [("api", "0051_auto_20190104_0908")] operations = [ - migrations.RemoveField( - model_name='ping', - name='fail', - ), - migrations.RemoveField( - model_name='ping', - name='start', - ), + migrations.RemoveField(model_name="ping", name="fail"), + migrations.RemoveField(model_name="ping", name="start"), ] diff --git a/hc/api/migrations/0053_check_subject.py b/hc/api/migrations/0053_check_subject.py index 1e99fae3..d78be7a1 100644 --- a/hc/api/migrations/0053_check_subject.py +++ b/hc/api/migrations/0053_check_subject.py @@ -5,14 +5,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0052_auto_20190104_1122'), - ] + dependencies = [("api", "0052_auto_20190104_1122")] operations = [ migrations.AddField( - model_name='check', - name='subject', + model_name="check", + name="subject", field=models.CharField(blank=True, max_length=100), - ), + ) ] diff --git a/hc/api/migrations/0054_auto_20190112_1427.py b/hc/api/migrations/0054_auto_20190112_1427.py index 1fb62976..9426ef7f 100644 --- a/hc/api/migrations/0054_auto_20190112_1427.py +++ b/hc/api/migrations/0054_auto_20190112_1427.py @@ -7,19 +7,27 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - ('accounts', '0018_auto_20190112_1426'), - ('api', '0053_check_subject'), + ("accounts", "0018_auto_20190112_1426"), + ("api", "0053_check_subject"), ] operations = [ migrations.AddField( - model_name='channel', - name='project', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='accounts.Project'), + model_name="channel", + name="project", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="accounts.Project", + ), ), migrations.AddField( - model_name='check', - name='project', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='accounts.Project'), + model_name="check", + name="project", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="accounts.Project", + ), ), ] diff --git a/hc/api/migrations/0055_auto_20190112_1427.py b/hc/api/migrations/0055_auto_20190112_1427.py index dcf61470..a84f77e8 100644 --- a/hc/api/migrations/0055_auto_20190112_1427.py +++ b/hc/api/migrations/0055_auto_20190112_1427.py @@ -14,10 +14,6 @@ def fill_project_id(apps, schema_editor): class Migration(migrations.Migration): - dependencies = [ - ('api', '0054_auto_20190112_1427'), - ] + dependencies = [("api", "0054_auto_20190112_1427")] - operations = [ - migrations.RunPython(fill_project_id, migrations.RunPython.noop), - ] + operations = [migrations.RunPython(fill_project_id, migrations.RunPython.noop)] diff --git a/hc/api/migrations/0056_auto_20190114_0857.py b/hc/api/migrations/0056_auto_20190114_0857.py index 977ece03..e5c09f1e 100644 --- a/hc/api/migrations/0056_auto_20190114_0857.py +++ b/hc/api/migrations/0056_auto_20190114_0857.py @@ -6,19 +6,21 @@ import django.db.models.deletion class Migration(migrations.Migration): - dependencies = [ - ('api', '0055_auto_20190112_1427'), - ] + dependencies = [("api", "0055_auto_20190112_1427")] operations = [ migrations.AlterField( - model_name='channel', - name='project', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='accounts.Project'), + model_name="channel", + name="project", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="accounts.Project" + ), ), migrations.AlterField( - model_name='check', - name='project', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='accounts.Project'), + model_name="check", + name="project", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="accounts.Project" + ), ), ] diff --git a/hc/api/migrations/0057_auto_20190118_1319.py b/hc/api/migrations/0057_auto_20190118_1319.py index 90a5f910..0e75ed00 100644 --- a/hc/api/migrations/0057_auto_20190118_1319.py +++ b/hc/api/migrations/0057_auto_20190118_1319.py @@ -5,17 +5,9 @@ from django.db import migrations class Migration(migrations.Migration): - dependencies = [ - ('api', '0056_auto_20190114_0857'), - ] + dependencies = [("api", "0056_auto_20190114_0857")] operations = [ - migrations.RemoveField( - model_name='channel', - name='user', - ), - migrations.RemoveField( - model_name='check', - name='user', - ), + migrations.RemoveField(model_name="channel", name="user"), + migrations.RemoveField(model_name="check", name="user"), ] diff --git a/hc/api/migrations/0058_auto_20190312_1716.py b/hc/api/migrations/0058_auto_20190312_1716.py index dbd86a39..bca7ec77 100644 --- a/hc/api/migrations/0058_auto_20190312_1716.py +++ b/hc/api/migrations/0058_auto_20190312_1716.py @@ -5,14 +5,32 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0057_auto_20190118_1319'), - ] + dependencies = [("api", "0057_auto_20190118_1319")] operations = [ migrations.AlterField( - model_name='channel', - name='kind', - field=models.CharField(choices=[('email', 'Email'), ('webhook', 'Webhook'), ('hipchat', 'HipChat'), ('slack', 'Slack'), ('pd', 'PagerDuty'), ('pagertree', 'PagerTree'), ('po', 'Pushover'), ('pushbullet', 'Pushbullet'), ('opsgenie', 'OpsGenie'), ('victorops', 'VictorOps'), ('discord', 'Discord'), ('telegram', 'Telegram'), ('sms', 'SMS'), ('zendesk', 'Zendesk'), ('trello', 'Trello'), ('matrix', 'Matrix')], max_length=20), - ), + model_name="channel", + name="kind", + field=models.CharField( + choices=[ + ("email", "Email"), + ("webhook", "Webhook"), + ("hipchat", "HipChat"), + ("slack", "Slack"), + ("pd", "PagerDuty"), + ("pagertree", "PagerTree"), + ("po", "Pushover"), + ("pushbullet", "Pushbullet"), + ("opsgenie", "OpsGenie"), + ("victorops", "VictorOps"), + ("discord", "Discord"), + ("telegram", "Telegram"), + ("sms", "SMS"), + ("zendesk", "Zendesk"), + ("trello", "Trello"), + ("matrix", "Matrix"), + ], + max_length=20, + ), + ) ] diff --git a/hc/api/migrations/0059_auto_20190314_1744.py b/hc/api/migrations/0059_auto_20190314_1744.py index 1b88d40c..f7447f70 100644 --- a/hc/api/migrations/0059_auto_20190314_1744.py +++ b/hc/api/migrations/0059_auto_20190314_1744.py @@ -5,14 +5,33 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0058_auto_20190312_1716'), - ] + dependencies = [("api", "0058_auto_20190312_1716")] operations = [ migrations.AlterField( - model_name='channel', - name='kind', - field=models.CharField(choices=[('email', 'Email'), ('webhook', 'Webhook'), ('hipchat', 'HipChat'), ('slack', 'Slack'), ('pd', 'PagerDuty'), ('pagertree', 'PagerTree'), ('pagerteam', 'Pager Team'), ('po', 'Pushover'), ('pushbullet', 'Pushbullet'), ('opsgenie', 'OpsGenie'), ('victorops', 'VictorOps'), ('discord', 'Discord'), ('telegram', 'Telegram'), ('sms', 'SMS'), ('zendesk', 'Zendesk'), ('trello', 'Trello'), ('matrix', 'Matrix')], max_length=20), - ), + model_name="channel", + name="kind", + field=models.CharField( + choices=[ + ("email", "Email"), + ("webhook", "Webhook"), + ("hipchat", "HipChat"), + ("slack", "Slack"), + ("pd", "PagerDuty"), + ("pagertree", "PagerTree"), + ("pagerteam", "Pager Team"), + ("po", "Pushover"), + ("pushbullet", "Pushbullet"), + ("opsgenie", "OpsGenie"), + ("victorops", "VictorOps"), + ("discord", "Discord"), + ("telegram", "Telegram"), + ("sms", "SMS"), + ("zendesk", "Zendesk"), + ("trello", "Trello"), + ("matrix", "Matrix"), + ], + max_length=20, + ), + ) ] diff --git a/hc/api/migrations/0060_tokenbucket.py b/hc/api/migrations/0060_tokenbucket.py index 07c154d8..5e65ba05 100644 --- a/hc/api/migrations/0060_tokenbucket.py +++ b/hc/api/migrations/0060_tokenbucket.py @@ -5,18 +5,24 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('api', '0059_auto_20190314_1744'), - ] + dependencies = [("api", "0059_auto_20190314_1744")] operations = [ migrations.CreateModel( - name='TokenBucket', + name="TokenBucket", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('value', models.CharField(max_length=80, unique=True)), - ('tokens', models.FloatField(default=1.0)), - ('updated', models.DateTimeField(auto_now_add=True)), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("value", models.CharField(max_length=80, unique=True)), + ("tokens", models.FloatField(default=1.0)), + ("updated", models.DateTimeField(auto_now_add=True)), ], - ), + ) ] diff --git a/hc/api/models.py b/hc/api/models.py index e9676fa5..141d7aae 100644 --- a/hc/api/models.py +++ b/hc/api/models.py @@ -15,43 +15,33 @@ from hc.api import transports from hc.lib import emails import pytz -STATUSES = ( - ("up", "Up"), - ("down", "Down"), - ("new", "New"), - ("paused", "Paused") -) +STATUSES = (("up", "Up"), ("down", "Down"), ("new", "New"), ("paused", "Paused")) DEFAULT_TIMEOUT = td(days=1) DEFAULT_GRACE = td(hours=1) NEVER = datetime(3000, 1, 1, tzinfo=pytz.UTC) -CHECK_KINDS = (("simple", "Simple"), - ("cron", "Cron")) - -CHANNEL_KINDS = (("email", "Email"), - ("webhook", "Webhook"), - ("hipchat", "HipChat"), - ("slack", "Slack"), - ("pd", "PagerDuty"), - ("pagertree", "PagerTree"), - ("pagerteam", "Pager Team"), - ("po", "Pushover"), - ("pushbullet", "Pushbullet"), - ("opsgenie", "OpsGenie"), - ("victorops", "VictorOps"), - ("discord", "Discord"), - ("telegram", "Telegram"), - ("sms", "SMS"), - ("zendesk", "Zendesk"), - ("trello", "Trello"), - ("matrix", "Matrix")) - -PO_PRIORITIES = { - -2: "lowest", - -1: "low", - 0: "normal", - 1: "high", - 2: "emergency" -} +CHECK_KINDS = (("simple", "Simple"), ("cron", "Cron")) + +CHANNEL_KINDS = ( + ("email", "Email"), + ("webhook", "Webhook"), + ("hipchat", "HipChat"), + ("slack", "Slack"), + ("pd", "PagerDuty"), + ("pagertree", "PagerTree"), + ("pagerteam", "Pager Team"), + ("po", "Pushover"), + ("pushbullet", "Pushbullet"), + ("opsgenie", "OpsGenie"), + ("victorops", "VictorOps"), + ("discord", "Discord"), + ("telegram", "Telegram"), + ("sms", "SMS"), + ("zendesk", "Zendesk"), + ("trello", "Trello"), + ("matrix", "Matrix"), +) + +PO_PRIORITIES = {-2: "lowest", -1: "low", 0: "normal", 1: "high", 2: "emergency"} def isostring(dt): @@ -68,8 +58,7 @@ class Check(models.Model): desc = models.TextField(blank=True) project = models.ForeignKey(Project, models.CASCADE) created = models.DateTimeField(auto_now_add=True) - kind = models.CharField(max_length=10, default="simple", - choices=CHECK_KINDS) + kind = models.CharField(max_length=10, default="simple", choices=CHECK_KINDS) timeout = models.DurationField(default=DEFAULT_TIMEOUT) grace = models.DurationField(default=DEFAULT_GRACE) schedule = models.CharField(max_length=100, default="* * * * *") @@ -194,7 +183,7 @@ class Check(models.Model): "channels": ",".join(sorted(channel_codes)), "last_ping": isostring(self.last_ping), "next_ping": isostring(self.get_grace_start()), - "desc": self.desc + "desc": self.desc, } if self.kind == "simple": @@ -283,11 +272,7 @@ class Channel(models.Model): return self.get_kind_display() def to_dict(self): - return { - "id": str(self.code), - "name": self.name, - "kind": self.kind - } + return {"id": str(self.code), "name": self.name, "kind": self.kind} def assign_all_checks(self): checks = Check.objects.filter(project=self.project) @@ -366,7 +351,7 @@ class Channel(models.Model): return error def icon_path(self): - return 'img/integrations/%s.png' % self.kind + return "img/integrations/%s.png" % self.kind @property def po_priority(self): diff --git a/hc/api/schemas.py b/hc/api/schemas.py index db0b8df8..bdd99f3b 100644 --- a/hc/api/schemas.py +++ b/hc/api/schemas.py @@ -10,7 +10,7 @@ check = { "channels": {"type": "string"}, "unique": { "type": "array", - "items": {"enum": ["name", "tags", "timeout", "grace"]} - } - } + "items": {"enum": ["name", "tags", "timeout", "grace"]}, + }, + }, } diff --git a/hc/api/tests/__init__.py b/hc/api/tests/__init__.py index b5ec7a15..488c7b46 100644 --- a/hc/api/tests/__init__.py +++ b/hc/api/tests/__init__.py @@ -3,11 +3,9 @@ from django.test.runner import DiscoverRunner class CustomRunner(DiscoverRunner): - def __init__(self, *args, **kwargs): # For speed: - settings.PASSWORD_HASHERS = \ - ('django.contrib.auth.hashers.MD5PasswordHasher', ) + settings.PASSWORD_HASHERS = ("django.contrib.auth.hashers.MD5PasswordHasher",) # Send emails synchronously settings.BLOCKING_EMAILS = True diff --git a/hc/api/tests/test_admin.py b/hc/api/tests/test_admin.py index acfb52d6..86a7db1e 100644 --- a/hc/api/tests/test_admin.py +++ b/hc/api/tests/test_admin.py @@ -3,7 +3,6 @@ from hc.test import BaseTestCase class ApiAdminTestCase(BaseTestCase): - def setUp(self): super(ApiAdminTestCase, self).setUp() self.check = Check.objects.create(project=self.project, tags="foo bar") @@ -15,8 +14,9 @@ class ApiAdminTestCase(BaseTestCase): def test_it_shows_channel_list_with_pushbullet(self): self.client.login(username="alice@example.org", password="password") - Channel.objects.create(project=self.project, kind="pushbullet", - value="test-token") + Channel.objects.create( + project=self.project, kind="pushbullet", value="test-token" + ) r = self.client.get("/admin/api/channel/") self.assertContains(r, "Pushbullet") @@ -24,8 +24,9 @@ class ApiAdminTestCase(BaseTestCase): def test_it_shows_channel_list_with_unverified_email(self): self.client.login(username="alice@example.org", password="password") - Channel.objects.create(project=self.project, kind="email", - value="foo@example.org") + Channel.objects.create( + project=self.project, kind="email", value="foo@example.org" + ) r = self.client.get("/admin/api/channel/") self.assertContains(r, "Email (unconfirmed)") diff --git a/hc/api/tests/test_badge.py b/hc/api/tests/test_badge.py index 9b1dbeae..c79c9675 100644 --- a/hc/api/tests/test_badge.py +++ b/hc/api/tests/test_badge.py @@ -9,7 +9,6 @@ from hc.test import BaseTestCase class BadgeTestCase(BaseTestCase): - def setUp(self): super(BadgeTestCase, self).setUp() self.check = Check.objects.create(project=self.project, tags="foo bar") diff --git a/hc/api/tests/test_bounce.py b/hc/api/tests/test_bounce.py index 45d02e38..617383c3 100644 --- a/hc/api/tests/test_bounce.py +++ b/hc/api/tests/test_bounce.py @@ -5,7 +5,6 @@ from hc.test import BaseTestCase class BounceTestCase(BaseTestCase): - def setUp(self): super(BounceTestCase, self).setUp() diff --git a/hc/api/tests/test_check_going_down_after.py b/hc/api/tests/test_check_going_down_after.py index 10763e23..c9fec987 100644 --- a/hc/api/tests/test_check_going_down_after.py +++ b/hc/api/tests/test_check_going_down_after.py @@ -6,7 +6,6 @@ from hc.api.models import Check class CheckModelTestCase(TestCase): - def test_it_handles_new_check(self): check = Check() self.assertEqual(check.going_down_after(), None) diff --git a/hc/api/tests/test_check_model.py b/hc/api/tests/test_check_model.py index af4cfd18..fec533e5 100644 --- a/hc/api/tests/test_check_model.py +++ b/hc/api/tests/test_check_model.py @@ -6,7 +6,6 @@ from hc.test import BaseTestCase class CheckModelTestCase(BaseTestCase): - def test_it_strips_tags(self): check = Check() diff --git a/hc/api/tests/test_create_check.py b/hc/api/tests/test_create_check.py index a657b35a..9dd80b59 100644 --- a/hc/api/tests/test_create_check.py +++ b/hc/api/tests/test_create_check.py @@ -21,13 +21,15 @@ class CreateCheckTestCase(BaseTestCase): return r def test_it_works(self): - r = self.post({ - "api_key": "X" * 32, - "name": "Foo", - "tags": "bar,baz", - "timeout": 3600, - "grace": 60 - }) + r = self.post( + { + "api_key": "X" * 32, + "name": "Foo", + "tags": "bar,baz", + "timeout": 3600, + "grace": 60, + } + ) self.assertEqual(r.status_code, 201) self.assertEqual(r["Access-Control-Allow-Origin"], "*") @@ -55,12 +57,9 @@ class CreateCheckTestCase(BaseTestCase): self.assertIn("POST", r["Access-Control-Allow-Methods"]) def test_30_days_works(self): - r = self.post({ - "api_key": "X" * 32, - "name": "Foo", - "timeout": 2592000, - "grace": 2592000 - }) + r = self.post( + {"api_key": "X" * 32, "name": "Foo", "timeout": 2592000, "grace": 2592000} + ) self.assertEqual(r.status_code, 201) @@ -70,9 +69,9 @@ class CreateCheckTestCase(BaseTestCase): def test_it_accepts_api_key_in_header(self): payload = json.dumps({"name": "Foo"}) - r = self.client.post(self.URL, payload, - content_type="application/json", - HTTP_X_API_KEY="X" * 32) + r = self.client.post( + self.URL, payload, content_type="application/json", HTTP_X_API_KEY="X" * 32 + ) self.assertEqual(r.status_code, 201) @@ -88,11 +87,7 @@ class CreateCheckTestCase(BaseTestCase): def test_it_supports_unique(self): Check.objects.create(project=self.project, name="Foo") - r = self.post({ - "api_key": "X" * 32, - "name": "Foo", - "unique": ["name"] - }) + r = self.post({"api_key": "X" * 32, "name": "Foo", "unique": ["name"]}) # Expect 200 instead of 201 self.assertEqual(r.status_code, 200) @@ -106,8 +101,9 @@ class CreateCheckTestCase(BaseTestCase): self.assertEqual(r.json()["error"], "missing api key") def test_it_handles_invalid_json(self): - r = self.client.post(self.URL, "this is not json", - content_type="application/json") + r = self.client.post( + self.URL, "this is not json", content_type="application/json" + ) self.assertEqual(r.status_code, 400) self.assertEqual(r.json()["error"], "could not parse request body") @@ -116,46 +112,56 @@ class CreateCheckTestCase(BaseTestCase): self.assertEqual(r.status_code, 401) def test_it_rejects_small_timeout(self): - self.post({"api_key": "X" * 32, "timeout": 0}, - expected_fragment="timeout is too small") + self.post( + {"api_key": "X" * 32, "timeout": 0}, + expected_fragment="timeout is too small", + ) def test_it_rejects_large_timeout(self): - self.post({"api_key": "X" * 32, "timeout": 2592001}, - expected_fragment="timeout is too large") + self.post( + {"api_key": "X" * 32, "timeout": 2592001}, + expected_fragment="timeout is too large", + ) def test_it_rejects_non_number_timeout(self): - self.post({"api_key": "X" * 32, "timeout": "oops"}, - expected_fragment="timeout is not a number") + self.post( + {"api_key": "X" * 32, "timeout": "oops"}, + expected_fragment="timeout is not a number", + ) def test_it_rejects_non_string_name(self): - self.post({"api_key": "X" * 32, "name": False}, - expected_fragment="name is not a string") + self.post( + {"api_key": "X" * 32, "name": False}, + expected_fragment="name is not a string", + ) def test_it_rejects_long_name(self): - self.post({"api_key": "X" * 32, "name": "01234567890" * 20}, - expected_fragment="name is too long") + self.post( + {"api_key": "X" * 32, "name": "01234567890" * 20}, + expected_fragment="name is too long", + ) def test_unique_accepts_only_whitelisted_values(self): - self.post({ - "api_key": "X" * 32, - "name": "Foo", - "unique": ["status"] - }, expected_fragment="unexpected value") + self.post( + {"api_key": "X" * 32, "name": "Foo", "unique": ["status"]}, + expected_fragment="unexpected value", + ) def test_it_rejects_bad_unique_values(self): - self.post({ - "api_key": "X" * 32, - "name": "Foo", - "unique": "not a list" - }, expected_fragment="not an array") + self.post( + {"api_key": "X" * 32, "name": "Foo", "unique": "not a list"}, + expected_fragment="not an array", + ) def test_it_supports_cron_syntax(self): - r = self.post({ - "api_key": "X" * 32, - "schedule": "5 * * * *", - "tz": "Europe/Riga", - "grace": 60 - }) + r = self.post( + { + "api_key": "X" * 32, + "schedule": "5 * * * *", + "tz": "Europe/Riga", + "grace": 60, + } + ) self.assertEqual(r.status_code, 201) @@ -167,22 +173,26 @@ class CreateCheckTestCase(BaseTestCase): self.assertTrue("timeout" not in doc) def test_it_validates_cron_expression(self): - r = self.post({ - "api_key": "X" * 32, - "schedule": "not-a-cron-expression", - "tz": "Europe/Riga", - "grace": 60 - }) + r = self.post( + { + "api_key": "X" * 32, + "schedule": "not-a-cron-expression", + "tz": "Europe/Riga", + "grace": 60, + } + ) self.assertEqual(r.status_code, 400) def test_it_validates_timezone(self): - r = self.post({ - "api_key": "X" * 32, - "schedule": "* * * * *", - "tz": "not-a-timezone", - "grace": 60 - }) + r = self.post( + { + "api_key": "X" * 32, + "schedule": "* * * * *", + "tz": "not-a-timezone", + "grace": 60, + } + ) self.assertEqual(r.status_code, 400) diff --git a/hc/api/tests/test_delete_check.py b/hc/api/tests/test_delete_check.py index be3af6a6..7bb2075c 100644 --- a/hc/api/tests/test_delete_check.py +++ b/hc/api/tests/test_delete_check.py @@ -3,14 +3,14 @@ from hc.test import BaseTestCase class DeleteCheckTestCase(BaseTestCase): - def setUp(self): super(DeleteCheckTestCase, self).setUp() self.check = Check.objects.create(project=self.project) def test_it_works(self): - r = self.client.delete("/api/v1/checks/%s" % self.check.code, - HTTP_X_API_KEY="X" * 32) + r = self.client.delete( + "/api/v1/checks/%s" % self.check.code, HTTP_X_API_KEY="X" * 32 + ) self.assertEqual(r.status_code, 200) self.assertEqual(r["Access-Control-Allow-Origin"], "*") diff --git a/hc/api/tests/test_list_channels.py b/hc/api/tests/test_list_channels.py index 48a255f2..0458aed6 100644 --- a/hc/api/tests/test_list_channels.py +++ b/hc/api/tests/test_list_channels.py @@ -5,7 +5,6 @@ from hc.test import BaseTestCase class ListChannelsTestCase(BaseTestCase): - def setUp(self): super(ListChannelsTestCase, self).setUp() @@ -36,8 +35,7 @@ class ListChannelsTestCase(BaseTestCase): self.assertIn("GET", r["Access-Control-Allow-Methods"]) def test_it_shows_only_users_channels(self): - Channel.objects.create(project=self.bobs_project, kind="email", - name="Bob") + Channel.objects.create(project=self.bobs_project, kind="email", name="Bob") r = self.get() data = r.json() @@ -47,8 +45,9 @@ class ListChannelsTestCase(BaseTestCase): def test_it_accepts_api_key_from_request_body(self): payload = json.dumps({"api_key": "X" * 32}) - r = self.client.generic("GET", "/api/v1/channels/", payload, - content_type="application/json") + r = self.client.generic( + "GET", "/api/v1/channels/", payload, content_type="application/json" + ) self.assertEqual(r.status_code, 200) self.assertContains(r, "Email to Alice") diff --git a/hc/api/tests/test_list_checks.py b/hc/api/tests/test_list_checks.py index 9b2f6b6d..e6c69074 100644 --- a/hc/api/tests/test_list_checks.py +++ b/hc/api/tests/test_list_checks.py @@ -8,7 +8,6 @@ from hc.test import BaseTestCase class ListChecksTestCase(BaseTestCase): - def setUp(self): super(ListChecksTestCase, self).setUp() @@ -91,8 +90,9 @@ class ListChecksTestCase(BaseTestCase): def test_it_accepts_api_key_from_request_body(self): payload = json.dumps({"api_key": "X" * 32}) - r = self.client.generic("GET", "/api/v1/checks/", payload, - content_type="application/json") + r = self.client.generic( + "GET", "/api/v1/checks/", payload, content_type="application/json" + ) self.assertEqual(r.status_code, 200) self.assertContains(r, "Alice") @@ -111,7 +111,9 @@ class ListChecksTestCase(BaseTestCase): self.assertEqual(check["tags"], "a2-tag") def test_it_filters_with_multiple_tags_param(self): - r = self.client.get("/api/v1/checks/?tag=a1-tag&tag=a1-additional-tag", HTTP_X_API_KEY="X" * 32) + r = self.client.get( + "/api/v1/checks/?tag=a1-tag&tag=a1-additional-tag", HTTP_X_API_KEY="X" * 32 + ) self.assertEqual(r.status_code, 200) doc = r.json() @@ -132,7 +134,10 @@ class ListChecksTestCase(BaseTestCase): self.assertEqual(len(doc["checks"]), 0) def test_non_existing_tags_filter_returns_empty_result(self): - r = self.client.get("/api/v1/checks/?tag=non_existing_tag_with_no_checks", HTTP_X_API_KEY="X" * 32) + r = self.client.get( + "/api/v1/checks/?tag=non_existing_tag_with_no_checks", + HTTP_X_API_KEY="X" * 32, + ) self.assertEqual(r.status_code, 200) doc = r.json() diff --git a/hc/api/tests/test_notify.py b/hc/api/tests/test_notify.py index 1438687f..9f1f034c 100644 --- a/hc/api/tests/test_notify.py +++ b/hc/api/tests/test_notify.py @@ -12,7 +12,6 @@ from requests.exceptions import ConnectionError, Timeout class NotifyTestCase(BaseTestCase): - def _setup_data(self, kind, value, status="down", email_verified=True): self.check = Check(project=self.project) self.check.status = status @@ -33,8 +32,11 @@ class NotifyTestCase(BaseTestCase): self.channel.notify(self.check) mock_get.assert_called_with( - "get", u"http://example", - headers={"User-Agent": "healthchecks.io"}, timeout=5) + "get", + u"http://example", + headers={"User-Agent": "healthchecks.io"}, + timeout=5, + ) @patch("hc.api.transports.requests.request", side_effect=Timeout) def test_webhooks_handle_timeouts(self, mock_get): @@ -80,8 +82,7 @@ class NotifyTestCase(BaseTestCase): self.channel.notify(self.check) - url = u"http://host/%s/down/foo/bar/?name=Hello%%20World" \ - % self.check.code + url = u"http://host/%s/down/foo/bar/?name=Hello%%20World" % self.check.code args, kwargs = mock_get.call_args self.assertEqual(args[0], "get") @@ -119,7 +120,8 @@ class NotifyTestCase(BaseTestCase): url = u"http://host/%24TAG1" mock_get.assert_called_with( - "get", url, headers={"User-Agent": "healthchecks.io"}, timeout=5) + "get", url, headers={"User-Agent": "healthchecks.io"}, timeout=5 + ) @patch("hc.api.transports.requests.request") def test_webhook_fires_on_up_event(self, mock_get): @@ -128,8 +130,8 @@ class NotifyTestCase(BaseTestCase): self.channel.notify(self.check) mock_get.assert_called_with( - "get", "http://bar", headers={"User-Agent": "healthchecks.io"}, - timeout=5) + "get", "http://bar", headers={"User-Agent": "healthchecks.io"}, timeout=5 + ) @patch("hc.api.transports.requests.request") def test_webhooks_handle_unicode_post_body(self, mock_request): @@ -151,7 +153,8 @@ class NotifyTestCase(BaseTestCase): headers = {"User-Agent": "healthchecks.io"} mock_request.assert_called_with( - "get", "http://foo.com", headers=headers, timeout=5) + "get", "http://foo.com", headers=headers, timeout=5 + ) @patch("hc.api.transports.requests.request") def test_webhooks_handle_json_up_event(self, mock_request): @@ -161,49 +164,44 @@ class NotifyTestCase(BaseTestCase): self.channel.notify(self.check) headers = {"User-Agent": "healthchecks.io"} - mock_request.assert_called_with( - "get", "http://bar", headers=headers, timeout=5) + mock_request.assert_called_with("get", "http://bar", headers=headers, timeout=5) @patch("hc.api.transports.requests.request") def test_webhooks_handle_post_headers(self, mock_request): definition = { "url_down": "http://foo.com", "post_data": "data", - "headers": {"Content-Type": "application/json"} + "headers": {"Content-Type": "application/json"}, } self._setup_data("webhook", json.dumps(definition)) self.channel.notify(self.check) - headers = { - "User-Agent": "healthchecks.io", - "Content-Type": "application/json" - } + headers = {"User-Agent": "healthchecks.io", "Content-Type": "application/json"} mock_request.assert_called_with( - "post", "http://foo.com", data=b"data", headers=headers, timeout=5) + "post", "http://foo.com", data=b"data", headers=headers, timeout=5 + ) @patch("hc.api.transports.requests.request") def test_webhooks_handle_get_headers(self, mock_request): definition = { "url_down": "http://foo.com", - "headers": {"Content-Type": "application/json"} + "headers": {"Content-Type": "application/json"}, } self._setup_data("webhook", json.dumps(definition)) self.channel.notify(self.check) - headers = { - "User-Agent": "healthchecks.io", - "Content-Type": "application/json" - } + headers = {"User-Agent": "healthchecks.io", "Content-Type": "application/json"} mock_request.assert_called_with( - "get", "http://foo.com", headers=headers, timeout=5) + "get", "http://foo.com", headers=headers, timeout=5 + ) @patch("hc.api.transports.requests.request") def test_webhooks_allow_user_agent_override(self, mock_request): definition = { "url_down": "http://foo.com", - "headers": {"User-Agent": "My-Agent"} + "headers": {"User-Agent": "My-Agent"}, } self._setup_data("webhook", json.dumps(definition)) @@ -211,13 +209,14 @@ class NotifyTestCase(BaseTestCase): headers = {"User-Agent": "My-Agent"} mock_request.assert_called_with( - "get", "http://foo.com", headers=headers, timeout=5) + "get", "http://foo.com", headers=headers, timeout=5 + ) @patch("hc.api.transports.requests.request") def test_webhooks_support_variables_in_headers(self, mock_request): definition = { "url_down": "http://foo.com", - "headers": {"X-Message": "$NAME is DOWN"} + "headers": {"X-Message": "$NAME is DOWN"}, } self._setup_data("webhook", json.dumps(definition)) @@ -226,12 +225,10 @@ class NotifyTestCase(BaseTestCase): self.channel.notify(self.check) - headers = { - "User-Agent": "healthchecks.io", - "X-Message": "Foo is DOWN" - } + headers = {"User-Agent": "healthchecks.io", "X-Message": "Foo is DOWN"} mock_request.assert_called_with( - "get", "http://foo.com", headers=headers, timeout=5) + "get", "http://foo.com", headers=headers, timeout=5 + ) def test_email(self): self._setup_data("email", "alice@example.org") diff --git a/hc/api/tests/test_pause.py b/hc/api/tests/test_pause.py index 9037d90d..eafbbe4c 100644 --- a/hc/api/tests/test_pause.py +++ b/hc/api/tests/test_pause.py @@ -6,13 +6,13 @@ from hc.test import BaseTestCase class PauseTestCase(BaseTestCase): - def test_it_works(self): check = Check.objects.create(project=self.project, status="up") url = "/api/v1/checks/%s/pause" % check.code - r = self.client.post(url, "", content_type="application/json", - HTTP_X_API_KEY="X" * 32) + r = self.client.post( + url, "", content_type="application/json", HTTP_X_API_KEY="X" * 32 + ) self.assertEqual(r.status_code, 200) self.assertEqual(r["Access-Control-Allow-Origin"], "*") @@ -37,22 +37,25 @@ class PauseTestCase(BaseTestCase): check = Check.objects.create(project=self.bobs_project, status="up") url = "/api/v1/checks/%s/pause" % check.code - r = self.client.post(url, "", content_type="application/json", - HTTP_X_API_KEY="X" * 32) + r = self.client.post( + url, "", content_type="application/json", HTTP_X_API_KEY="X" * 32 + ) self.assertEqual(r.status_code, 403) def test_it_validates_uuid(self): url = "/api/v1/checks/not-uuid/pause" - r = self.client.post(url, "", content_type="application/json", - HTTP_X_API_KEY="X" * 32) + r = self.client.post( + url, "", content_type="application/json", HTTP_X_API_KEY="X" * 32 + ) self.assertEqual(r.status_code, 404) def test_it_handles_missing_check(self): url = "/api/v1/checks/07c2f548-9850-4b27-af5d-6c9dc157ec02/pause" - r = self.client.post(url, "", content_type="application/json", - HTTP_X_API_KEY="X" * 32) + r = self.client.post( + url, "", content_type="application/json", HTTP_X_API_KEY="X" * 32 + ) self.assertEqual(r.status_code, 404) @@ -63,8 +66,9 @@ class PauseTestCase(BaseTestCase): check.save() url = "/api/v1/checks/%s/pause" % check.code - r = self.client.post(url, "", content_type="application/json", - HTTP_X_API_KEY="X" * 32) + r = self.client.post( + url, "", content_type="application/json", HTTP_X_API_KEY="X" * 32 + ) self.assertEqual(r.status_code, 200) self.assertEqual(r["Access-Control-Allow-Origin"], "*") diff --git a/hc/api/tests/test_ping.py b/hc/api/tests/test_ping.py index 96f84ea2..ec1ee7bb 100644 --- a/hc/api/tests/test_ping.py +++ b/hc/api/tests/test_ping.py @@ -7,7 +7,6 @@ from hc.test import BaseTestCase class PingTestCase(BaseTestCase): - def setUp(self): super().setUp() self.check = Check.objects.create(project=self.project) @@ -47,8 +46,9 @@ class PingTestCase(BaseTestCase): def test_post_works(self): csrf_client = Client(enforce_csrf_checks=True) - r = csrf_client.post("/ping/%s/" % self.check.code, "hello world", - content_type="text/plain") + r = csrf_client.post( + "/ping/%s/" % self.check.code, "hello world", content_type="text/plain" + ) self.assertEqual(r.status_code, 200) ping = Ping.objects.latest("id") @@ -75,9 +75,11 @@ class PingTestCase(BaseTestCase): self.assertEqual(r.status_code, 404) def test_it_handles_120_char_ua(self): - ua = ("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) " - "AppleWebKit/537.36 (KHTML, like Gecko) " - "Chrome/44.0.2403.89 Safari/537.36") + ua = ( + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) " + "AppleWebKit/537.36 (KHTML, like Gecko) " + "Chrome/44.0.2403.89 Safari/537.36" + ) r = self.client.get("/ping/%s/" % self.check.code, HTTP_USER_AGENT=ua) self.assertEqual(r.status_code, 200) @@ -97,22 +99,25 @@ class PingTestCase(BaseTestCase): def test_it_reads_forwarded_ip(self): ip = "1.1.1.1" - r = self.client.get("/ping/%s/" % self.check.code, - HTTP_X_FORWARDED_FOR=ip) + r = self.client.get("/ping/%s/" % self.check.code, HTTP_X_FORWARDED_FOR=ip) ping = Ping.objects.latest("id") self.assertEqual(r.status_code, 200) self.assertEqual(ping.remote_addr, "1.1.1.1") ip = "1.1.1.1, 2.2.2.2" - r = self.client.get("/ping/%s/" % self.check.code, - HTTP_X_FORWARDED_FOR=ip, REMOTE_ADDR="3.3.3.3") + r = self.client.get( + "/ping/%s/" % self.check.code, + HTTP_X_FORWARDED_FOR=ip, + REMOTE_ADDR="3.3.3.3", + ) ping = Ping.objects.latest("id") self.assertEqual(r.status_code, 200) self.assertEqual(ping.remote_addr, "1.1.1.1") def test_it_reads_forwarded_protocol(self): - r = self.client.get("/ping/%s/" % self.check.code, - HTTP_X_FORWARDED_PROTO="https") + r = self.client.get( + "/ping/%s/" % self.check.code, HTTP_X_FORWARDED_PROTO="https" + ) ping = Ping.objects.latest("id") self.assertEqual(r.status_code, 200) self.assertEqual(ping.scheme, "https") @@ -123,8 +128,9 @@ class PingTestCase(BaseTestCase): def test_it_updates_confirmation_flag(self): payload = "Please Confirm ..." - r = self.client.post("/ping/%s/" % self.check.code, data=payload, - content_type="text/plain") + r = self.client.post( + "/ping/%s/" % self.check.code, data=payload, content_type="text/plain" + ) self.assertEqual(r.status_code, 200) self.check.refresh_from_db() diff --git a/hc/api/tests/test_sendalerts.py b/hc/api/tests/test_sendalerts.py index e709c24b..95ab009b 100644 --- a/hc/api/tests/test_sendalerts.py +++ b/hc/api/tests/test_sendalerts.py @@ -10,7 +10,6 @@ from hc.test import BaseTestCase class SendAlertsTestCase(BaseTestCase): - def test_it_handles_grace_period(self): check = Check(project=self.project, status="up") # 1 day 30 minutes after ping the check is in grace period: @@ -97,8 +96,7 @@ class SendAlertsTestCase(BaseTestCase): check.alert_after = check.last_ping + td(days=1, hours=1) check.save() - call_command("sendalerts", loop=False, use_threads=False, - stdout=StringIO()) + call_command("sendalerts", loop=False, use_threads=False, stdout=StringIO()) # It should call `notify` instead of `notify_on_thread` self.assertTrue(mock_notify.called) diff --git a/hc/api/tests/test_sendreports.py b/hc/api/tests/test_sendreports.py index 9da2d940..e61fe093 100644 --- a/hc/api/tests/test_sendreports.py +++ b/hc/api/tests/test_sendreports.py @@ -9,7 +9,6 @@ from mock import Mock class SendAlertsTestCase(BaseTestCase): - def setUp(self): super(SendAlertsTestCase, self).setUp() diff --git a/hc/api/tests/test_tokenbucket.py b/hc/api/tests/test_tokenbucket.py index 03506d33..34329173 100644 --- a/hc/api/tests/test_tokenbucket.py +++ b/hc/api/tests/test_tokenbucket.py @@ -11,7 +11,6 @@ ALICE_HASH = "d60db3b2343e713a4de3e92d4eb417e4f05f06ab" @override_settings(SECRET_KEY="test-secret") class TokenBucketTestCase(BaseTestCase): - def test_it_works(self): r = TokenBucket.authorize_login_email("alice@example.org") self.assertTrue(r) diff --git a/hc/api/tests/test_update_check.py b/hc/api/tests/test_update_check.py index a8c7addb..40004e45 100644 --- a/hc/api/tests/test_update_check.py +++ b/hc/api/tests/test_update_check.py @@ -5,7 +5,6 @@ from hc.test import BaseTestCase class UpdateCheckTestCase(BaseTestCase): - def setUp(self): super(UpdateCheckTestCase, self).setUp() self.check = Check.objects.create(project=self.project) @@ -15,13 +14,16 @@ class UpdateCheckTestCase(BaseTestCase): return self.client.post(url, data, content_type="application/json") def test_it_works(self): - r = self.post(self.check.code, { - "api_key": "X" * 32, - "name": "Foo", - "tags": "bar,baz", - "timeout": 3600, - "grace": 60 - }) + r = self.post( + self.check.code, + { + "api_key": "X" * 32, + "name": "Foo", + "tags": "bar,baz", + "timeout": 3600, + "grace": 60, + }, + ) self.assertEqual(r.status_code, 200) self.assertEqual(r["Access-Control-Allow-Origin"], "*") @@ -53,10 +55,7 @@ class UpdateCheckTestCase(BaseTestCase): Channel.objects.create(project=self.project) self.check.assign_all_channels() - r = self.post(self.check.code, { - "api_key": "X" * 32, - "channels": "" - }) + r = self.post(self.check.code, {"api_key": "X" * 32, "channels": ""}) self.assertEqual(r.status_code, 200) check = Check.objects.get() @@ -99,10 +98,9 @@ class UpdateCheckTestCase(BaseTestCase): # gets assigned: Channel.objects.create(project=self.project) - r = self.post(self.check.code, { - "api_key": "X" * 32, - "channels": str(channel.code) - }) + r = self.post( + self.check.code, {"api_key": "X" * 32, "channels": str(channel.code)} + ) self.assertEqual(r.status_code, 200) @@ -113,10 +111,10 @@ class UpdateCheckTestCase(BaseTestCase): def test_it_handles_comma_separated_channel_codes(self): c1 = Channel.objects.create(project=self.project) c2 = Channel.objects.create(project=self.project) - r = self.post(self.check.code, { - "api_key": "X" * 32, - "channels": "%s,%s" % (c1.code, c2.code) - }) + r = self.post( + self.check.code, + {"api_key": "X" * 32, "channels": "%s,%s" % (c1.code, c2.code)}, + ) self.assertEqual(r.status_code, 200) @@ -126,10 +124,7 @@ class UpdateCheckTestCase(BaseTestCase): def test_it_handles_asterix(self): Channel.objects.create(project=self.project) Channel.objects.create(project=self.project) - r = self.post(self.check.code, { - "api_key": "X" * 32, - "channels": "*" - }) + r = self.post(self.check.code, {"api_key": "X" * 32, "channels": "*"}) self.assertEqual(r.status_code, 200) @@ -146,10 +141,9 @@ class UpdateCheckTestCase(BaseTestCase): self.assertEqual(check.channel_set.count(), 1) def test_it_rejects_bad_channel_code(self): - r = self.post(self.check.code, { - "api_key": "X" * 32, - "channels": str(uuid.uuid4()) - }) + r = self.post( + self.check.code, {"api_key": "X" * 32, "channels": str(uuid.uuid4())} + ) self.assertEqual(r.status_code, 400) @@ -157,10 +151,7 @@ class UpdateCheckTestCase(BaseTestCase): self.assertEqual(self.check.channel_set.count(), 0) def test_it_rejects_non_uuid_channel_code(self): - r = self.post(self.check.code, { - "api_key": "X" * 32, - "channels": "foo" - }) + r = self.post(self.check.code, {"api_key": "X" * 32, "channels": "foo"}) self.assertEqual(r.status_code, 400) @@ -168,9 +159,6 @@ class UpdateCheckTestCase(BaseTestCase): self.assertEqual(self.check.channel_set.count(), 0) def test_it_rejects_non_string_channels_key(self): - r = self.post(self.check.code, { - "api_key": "X" * 32, - "channels": None - }) + r = self.post(self.check.code, {"api_key": "X" * 32, "channels": None}) self.assertEqual(r.status_code, 400) diff --git a/hc/api/transports.py b/hc/api/transports.py index 5263042c..b2a6b118 100644 --- a/hc/api/transports.py +++ b/hc/api/transports.py @@ -52,10 +52,7 @@ class Email(Transport): unsub_link = self.channel.get_unsub_link() - headers = { - "X-Bounce-Url": bounce_url, - "List-Unsubscribe": unsub_link - } + headers = {"X-Bounce-Url": bounce_url, "List-Unsubscribe": unsub_link} try: # Look up the sorting preference for this email address @@ -72,7 +69,7 @@ class Email(Transport): "checks": list(self.checks()), "sort": sort, "now": timezone.now(), - "unsub_link": unsub_link + "unsub_link": unsub_link, } emails.alert(self.channel.email_value, ctx, headers) @@ -88,7 +85,6 @@ class Email(Transport): class HttpTransport(Transport): - @classmethod def _request(cls, method, url, **kwargs): try: @@ -213,24 +209,19 @@ class HipChat(HttpTransport): class OpsGenie(HttpTransport): - def notify(self, check): headers = { "Conent-Type": "application/json", - "Authorization": "GenieKey %s" % self.channel.value + "Authorization": "GenieKey %s" % self.channel.value, } - payload = { - "alias": str(check.code), - "source": settings.SITE_NAME - } + payload = {"alias": str(check.code), "source": settings.SITE_NAME} if check.status == "down": payload["tags"] = check.tags_list() payload["message"] = tmpl("opsgenie_message.html", check=check) payload["note"] = tmpl("opsgenie_note.html", check=check) - payload["description"] = \ - tmpl("opsgenie_description.html", check=check) + payload["description"] = tmpl("opsgenie_description.html", check=check) url = "https://api.opsgenie.com/v2/alerts" if check.status == "up": @@ -251,7 +242,7 @@ class PagerDuty(HttpTransport): "event_type": "trigger" if check.status == "down" else "resolve", "description": description, "client": settings.SITE_NAME, - "client_url": settings.SITE_ROOT + "client_url": settings.SITE_ROOT, } return self.post(self.URL, json=payload) @@ -260,9 +251,7 @@ class PagerDuty(HttpTransport): class PagerTree(HttpTransport): def notify(self, check): url = self.channel.value - headers = { - "Conent-Type": "application/json" - } + headers = {"Conent-Type": "application/json"} payload = { "incident_key": str(check.code), "event_type": "trigger" if check.status == "down" else "resolve", @@ -270,17 +259,16 @@ class PagerTree(HttpTransport): "description": tmpl("pagertree_description.html", check=check), "client": settings.SITE_NAME, "client_url": settings.SITE_ROOT, - "tags": ",".join(check.tags_list()) + "tags": ",".join(check.tags_list()), } return self.post(url, json=payload, headers=headers) + class PagerTeam(HttpTransport): def notify(self, check): url = self.channel.value - headers = { - "Conent-Type": "application/json" - } + headers = {"Conent-Type": "application/json"} payload = { "incident_key": str(check.code), "event_type": "trigger" if check.status == "down" else "resolve", @@ -288,7 +276,7 @@ class PagerTeam(HttpTransport): "description": tmpl("pagerteam_description.html", check=check), "client": settings.SITE_NAME, "client_url": settings.SITE_ROOT, - "tags": ",".join(check.tags_list()) + "tags": ",".join(check.tags_list()), } return self.post(url, json=payload, headers=headers) @@ -300,13 +288,9 @@ class Pushbullet(HttpTransport): url = "https://api.pushbullet.com/v2/pushes" headers = { "Access-Token": self.channel.value, - "Conent-Type": "application/json" - } - payload = { - "type": "note", - "title": settings.SITE_NAME, - "body": text + "Conent-Type": "application/json", } + payload = {"type": "note", "title": settings.SITE_NAME, "body": text} return self.post(url, json=payload, headers=headers) @@ -319,10 +303,7 @@ class Pushover(HttpTransport): # list() executes the query, to avoid DB access while # rendering a template - ctx = { - "check": check, - "down_checks": list(others), - } + ctx = {"check": check, "down_checks": list(others)} text = tmpl("pushover_message.html", **ctx) title = tmpl("pushover_title.html", **ctx) @@ -380,7 +361,7 @@ class Matrix(HttpTransport): "msgtype": "m.text", "body": plain, "format": "org.matrix.custom.html", - "formatted_body": formatted + "formatted_body": formatted, } return self.post(self.get_url(), json=payload) @@ -399,11 +380,9 @@ class Telegram(HttpTransport): @classmethod def send(cls, chat_id, text): - return cls.post(cls.SM, json={ - "chat_id": chat_id, - "text": text, - "parse_mode": "html" - }) + return cls.post( + cls.SM, json={"chat_id": chat_id, "text": text, "parse_mode": "html"} + ) def notify(self, check): text = tmpl("telegram_message.html", check=check) @@ -411,7 +390,7 @@ class Telegram(HttpTransport): class Sms(HttpTransport): - URL = 'https://api.twilio.com/2010-04-01/Accounts/%s/Messages.json' + URL = "https://api.twilio.com/2010-04-01/Accounts/%s/Messages.json" def is_noop(self, check): return check.status != "down" @@ -423,20 +402,19 @@ class Sms(HttpTransport): url = self.URL % settings.TWILIO_ACCOUNT auth = (settings.TWILIO_ACCOUNT, settings.TWILIO_AUTH) - text = tmpl("sms_message.html", check=check, - site_name=settings.SITE_NAME) + text = tmpl("sms_message.html", check=check, site_name=settings.SITE_NAME) data = { - 'From': settings.TWILIO_FROM, - 'To': self.channel.sms_number, - 'Body': text, + "From": settings.TWILIO_FROM, + "To": self.channel.sms_number, + "Body": text, } return self.post(url, data=data, auth=auth) class Trello(HttpTransport): - URL = 'https://api.trello.com/1/cards' + URL = "https://api.trello.com/1/cards" def is_noop(self, check): return check.status != "down" @@ -447,7 +425,7 @@ class Trello(HttpTransport): "name": tmpl("trello_name.html", check=check), "desc": tmpl("trello_desc.html", check=check), "key": settings.TRELLO_APP_KEY, - "token": self.channel.trello_token + "token": self.channel.trello_token, } return self.post(self.URL, params=params) diff --git a/hc/api/urls.py b/hc/api/urls.py index cf035c45..ddb3c154 100644 --- a/hc/api/urls.py +++ b/hc/api/urls.py @@ -5,7 +5,7 @@ from hc.api import views class QuoteConverter: - regex = '[\w%~_.-]+' + regex = "[\w%~_.-]+" def to_python(self, value): return unquote(value) @@ -14,34 +14,40 @@ class QuoteConverter: return quote(value, safe="") -register_converter(QuoteConverter, 'quoted') +register_converter(QuoteConverter, "quoted") urlpatterns = [ - path('ping//', views.ping, name="hc-ping-slash"), - path('ping/', views.ping, name="hc-ping"), - path('ping//fail', views.ping, {"action": "fail"}, name="hc-fail"), - path('ping//start', views.ping, {"action": "start"}, name="hc-start"), - - path('api/v1/checks/', views.checks), - path('api/v1/checks/', views.update, name="hc-api-update"), - path('api/v1/checks//pause', views.pause, name="hc-api-pause"), - path('api/v1/notifications//bounce', views.bounce, - name="hc-api-bounce"), - - path('api/v1/channels/', views.channels), - - - path('badge///.svg', views.badge, - name="hc-badge"), - - path('badge//.svg', views.badge, - {"tag": "*"}, name="hc-badge-all"), - - path('badge///.json', views.badge, - {"format": "json"}, name="hc-badge-json"), - - path('badge//.json', views.badge, - {"format": "json", "tag": "*"}, name="hc-badge-json-all"), - - path('api/v1/status/', views.status), + path("ping//", views.ping, name="hc-ping-slash"), + path("ping/", views.ping, name="hc-ping"), + path("ping//fail", views.ping, {"action": "fail"}, name="hc-fail"), + path("ping//start", views.ping, {"action": "start"}, name="hc-start"), + path("api/v1/checks/", views.checks), + path("api/v1/checks/", views.update, name="hc-api-update"), + path("api/v1/checks//pause", views.pause, name="hc-api-pause"), + path("api/v1/notifications//bounce", views.bounce, name="hc-api-bounce"), + path("api/v1/channels/", views.channels), + path( + "badge///.svg", + views.badge, + name="hc-badge", + ), + path( + "badge//.svg", + views.badge, + {"tag": "*"}, + name="hc-badge-all", + ), + path( + "badge///.json", + views.badge, + {"format": "json"}, + name="hc-badge-json", + ), + path( + "badge//.json", + views.badge, + {"format": "json", "tag": "*"}, + name="hc-badge-json-all", + ), + path("api/v1/status/", views.status), ] diff --git a/hc/api/views.py b/hc/api/views.py index 5f094483..38a5a2e6 100644 --- a/hc/api/views.py +++ b/hc/api/views.py @@ -4,8 +4,12 @@ import uuid from django.conf import settings from django.core.exceptions import SuspiciousOperation from django.db import connection -from django.http import (HttpResponse, HttpResponseForbidden, - HttpResponseNotFound, JsonResponse) +from django.http import ( + HttpResponse, + HttpResponseForbidden, + HttpResponseNotFound, + JsonResponse, +) from django.shortcuts import get_object_or_404 from django.utils import timezone from django.views.decorators.cache import never_cache @@ -228,12 +232,9 @@ def badge(request, badge_key, signature, tag, format="svg"): status = "late" if format == "json": - return JsonResponse({ - "status": status, - "total": total, - "grace": grace, - "down": down - }) + return JsonResponse( + {"status": status, "total": total, "grace": grace, "down": down} + ) svg = get_badge_svg(label, status) return HttpResponse(svg, content_type="image/svg+xml") diff --git a/hc/front/forms.py b/hc/front/forms.py index cad5c03a..a43f0856 100644 --- a/hc/front/forms.py +++ b/hc/front/forms.py @@ -6,8 +6,11 @@ from urllib.parse import quote, urlencode from django import forms from django.conf import settings from django.core.validators import RegexValidator -from hc.front.validators import (CronExpressionValidator, TimezoneValidator, - WebhookValidator) +from hc.front.validators import ( + CronExpressionValidator, + TimezoneValidator, + WebhookValidator, +) import requests @@ -43,8 +46,7 @@ class TimeoutForm(forms.Form): class CronForm(forms.Form): - schedule = forms.CharField(max_length=100, - validators=[CronExpressionValidator()]) + schedule = forms.CharField(max_length=100, validators=[CronExpressionValidator()]) tz = forms.CharField(max_length=36, validators=[TimezoneValidator()]) grace = forms.IntegerField(min_value=1, max_value=43200) @@ -66,17 +68,19 @@ class AddUrlForm(forms.Form): value = forms.URLField(max_length=1000, validators=[WebhookValidator()]) -_valid_header_name = re.compile(r'\A[^:\s][^:\r\n]*\Z').match +_valid_header_name = re.compile(r"\A[^:\s][^:\r\n]*\Z").match class AddWebhookForm(forms.Form): error_css_class = "has-error" - url_down = forms.URLField(max_length=1000, required=False, - validators=[WebhookValidator()]) + url_down = forms.URLField( + max_length=1000, required=False, validators=[WebhookValidator()] + ) - url_up = forms.URLField(max_length=1000, required=False, - validators=[WebhookValidator()]) + url_up = forms.URLField( + max_length=1000, required=False, validators=[WebhookValidator()] + ) post_data = forms.CharField(max_length=1000, required=False) @@ -109,8 +113,9 @@ class AddWebhookForm(forms.Form): return json.dumps(val, sort_keys=True) -phone_validator = RegexValidator(regex='^\+\d{5,15}$', - message="Invalid phone number format.") +phone_validator = RegexValidator( + regex="^\+\d{5,15}$", message="Invalid phone number format." +) class AddSmsForm(forms.Form): @@ -136,8 +141,7 @@ class AddMatrixForm(forms.Form): url += urlencode({"access_token": settings.MATRIX_ACCESS_TOKEN}) doc = requests.post(url, {}).json() if "error" in doc: - raise forms.ValidationError( - "Response from Matrix: %s" % doc["error"]) + raise forms.ValidationError("Response from Matrix: %s" % doc["error"]) self.cleaned_data["room_id"] = doc["room_id"] diff --git a/hc/front/management/commands/pygmentize.py b/hc/front/management/commands/pygmentize.py index 350c62f3..59a4e717 100644 --- a/hc/front/management/commands/pygmentize.py +++ b/hc/front/management/commands/pygmentize.py @@ -4,6 +4,7 @@ from django.core.management.base import BaseCommand def _process(name, lexer): from pygments import highlight from pygments.formatters import HtmlFormatter + source = open("templates/front/snippets/%s.txt" % name).read() processed = highlight(source, lexer, HtmlFormatter()) processed = processed.replace("PING_URL", "{{ ping_url }}") @@ -14,7 +15,7 @@ def _process(name, lexer): class Command(BaseCommand): - help = 'Compiles snippets with Pygments' + help = "Compiles snippets with Pygments" def handle(self, *args, **options): diff --git a/hc/front/schemas.py b/hc/front/schemas.py index 7bbd976b..3ecc9e53 100644 --- a/hc/front/schemas.py +++ b/hc/front/schemas.py @@ -10,14 +10,14 @@ telegram_callback = { "id": {"type": "number"}, "type": {"enum": ["group", "private", "supergroup"]}, "title": {"type": "string"}, - "username": {"type": "string"} + "username": {"type": "string"}, }, - "required": ["id", "type"] + "required": ["id", "type"], }, - "text": {"type": "string"} + "text": {"type": "string"}, }, - "required": ["chat", "text"] + "required": ["chat", "text"], } }, - "required": ["message"] + "required": ["message"], } diff --git a/hc/front/templatetags/hc_extras.py b/hc/front/templatetags/hc_extras.py index 78a1010c..2d20ae34 100644 --- a/hc/front/templatetags/hc_extras.py +++ b/hc/front/templatetags/hc_extras.py @@ -38,22 +38,24 @@ def site_root(): @register.simple_tag def debug_warning(): if settings.DEBUG: - return mark_safe(""" + return mark_safe( + """
Running in debug mode, do not use in production.
- """) + """ + ) return "" def naturalize_int_match(match): - return '%08d' % (int(match.group(0)),) + return "%08d" % (int(match.group(0)),) def natural_name_key(check): s = check.name.lower().strip() - return re.sub(r'\d+', naturalize_int_match, s) + return re.sub(r"\d+", naturalize_int_match, s) def last_ping_key(check): diff --git a/hc/front/tests/test_add_discord.py b/hc/front/tests/test_add_discord.py index 5d05de20..214d0336 100644 --- a/hc/front/tests/test_add_discord.py +++ b/hc/front/tests/test_add_discord.py @@ -33,10 +33,7 @@ class AddDiscordTestCase(BaseTestCase): oauth_response = { "access_token": "test-token", - "webhook": { - "url": "foo", - "id": "bar" - } + "webhook": {"url": "foo", "id": "bar"}, } mock_post.return_value.text = json.dumps(oauth_response) diff --git a/hc/front/tests/test_add_pushover.py b/hc/front/tests/test_add_pushover.py index 1206ed40..fe55ff49 100644 --- a/hc/front/tests/test_add_pushover.py +++ b/hc/front/tests/test_add_pushover.py @@ -3,7 +3,9 @@ from hc.api.models import Channel from hc.test import BaseTestCase -@override_settings(PUSHOVER_API_TOKEN="token", PUSHOVER_SUBSCRIPTION_URL="http://example.org") +@override_settings( + PUSHOVER_API_TOKEN="token", PUSHOVER_SUBSCRIPTION_URL="http://example.org" +) class AddPushoverTestCase(BaseTestCase): @override_settings(PUSHOVER_API_TOKEN=None) def test_it_requires_api_token(self): diff --git a/hc/front/tests/test_add_slack_btn.py b/hc/front/tests/test_add_slack_btn.py index d78e95bd..8b724cdf 100644 --- a/hc/front/tests/test_add_slack_btn.py +++ b/hc/front/tests/test_add_slack_btn.py @@ -7,12 +7,10 @@ from mock import patch class AddSlackBtnTestCase(BaseTestCase): - @override_settings(SLACK_CLIENT_ID="foo") def test_it_prepares_login_link(self): r = self.client.get("/integrations/add_slack/") - self.assertContains(r, "Before adding Slack integration", - status_code=200) + self.assertContains(r, "Before adding Slack integration", status_code=200) self.assertContains(r, "?next=/integrations/add_slack/") @@ -34,10 +32,7 @@ class AddSlackBtnTestCase(BaseTestCase): oauth_response = { "ok": True, "team_name": "foo", - "incoming_webhook": { - "url": "http://example.org", - "channel": "bar" - } + "incoming_webhook": {"url": "http://example.org", "channel": "bar"}, } mock_post.return_value.text = json.dumps(oauth_response) @@ -76,10 +71,7 @@ class AddSlackBtnTestCase(BaseTestCase): session["slack"] = "foo" session.save() - oauth_response = { - "ok": False, - "error": "something went wrong" - } + oauth_response = {"ok": False, "error": "something went wrong"} mock_post.return_value.text = json.dumps(oauth_response) mock_post.return_value.json.return_value = oauth_response diff --git a/hc/front/tests/test_add_telegram.py b/hc/front/tests/test_add_telegram.py index f4a7a43d..5b106c94 100644 --- a/hc/front/tests/test_add_telegram.py +++ b/hc/front/tests/test_add_telegram.py @@ -37,16 +37,13 @@ class AddTelegramTestCase(BaseTestCase): def test_it_sends_invite(self, mock_get): data = { "message": { - "chat": { - "id": 123, - "title": "My Group", - "type": "group" - }, - "text": "/start" + "chat": {"id": 123, "title": "My Group", "type": "group"}, + "text": "/start", } } - r = self.client.post("/integrations/telegram/bot/", data, - content_type="application/json") + r = self.client.post( + "/integrations/telegram/bot/", data, content_type="application/json" + ) self.assertEqual(r.status_code, 200) self.assertTrue(mock_get.called) @@ -56,21 +53,17 @@ class AddTelegramTestCase(BaseTestCase): samples = ["", "{}"] # text is missing - samples.append({ - "message": {"chat": {"id": 123, "type": "group"}} - }) + samples.append({"message": {"chat": {"id": 123, "type": "group"}}}) # bad chat type - samples.append({ - "message": { - "chat": {"id": 123, "type": "invalid"}, - "text": "/start" - } - }) + samples.append( + {"message": {"chat": {"id": 123, "type": "invalid"}, "text": "/start"}} + ) for sample in samples: - r = self.client.post("/integrations/telegram/bot/", sample, - content_type="application/json") + r = self.client.post( + "/integrations/telegram/bot/", sample, content_type="application/json" + ) if sample == "": # Bad JSON payload @@ -78,4 +71,3 @@ class AddTelegramTestCase(BaseTestCase): else: # JSON decodes but message structure not recognized self.assertEqual(r.status_code, 200) - diff --git a/hc/front/tests/test_add_trello.py b/hc/front/tests/test_add_trello.py index 8c9647bd..55a9406e 100644 --- a/hc/front/tests/test_add_trello.py +++ b/hc/front/tests/test_add_trello.py @@ -16,12 +16,16 @@ class AddPagerTreeTestCase(BaseTestCase): @override_settings(TRELLO_APP_KEY="foo") def test_it_works(self): - form = {"settings": json.dumps({ - "token": "fake-token", - "board_name": "My Board", - "list_name": "My List", - "list_id": "fake-list-id" - })} + form = { + "settings": json.dumps( + { + "token": "fake-token", + "board_name": "My Board", + "list_name": "My List", + "list_id": "fake-list-id", + } + ) + } self.client.login(username="alice@example.org", password="password") r = self.client.post(self.url, form) diff --git a/hc/front/tests/test_add_webhook.py b/hc/front/tests/test_add_webhook.py index 1ddbda50..cbe26d15 100644 --- a/hc/front/tests/test_add_webhook.py +++ b/hc/front/tests/test_add_webhook.py @@ -18,7 +18,10 @@ class AddWebhookTestCase(BaseTestCase): self.assertRedirects(r, "/integrations/") c = Channel.objects.get() - self.assertEqual(c.value, '{"headers": {}, "post_data": "", "url_down": "http://foo.com", "url_up": "https://bar.com"}') + self.assertEqual( + c.value, + '{"headers": {}, "post_data": "", "url_down": "http://foo.com", "url_up": "https://bar.com"}', + ) self.assertEqual(c.project, self.project) def test_it_adds_webhook_using_team_access(self): @@ -31,7 +34,10 @@ class AddWebhookTestCase(BaseTestCase): c = Channel.objects.get() self.assertEqual(c.project, self.project) - self.assertEqual(c.value, '{"headers": {}, "post_data": "", "url_down": "http://foo.com", "url_up": "https://bar.com"}') + self.assertEqual( + c.value, + '{"headers": {}, "post_data": "", "url_down": "http://foo.com", "url_up": "https://bar.com"}', + ) def test_it_rejects_bad_urls(self): urls = [ @@ -41,7 +47,7 @@ class AddWebhookTestCase(BaseTestCase): "ftp://example.org", # no loopback "http://localhost:1234/endpoint", - "http://127.0.0.1/endpoint" + "http://127.0.0.1/endpoint", ] self.client.login(username="alice@example.org", password="password") @@ -60,7 +66,10 @@ class AddWebhookTestCase(BaseTestCase): self.client.post(self.url, form) c = Channel.objects.get() - self.assertEqual(c.value, '{"headers": {}, "post_data": "", "url_down": "", "url_up": "http://foo.com"}') + self.assertEqual( + c.value, + '{"headers": {}, "post_data": "", "url_down": "", "url_up": "http://foo.com"}', + ) def test_it_adds_post_data(self): form = {"url_down": "http://foo.com", "post_data": "hello"} @@ -70,13 +79,16 @@ class AddWebhookTestCase(BaseTestCase): self.assertRedirects(r, "/integrations/") c = Channel.objects.get() - self.assertEqual(c.value, '{"headers": {}, "post_data": "hello", "url_down": "http://foo.com", "url_up": ""}') + self.assertEqual( + c.value, + '{"headers": {}, "post_data": "hello", "url_down": "http://foo.com", "url_up": ""}', + ) def test_it_adds_headers(self): form = { "url_down": "http://foo.com", "header_key[]": ["test", "test2"], - "header_value[]": ["123", "abc"] + "header_value[]": ["123", "abc"], } self.client.login(username="alice@example.org", password="password") @@ -91,7 +103,7 @@ class AddWebhookTestCase(BaseTestCase): form = { "url_down": "http://example.org", "header_key[]": ["ill:egal"], - "header_value[]": ["123"] + "header_value[]": ["123"], } r = self.client.post(self.url, form) diff --git a/hc/front/tests/test_badges.py b/hc/front/tests/test_badges.py index 705193e3..c79ed9c8 100644 --- a/hc/front/tests/test_badges.py +++ b/hc/front/tests/test_badges.py @@ -3,7 +3,6 @@ from hc.api.models import Check class BadgesTestCase(BaseTestCase): - def setUp(self): super(BadgesTestCase, self).setUp() diff --git a/hc/front/tests/test_basics.py b/hc/front/tests/test_basics.py index 95098968..fd3cbbaf 100644 --- a/hc/front/tests/test_basics.py +++ b/hc/front/tests/test_basics.py @@ -3,7 +3,6 @@ from django.test.utils import override_settings class BasicsTestCase(TestCase): - def test_it_shows_welcome(self): r = self.client.get("/") self.assertContains(r, "Get Notified", status_code=200) diff --git a/hc/front/tests/test_channel_checks.py b/hc/front/tests/test_channel_checks.py index df04918d..84698ede 100644 --- a/hc/front/tests/test_channel_checks.py +++ b/hc/front/tests/test_channel_checks.py @@ -3,7 +3,6 @@ from hc.test import BaseTestCase class ChannelChecksTestCase(BaseTestCase): - def setUp(self): super(ChannelChecksTestCase, self).setUp() self.channel = Channel(project=self.project, kind="email") diff --git a/hc/front/tests/test_channels.py b/hc/front/tests/test_channels.py index 36c33c7d..e6e95991 100644 --- a/hc/front/tests/test_channels.py +++ b/hc/front/tests/test_channels.py @@ -5,17 +5,15 @@ from hc.test import BaseTestCase class ChannelsTestCase(BaseTestCase): - def test_it_formats_complex_slack_value(self): ch = Channel(kind="slack", project=self.project) - ch.value = json.dumps({ - "ok": True, - "team_name": "foo-team", - "incoming_webhook": { - "url": "http://example.org", - "channel": "#bar" + ch.value = json.dumps( + { + "ok": True, + "team_name": "foo-team", + "incoming_webhook": {"url": "http://example.org", "channel": "#bar"}, } - }) + ) ch.save() self.client.login(username="alice@example.org", password="password") @@ -76,11 +74,9 @@ class ChannelsTestCase(BaseTestCase): def test_it_shows_down_only_note_for_email(self): channel = Channel(project=self.project, kind="email") - channel.value = json.dumps({ - "value": "alice@example.org", - "up": False, - "down": True - }) + channel.value = json.dumps( + {"value": "alice@example.org", "up": False, "down": True} + ) channel.save() self.client.login(username="alice@example.org", password="password") @@ -90,11 +86,9 @@ class ChannelsTestCase(BaseTestCase): def test_it_shows_up_only_note_for_email(self): channel = Channel(project=self.project, kind="email") - channel.value = json.dumps({ - "value": "alice@example.org", - "up": True, - "down": False - }) + channel.value = json.dumps( + {"value": "alice@example.org", "up": True, "down": False} + ) channel.save() self.client.login(username="alice@example.org", password="password") diff --git a/hc/front/tests/test_cron_preview.py b/hc/front/tests/test_cron_preview.py index 8fced14c..0b226cdb 100644 --- a/hc/front/tests/test_cron_preview.py +++ b/hc/front/tests/test_cron_preview.py @@ -6,21 +6,13 @@ import pytz class CronPreviewTestCase(BaseTestCase): - def test_it_works(self): - payload = { - "schedule": "* * * * *", - "tz": "UTC" - } + payload = {"schedule": "* * * * *", "tz": "UTC"} r = self.client.post("/checks/cron_preview/", payload) self.assertContains(r, "cron-preview-title", status_code=200) def test_it_rejects_invalid_cron_expression(self): - samples = ["", - "*", - "100 100 100 100 100", - "* * * * * *", - "1,2 3,* * * *"] + samples = ["", "*", "100 100 100 100 100", "* * * * * *", "1,2 3,* * * *"] for schedule in samples: payload = {"schedule": schedule, "tz": "UTC"} @@ -52,9 +44,6 @@ class CronPreviewTestCase(BaseTestCase): # This schedule will hit the ambiguous date. Cron preview must # be able to handle this: - payload = { - "schedule": "0 3 * * *", - "tz": "Europe/Riga" - } + payload = {"schedule": "0 3 * * *", "tz": "Europe/Riga"} r = self.client.post("/checks/cron_preview/", payload) self.assertNotContains(r, "Invalid cron expression", status_code=200) diff --git a/hc/front/tests/test_details.py b/hc/front/tests/test_details.py index 63542809..8690df89 100644 --- a/hc/front/tests/test_details.py +++ b/hc/front/tests/test_details.py @@ -3,7 +3,6 @@ from hc.test import BaseTestCase class DetailsTestCase(BaseTestCase): - def setUp(self): super(DetailsTestCase, self).setUp() self.check = Check.objects.create(project=self.project) diff --git a/hc/front/tests/test_hc_extras.py b/hc/front/tests/test_hc_extras.py index 5e46105f..5142b8f9 100644 --- a/hc/front/tests/test_hc_extras.py +++ b/hc/front/tests/test_hc_extras.py @@ -4,7 +4,6 @@ from hc.front.templatetags.hc_extras import hc_duration class HcExtrasTestCase(TestCase): - def test_hc_duration_works(self): samples = [ (60, "1 minute"), @@ -15,7 +14,7 @@ class HcExtrasTestCase(TestCase): (604800, "1 week"), (2419200, "4 weeks"), (2592000, "30 days"), - (3801600, "44 days") + (3801600, "44 days"), ] for seconds, expected_result in samples: diff --git a/hc/front/tests/test_log.py b/hc/front/tests/test_log.py index 7e9735eb..93717390 100644 --- a/hc/front/tests/test_log.py +++ b/hc/front/tests/test_log.py @@ -5,7 +5,6 @@ from hc.test import BaseTestCase class LogTestCase(BaseTestCase): - def setUp(self): super(LogTestCase, self).setUp() self.check = Check.objects.create(project=self.project) @@ -55,19 +54,14 @@ class LogTestCase(BaseTestCase): def test_it_shows_email_notification(self): ch = Channel(kind="email", project=self.project) - ch.value = json.dumps({ - "value": "alice@example.org", - "up": True, - "down": True - }) + ch.value = json.dumps({"value": "alice@example.org", "up": True, "down": True}) ch.save() Notification(owner=self.check, channel=ch, check_status="down").save() self.client.login(username="alice@example.org", password="password") r = self.client.get(self.url) - self.assertContains(r, "Sent email alert to alice@example.org", - status_code=200) + self.assertContains(r, "Sent email alert to alice@example.org", status_code=200) def test_it_shows_pushover_notification(self): ch = Channel.objects.create(kind="po", project=self.project) diff --git a/hc/front/tests/test_my_checks.py b/hc/front/tests/test_my_checks.py index 1c5707ce..1d896ab8 100644 --- a/hc/front/tests/test_my_checks.py +++ b/hc/front/tests/test_my_checks.py @@ -5,7 +5,6 @@ from django.utils import timezone class MyChecksTestCase(BaseTestCase): - def setUp(self): super(MyChecksTestCase, self).setUp() self.check = Check(project=self.project, name="Alice Was Here") diff --git a/hc/front/tests/test_pause.py b/hc/front/tests/test_pause.py index 5d0fed24..35176ae1 100644 --- a/hc/front/tests/test_pause.py +++ b/hc/front/tests/test_pause.py @@ -6,7 +6,6 @@ from hc.test import BaseTestCase class PauseTestCase(BaseTestCase): - def setUp(self): super(PauseTestCase, self).setUp() self.check = Check.objects.create(project=self.project, status="up") diff --git a/hc/front/tests/test_ping_details.py b/hc/front/tests/test_ping_details.py index 8fcf19f6..77f5d965 100644 --- a/hc/front/tests/test_ping_details.py +++ b/hc/front/tests/test_ping_details.py @@ -3,7 +3,6 @@ from hc.test import BaseTestCase class LastPingTestCase(BaseTestCase): - def test_it_works(self): check = Check.objects.create(project=self.project) Ping.objects.create(owner=check, body="this is body") diff --git a/hc/front/tests/test_remove_channel.py b/hc/front/tests/test_remove_channel.py index a98ebc0a..50ca2063 100644 --- a/hc/front/tests/test_remove_channel.py +++ b/hc/front/tests/test_remove_channel.py @@ -3,7 +3,6 @@ from hc.test import BaseTestCase class RemoveChannelTestCase(BaseTestCase): - def setUp(self): super(RemoveChannelTestCase, self).setUp() self.channel = Channel(project=self.project, kind="email") diff --git a/hc/front/tests/test_remove_check.py b/hc/front/tests/test_remove_check.py index 67a65f98..c1cd48a2 100644 --- a/hc/front/tests/test_remove_check.py +++ b/hc/front/tests/test_remove_check.py @@ -3,7 +3,6 @@ from hc.test import BaseTestCase class RemoveCheckTestCase(BaseTestCase): - def setUp(self): super(RemoveCheckTestCase, self).setUp() self.check = Check.objects.create(project=self.project) diff --git a/hc/front/tests/test_send_test_notification.py b/hc/front/tests/test_send_test_notification.py index 04caa4d5..6ddec998 100644 --- a/hc/front/tests/test_send_test_notification.py +++ b/hc/front/tests/test_send_test_notification.py @@ -4,7 +4,6 @@ from hc.test import BaseTestCase class SendTestNotificationTestCase(BaseTestCase): - def setUp(self): super(SendTestNotificationTestCase, self).setUp() self.channel = Channel(kind="email", project=self.project) diff --git a/hc/front/tests/test_status.py b/hc/front/tests/test_status.py index 1c9a5ead..17ddc3f5 100644 --- a/hc/front/tests/test_status.py +++ b/hc/front/tests/test_status.py @@ -3,7 +3,6 @@ from hc.test import BaseTestCase class MyChecksTestCase(BaseTestCase): - def setUp(self): super(MyChecksTestCase, self).setUp() self.check = Check(project=self.project, name="Alice Was Here") diff --git a/hc/front/tests/test_status_single.py b/hc/front/tests/test_status_single.py index b9c4c611..0889e361 100644 --- a/hc/front/tests/test_status_single.py +++ b/hc/front/tests/test_status_single.py @@ -3,7 +3,6 @@ from hc.test import BaseTestCase class StatusSingleTestCase(BaseTestCase): - def setUp(self): super(StatusSingleTestCase, self).setUp() self.check = Check(project=self.project, name="Alice Was Here") diff --git a/hc/front/tests/test_switch_channel.py b/hc/front/tests/test_switch_channel.py index d5abd8dd..0b74688d 100644 --- a/hc/front/tests/test_switch_channel.py +++ b/hc/front/tests/test_switch_channel.py @@ -4,7 +4,6 @@ from hc.test import BaseTestCase class SwitchChannelTestCase(BaseTestCase): - def setUp(self): super(SwitchChannelTestCase, self).setUp() self.check = Check.objects.create(project=self.project) @@ -13,7 +12,10 @@ class SwitchChannelTestCase(BaseTestCase): self.channel.value = "alice@example.org" self.channel.save() - self.url = "/checks/%s/channels/%s/enabled" % (self.check.code, self.channel.code) + self.url = "/checks/%s/channels/%s/enabled" % ( + self.check.code, + self.channel.code, + ) def test_it_enables(self): self.client.login(username="alice@example.org", password="password") diff --git a/hc/front/tests/test_transfer.py b/hc/front/tests/test_transfer.py index f8f18e3a..952cce54 100644 --- a/hc/front/tests/test_transfer.py +++ b/hc/front/tests/test_transfer.py @@ -42,11 +42,9 @@ class TrabsferTestCase(BaseTestCase): self.assertEqual(r.status_code, 400) def test_it_reassigns_channels(self): - alices_mail = Channel.objects.create(kind="email", - project=self.project) + alices_mail = Channel.objects.create(kind="email", project=self.project) - bobs_mail = Channel.objects.create(kind="email", - project=self.bobs_project) + bobs_mail = Channel.objects.create(kind="email", project=self.bobs_project) self.check.channel_set.add(bobs_mail) diff --git a/hc/front/tests/test_unsubscribe_email.py b/hc/front/tests/test_unsubscribe_email.py index a18acfea..034985cd 100644 --- a/hc/front/tests/test_unsubscribe_email.py +++ b/hc/front/tests/test_unsubscribe_email.py @@ -3,7 +3,6 @@ from hc.test import BaseTestCase class UnsubscribeEmailTestCase(BaseTestCase): - def setUp(self): super(UnsubscribeEmailTestCase, self).setUp() self.channel = Channel(project=self.project, kind="email") @@ -24,8 +23,7 @@ class UnsubscribeEmailTestCase(BaseTestCase): url = "/integrations/%s/unsub/faketoken/" % self.channel.code r = self.client.get(url) - self.assertContains(r, "link you just used is incorrect", - status_code=200) + self.assertContains(r, "link you just used is incorrect", status_code=200) def test_it_checks_channel_kind(self): self.channel.kind = "webhook" diff --git a/hc/front/tests/test_update_channel.py b/hc/front/tests/test_update_channel.py index 8d857869..5cc20798 100644 --- a/hc/front/tests/test_update_channel.py +++ b/hc/front/tests/test_update_channel.py @@ -4,7 +4,6 @@ from hc.test import BaseTestCase class UpdateChannelTestCase(BaseTestCase): - def setUp(self): super(UpdateChannelTestCase, self).setUp() self.check = Check.objects.create(project=self.project) @@ -14,10 +13,7 @@ class UpdateChannelTestCase(BaseTestCase): self.channel.save() def test_it_works(self): - payload = { - "channel": self.channel.code, - "check-%s" % self.check.code: True - } + payload = {"channel": self.channel.code, "check-%s" % self.check.code: True} self.client.login(username="alice@example.org", password="password") r = self.client.post("/integrations/", data=payload) @@ -29,10 +25,7 @@ class UpdateChannelTestCase(BaseTestCase): assert checks[0].code == self.check.code def test_team_access_works(self): - payload = { - "channel": self.channel.code, - "check-%s" % self.check.code: True - } + payload = {"channel": self.channel.code, "check-%s" % self.check.code: True} # Logging in as bob, not alice. Bob has team access so this # should work. @@ -55,10 +48,7 @@ class UpdateChannelTestCase(BaseTestCase): charlies_channel.email = "charlie@example.org" charlies_channel.save() - payload = { - "channel": charlies_channel.code, - "check-%s" % self.check.code: True - } + payload = {"channel": charlies_channel.code, "check-%s" % self.check.code: True} self.client.login(username="charlie@example.org", password="password") r = self.client.post("/integrations/", data=payload) @@ -77,7 +67,7 @@ class UpdateChannelTestCase(BaseTestCase): # check- key has a correct UUID but there's no check object for it payload = { "channel": self.channel.code, - "check-6837d6ec-fc08-4da5-a67f-08a9ed1ccf62": True + "check-6837d6ec-fc08-4da5-a67f-08a9ed1ccf62": True, } self.client.login(username="alice@example.org", password="password") diff --git a/hc/front/tests/test_update_channel_name.py b/hc/front/tests/test_update_channel_name.py index 8d27bc64..7d7bc2f3 100644 --- a/hc/front/tests/test_update_channel_name.py +++ b/hc/front/tests/test_update_channel_name.py @@ -3,7 +3,6 @@ from hc.test import BaseTestCase class UpdateChannelNameTestCase(BaseTestCase): - def setUp(self): super(UpdateChannelNameTestCase, self).setUp() self.channel = Channel(kind="email", project=self.project) diff --git a/hc/front/tests/test_update_name.py b/hc/front/tests/test_update_name.py index ee8f086a..55bb2d4e 100644 --- a/hc/front/tests/test_update_name.py +++ b/hc/front/tests/test_update_name.py @@ -3,7 +3,6 @@ from hc.test import BaseTestCase class UpdateNameTestCase(BaseTestCase): - def setUp(self): super(UpdateNameTestCase, self).setUp() self.check = Check.objects.create(project=self.project) diff --git a/hc/front/tests/test_update_timeout.py b/hc/front/tests/test_update_timeout.py index 861b0394..0b82909a 100644 --- a/hc/front/tests/test_update_timeout.py +++ b/hc/front/tests/test_update_timeout.py @@ -6,7 +6,6 @@ from hc.test import BaseTestCase class UpdateTimeoutTestCase(BaseTestCase): - def setUp(self): super(UpdateTimeoutTestCase, self).setUp() self.check = Check(project=self.project, status="up") @@ -47,12 +46,7 @@ class UpdateTimeoutTestCase(BaseTestCase): self.assertEqual(self.check.status, "down") def test_it_saves_cron_expression(self): - payload = { - "kind": "cron", - "schedule": "5 * * * *", - "tz": "UTC", - "grace": 60 - } + payload = {"kind": "cron", "schedule": "5 * * * *", "tz": "UTC", "grace": 60} self.client.login(username="alice@example.org", password="password") r = self.client.post(self.url, data=payload) @@ -67,12 +61,7 @@ class UpdateTimeoutTestCase(BaseTestCase): samples = ["* invalid *", "1,2 3,* * * *"] for sample in samples: - payload = { - "kind": "cron", - "schedule": sample, - "tz": "UTC", - "grace": 60 - } + payload = {"kind": "cron", "schedule": sample, "tz": "UTC", "grace": 60} r = self.client.post(self.url, data=payload) self.assertEqual(r.status_code, 400) @@ -86,7 +75,7 @@ class UpdateTimeoutTestCase(BaseTestCase): "kind": "cron", "schedule": "* * * * * *", # six fields instead of five "tz": "UTC", - "grace": 60 + "grace": 60, } self.client.login(username="alice@example.org", password="password") @@ -102,7 +91,7 @@ class UpdateTimeoutTestCase(BaseTestCase): "kind": "cron", "schedule": "* * * * *", "tz": "not-a-tz", - "grace": 60 + "grace": 60, } self.client.login(username="alice@example.org", password="password") @@ -115,11 +104,7 @@ class UpdateTimeoutTestCase(BaseTestCase): def test_it_rejects_missing_schedule(self): # tz field is omitted so this should fail: - payload = { - "kind": "cron", - "grace": 60, - "tz": "UTC" - } + payload = {"kind": "cron", "grace": 60, "tz": "UTC"} self.client.login(username="alice@example.org", password="password") r = self.client.post(self.url, data=payload) @@ -127,11 +112,7 @@ class UpdateTimeoutTestCase(BaseTestCase): def test_it_rejects_missing_tz(self): # tz field is omitted so this should fail: - payload = { - "kind": "cron", - "schedule": "* * * * *", - "grace": 60 - } + payload = {"kind": "cron", "schedule": "* * * * *", "grace": 60} self.client.login(username="alice@example.org", password="password") r = self.client.post(self.url, data=payload) diff --git a/hc/front/tests/test_verify_email.py b/hc/front/tests/test_verify_email.py index e53008a5..b2fc4731 100644 --- a/hc/front/tests/test_verify_email.py +++ b/hc/front/tests/test_verify_email.py @@ -3,7 +3,6 @@ from hc.test import BaseTestCase class VerifyEmailTestCase(BaseTestCase): - def setUp(self): super(VerifyEmailTestCase, self).setUp() self.channel = Channel(project=self.project, kind="email") diff --git a/hc/front/urls.py b/hc/front/urls.py index 71f1db9b..4bb6b004 100644 --- a/hc/front/urls.py +++ b/hc/front/urls.py @@ -3,63 +3,70 @@ from django.urls import include, path from hc.front import views check_urls = [ - path('name/', views.update_name, name="hc-update-name"), - path('details/', views.details, name="hc-details"), - path('email_settings/', views.email_settings, name="hc-email-settings"), - path('timeout/', views.update_timeout, name="hc-update-timeout"), - path('pause/', views.pause, name="hc-pause"), - path('remove/', views.remove_check, name="hc-remove-check"), - path('log/', views.log, name="hc-log"), - path('status/', views.status_single), - path('last_ping/', views.ping_details, name="hc-last-ping"), - path('transfer/', views.transfer, name="hc-transfer"), - path('channels//enabled', views.switch_channel, name="hc-switch-channel"), - path('pings//', views.ping_details, name="hc-ping-details"), + path("name/", views.update_name, name="hc-update-name"), + path("details/", views.details, name="hc-details"), + path("email_settings/", views.email_settings, name="hc-email-settings"), + path("timeout/", views.update_timeout, name="hc-update-timeout"), + path("pause/", views.pause, name="hc-pause"), + path("remove/", views.remove_check, name="hc-remove-check"), + path("log/", views.log, name="hc-log"), + path("status/", views.status_single), + path("last_ping/", views.ping_details, name="hc-last-ping"), + path("transfer/", views.transfer, name="hc-transfer"), + path( + "channels//enabled", + views.switch_channel, + name="hc-switch-channel", + ), + path("pings//", views.ping_details, name="hc-ping-details"), ] channel_urls = [ - path('', views.channels, name="hc-channels"), - path('add_email/', views.add_email, name="hc-add-email"), - path('add_webhook/', views.add_webhook, name="hc-add-webhook"), - path('add_pd/', views.add_pd, name="hc-add-pd"), - path('add_pd//', views.add_pd, name="hc-add-pd-state"), - path('add_pagertree/', views.add_pagertree, name="hc-add-pagertree"), - path('add_pagerteam/', views.add_pagerteam, name="hc-add-pagerteam"), - path('add_slack/', views.add_slack, name="hc-add-slack"), - path('add_slack_btn/', views.add_slack_btn, name="hc-add-slack-btn"), - path('add_pushbullet/', views.add_pushbullet, name="hc-add-pushbullet"), - path('add_discord/', views.add_discord, name="hc-add-discord"), - path('add_pushover/', views.add_pushover, name="hc-add-pushover"), - path('add_opsgenie/', views.add_opsgenie, name="hc-add-opsgenie"), - path('add_victorops/', views.add_victorops, name="hc-add-victorops"), - path('telegram/bot/', views.telegram_bot, name="hc-telegram-webhook"), - path('add_telegram/', views.add_telegram, name="hc-add-telegram"), - path('add_sms/', views.add_sms, name="hc-add-sms"), - path('add_trello/', views.add_trello, name="hc-add-trello"), - path('add_trello/settings/', views.trello_settings, name="hc-trello-settings"), - path('add_matrix/', views.add_matrix, name="hc-add-matrix"), - path('/checks/', views.channel_checks, name="hc-channel-checks"), - path('/name/', views.update_channel_name, name="hc-channel-name"), - path('/test/', views.send_test_notification, name="hc-channel-test"), - path('/remove/', views.remove_channel, name="hc-remove-channel"), - path('/verify//', views.verify_email, - name="hc-verify-email"), - path('/unsub//', views.unsubscribe_email, - name="hc-unsubscribe-alerts"), + path("", views.channels, name="hc-channels"), + path("add_email/", views.add_email, name="hc-add-email"), + path("add_webhook/", views.add_webhook, name="hc-add-webhook"), + path("add_pd/", views.add_pd, name="hc-add-pd"), + path("add_pd//", views.add_pd, name="hc-add-pd-state"), + path("add_pagertree/", views.add_pagertree, name="hc-add-pagertree"), + path("add_pagerteam/", views.add_pagerteam, name="hc-add-pagerteam"), + path("add_slack/", views.add_slack, name="hc-add-slack"), + path("add_slack_btn/", views.add_slack_btn, name="hc-add-slack-btn"), + path("add_pushbullet/", views.add_pushbullet, name="hc-add-pushbullet"), + path("add_discord/", views.add_discord, name="hc-add-discord"), + path("add_pushover/", views.add_pushover, name="hc-add-pushover"), + path("add_opsgenie/", views.add_opsgenie, name="hc-add-opsgenie"), + path("add_victorops/", views.add_victorops, name="hc-add-victorops"), + path("telegram/bot/", views.telegram_bot, name="hc-telegram-webhook"), + path("add_telegram/", views.add_telegram, name="hc-add-telegram"), + path("add_sms/", views.add_sms, name="hc-add-sms"), + path("add_trello/", views.add_trello, name="hc-add-trello"), + path("add_trello/settings/", views.trello_settings, name="hc-trello-settings"), + path("add_matrix/", views.add_matrix, name="hc-add-matrix"), + path("/checks/", views.channel_checks, name="hc-channel-checks"), + path("/name/", views.update_channel_name, name="hc-channel-name"), + path("/test/", views.send_test_notification, name="hc-channel-test"), + path("/remove/", views.remove_channel, name="hc-remove-channel"), + path( + "/verify//", views.verify_email, name="hc-verify-email" + ), + path( + "/unsub//", + views.unsubscribe_email, + name="hc-unsubscribe-alerts", + ), ] urlpatterns = [ - path('', views.index, name="hc-index"), - path('projects//checks/', views.my_checks, name="hc-checks"), - path('projects//badges/', views.badges, name="hc-badges"), - path('projects//checks/add/', views.add_check, name="hc-add-check"), - path('checks/cron_preview/', views.cron_preview), - path('projects//checks/status/', views.status, name="hc-status"), - path('checks//', include(check_urls)), - path('integrations/', include(channel_urls)), - - path('docs/', views.docs, name="hc-docs"), - path('docs/api/', views.docs_api, name="hc-docs-api"), - path('docs/cron/', views.docs_cron, name="hc-docs-cron"), - path('docs/resources/', views.docs_resources, name="hc-docs-resources"), + path("", views.index, name="hc-index"), + path("projects//checks/", views.my_checks, name="hc-checks"), + path("projects//badges/", views.badges, name="hc-badges"), + path("projects//checks/add/", views.add_check, name="hc-add-check"), + path("checks/cron_preview/", views.cron_preview), + path("projects//checks/status/", views.status, name="hc-status"), + path("checks//", include(check_urls)), + path("integrations/", include(channel_urls)), + path("docs/", views.docs, name="hc-docs"), + path("docs/api/", views.docs_api, name="hc-docs-api"), + path("docs/cron/", views.docs_cron, name="hc-docs-cron"), + path("docs/resources/", views.docs_resources, name="hc-docs-resources"), ] diff --git a/hc/front/views.py b/hc/front/views.py index ca896917..6a5bce7e 100644 --- a/hc/front/views.py +++ b/hc/front/views.py @@ -1,6 +1,5 @@ from datetime import datetime, timedelta as td import json -import re from urllib.parse import urlencode from croniter import croniter @@ -9,8 +8,13 @@ from django.contrib import messages from django.contrib.auth.decorators import login_required from django.core import signing from django.db.models import Count -from django.http import (Http404, HttpResponse, HttpResponseBadRequest, - HttpResponseForbidden, JsonResponse) +from django.http import ( + Http404, + HttpResponse, + HttpResponseBadRequest, + HttpResponseForbidden, + JsonResponse, +) from django.shortcuts import get_object_or_404, redirect, render from django.template.loader import get_template, render_to_string from django.urls import reverse @@ -19,16 +23,30 @@ from django.utils.crypto import get_random_string from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_POST from hc.accounts.models import Project -from hc.api.models import (DEFAULT_GRACE, DEFAULT_TIMEOUT, Channel, Check, - Ping, Notification) +from hc.api.models import ( + DEFAULT_GRACE, + DEFAULT_TIMEOUT, + Channel, + Check, + Ping, + Notification, +) from hc.api.transports import Telegram -from hc.front.forms import (AddWebhookForm, NameTagsForm, - TimeoutForm, AddUrlForm, AddEmailForm, - AddOpsGenieForm, CronForm, AddSmsForm, - ChannelNameForm, EmailSettingsForm, AddMatrixForm) +from hc.front.forms import ( + AddWebhookForm, + NameTagsForm, + TimeoutForm, + AddUrlForm, + AddEmailForm, + AddOpsGenieForm, + CronForm, + AddSmsForm, + ChannelNameForm, + EmailSettingsForm, + AddMatrixForm, +) from hc.front.schemas import telegram_callback -from hc.front.templatetags.hc_extras import (num_down_title, down_title, - sortchecks) +from hc.front.templatetags.hc_extras import num_down_title, down_title, sortchecks from hc.lib import jsonschema from hc.lib.badges import get_badge_url import pytz @@ -150,7 +168,7 @@ def my_checks(request, code): "selected_tags": selected_tags, "show_search": True, "search": search, - "hidden_checks": hidden_checks + "hidden_checks": hidden_checks, } return render(request, "front/my_checks.html", ctx) @@ -165,18 +183,18 @@ def status(request, code): details = [] for check in checks: ctx = {"check": check} - details.append({ - "code": str(check.code), - "status": check.get_status(), - "last_ping": LAST_PING_TMPL.render(ctx) - }) + details.append( + { + "code": str(check.code), + "status": check.get_status(), + "last_ping": LAST_PING_TMPL.render(ctx), + } + ) tags_statuses, num_down = _tags_statuses(checks) - return JsonResponse({ - "details": details, - "tags": tags_statuses, - "title": num_down_title(num_down) - }) + return JsonResponse( + {"details": details, "tags": tags_statuses, "title": num_down_title(num_down)} + ) @login_required @@ -200,10 +218,7 @@ def index(request): if request.user.is_authenticated: projects = list(request.profile.projects()) - ctx = { - "page": "projects", - "projects": projects - } + ctx = {"page": "projects", "projects": projects} return render(request, "front/projects.html", ctx) check = Check() @@ -220,7 +235,7 @@ def index(request): "enable_pd": settings.PD_VENDOR_KEY is not None, "enable_trello": settings.TRELLO_APP_KEY is not None, "enable_matrix": settings.MATRIX_ACCESS_TOKEN is not None, - "registration_open": settings.REGISTRATION_OPEN + "registration_open": settings.REGISTRATION_OPEN, } return render(request, "front/welcome.html", ctx) @@ -233,7 +248,7 @@ def docs(request): "ping_endpoint": settings.PING_ENDPOINT, "ping_email": "your-uuid-here@%s" % settings.PING_EMAIL_DOMAIN, "ping_email_domain": settings.PING_EMAIL_DOMAIN, - "ping_url": settings.PING_ENDPOINT + "your-uuid-here" + "ping_url": settings.PING_ENDPOINT + "your-uuid-here", } return render(request, "front/docs.html", ctx) @@ -246,7 +261,7 @@ def docs_api(request): "SITE_ROOT": settings.SITE_ROOT, "PING_ENDPOINT": settings.PING_ENDPOINT, "default_timeout": int(DEFAULT_TIMEOUT.total_seconds()), - "default_grace": int(DEFAULT_GRACE.total_seconds()) + "default_grace": int(DEFAULT_GRACE.total_seconds()), } return render(request, "front/docs_api.html", ctx) @@ -371,10 +386,7 @@ def ping_details(request, code, n=None): ping = q.latest("created") - ctx = { - "check": check, - "ping": ping - } + ctx = {"check": check, "ping": ping} return render(request, "front/ping_details.html", ctx) @@ -424,9 +436,9 @@ def _get_events(check, limit): alerts = [] if len(pings): cutoff = pings[-1].created - alerts = Notification.objects \ - .select_related("channel") \ - .filter(owner=check, check_status="down", created__gt=cutoff) + alerts = Notification.objects.select_related("channel").filter( + owner=check, check_status="down", created__gt=cutoff + ) events = pings + list(alerts) events.sort(key=lambda el: el.created, reverse=True) @@ -443,7 +455,7 @@ def log(request, code): "check": check, "events": _get_events(check, limit), "limit": limit, - "show_limit_notice": check.n_pings > limit and settings.USE_PAYMENTS + "show_limit_notice": check.n_pings > limit and settings.USE_PAYMENTS, } return render(request, "front/log.html", ctx) @@ -461,7 +473,7 @@ def details(request, code): "project": check.project, "check": check, "channels": channels, - "timezones": pytz.all_timezones + "timezones": pytz.all_timezones, } return render(request, "front/details.html", ctx) @@ -506,7 +518,7 @@ def status_single(request, code): "status": status, "status_text": STATUS_TEXT_TMPL.render({"check": check}), "title": down_title(check), - "updated": updated + "updated": updated, } if updated != request.GET.get("u"): @@ -528,17 +540,19 @@ def badges(request, code): urls = [] for tag in sorted_tags: - urls.append({ - "tag": tag, - "svg": get_badge_url(project.badge_key, tag), - "json": get_badge_url(project.badge_key, tag, format="json"), - }) + urls.append( + { + "tag": tag, + "svg": get_badge_url(project.badge_key, tag), + "json": get_badge_url(project.badge_key, tag, format="json"), + } + ) ctx = { "have_tags": len(urls) > 1, "page": "badges", "project": project, - "badges": urls + "badges": urls, } return render(request, "front/badges.html", ctx) @@ -587,7 +601,7 @@ def channels(request): "enable_pd": settings.PD_VENDOR_KEY is not None, "enable_trello": settings.TRELLO_APP_KEY is not None, "enable_matrix": settings.MATRIX_ACCESS_TOKEN is not None, - "use_payments": settings.USE_PAYMENTS + "use_payments": settings.USE_PAYMENTS, } return render(request, "front/channels.html", ctx) @@ -599,14 +613,10 @@ def channel_checks(request, code): if channel.project_id != request.project.id: return HttpResponseForbidden() - assigned = set(channel.checks.values_list('code', flat=True).distinct()) + assigned = set(channel.checks.values_list("code", flat=True).distinct()) checks = Check.objects.filter(project=request.project).order_by("created") - ctx = { - "checks": checks, - "assigned": assigned, - "channel": channel - } + ctx = {"checks": checks, "assigned": assigned, "channel": channel} return render(request, "front/channel_checks.html", ctx) @@ -696,11 +706,13 @@ def add_email(request): form = AddEmailForm(request.POST) if form.is_valid(): channel = Channel(project=request.project, kind="email") - channel.value = json.dumps({ - "value": form.cleaned_data["value"], - "up": form.cleaned_data["up"], - "down": form.cleaned_data["down"] - }) + channel.value = json.dumps( + { + "value": form.cleaned_data["value"], + "up": form.cleaned_data["up"], + "down": form.cleaned_data["down"], + } + ) channel.save() channel.assign_all_checks() @@ -726,7 +738,7 @@ def add_email(request): "page": "channels", "project": request.project, "use_verification": settings.EMAIL_USE_VERIFICATION, - "form": form + "form": form, } return render(request, "integrations/add_email.html", ctx) @@ -749,7 +761,7 @@ def add_webhook(request): "page": "channels", "project": request.project, "form": form, - "now": timezone.now().replace(microsecond=0).isoformat() + "now": timezone.now().replace(microsecond=0).isoformat(), } return render(request, "integrations/add_webhook.html", ctx) @@ -790,10 +802,12 @@ def add_pd(request, state=None): channel = Channel(kind="pd", project=request.project) channel.user = request.project.owner - channel.value = json.dumps({ - "service_key": request.GET.get("service_key"), - "account": request.GET.get("account") - }) + channel.value = json.dumps( + { + "service_key": request.GET.get("service_key"), + "account": request.GET.get("account"), + } + ) channel.save() channel.assign_all_checks() messages.success(request, "The PagerDuty integration has been added!") @@ -801,16 +815,11 @@ def add_pd(request, state=None): state = _prepare_state(request, "pd") callback = settings.SITE_ROOT + reverse("hc-add-pd-state", args=[state]) - connect_url = "https://connect.pagerduty.com/connect?" + urlencode({ - "vendor": settings.PD_VENDOR_KEY, - "callback": callback - }) + connect_url = "https://connect.pagerduty.com/connect?" + urlencode( + {"vendor": settings.PD_VENDOR_KEY, "callback": callback} + ) - ctx = { - "page": "channels", - "project": request.project, - "connect_url": connect_url - } + ctx = {"page": "channels", "project": request.project, "connect_url": connect_url} return render(request, "integrations/add_pd.html", ctx) @@ -828,11 +837,7 @@ def add_pagertree(request): else: form = AddUrlForm() - ctx = { - "page": "channels", - "project": request.project, - "form": form - } + ctx = {"page": "channels", "project": request.project, "form": form} return render(request, "integrations/add_pagertree.html", ctx) @@ -850,11 +855,7 @@ def add_pagerteam(request): else: form = AddUrlForm() - ctx = { - "page": "channels", - "project": request.project, - "form": form - } + ctx = {"page": "channels", "project": request.project, "form": form} return render(request, "integrations/add_pagerteam.html", ctx) @@ -877,7 +878,7 @@ def add_slack(request): ctx = { "page": "channels", "form": form, - "slack_client_id": settings.SLACK_CLIENT_ID + "slack_client_id": settings.SLACK_CLIENT_ID, } if request.user.is_authenticated: @@ -895,11 +896,14 @@ def add_slack_btn(request): if code is None: return HttpResponseBadRequest() - result = requests.post("https://slack.com/api/oauth.access", { - "client_id": settings.SLACK_CLIENT_ID, - "client_secret": settings.SLACK_CLIENT_SECRET, - "code": code - }) + result = requests.post( + "https://slack.com/api/oauth.access", + { + "client_id": settings.SLACK_CLIENT_ID, + "client_secret": settings.SLACK_CLIENT_SECRET, + "code": code, + }, + ) doc = result.json() if doc.get("ok"): @@ -926,12 +930,15 @@ def add_pushbullet(request): if code is None: return HttpResponseBadRequest() - result = requests.post("https://api.pushbullet.com/oauth2/token", { - "client_id": settings.PUSHBULLET_CLIENT_ID, - "client_secret": settings.PUSHBULLET_CLIENT_SECRET, - "code": code, - "grant_type": "authorization_code" - }) + result = requests.post( + "https://api.pushbullet.com/oauth2/token", + { + "client_id": settings.PUSHBULLET_CLIENT_ID, + "client_secret": settings.PUSHBULLET_CLIENT_SECRET, + "code": code, + "grant_type": "authorization_code", + }, + ) doc = result.json() if "access_token" in doc: @@ -940,25 +947,26 @@ def add_pushbullet(request): channel.value = doc["access_token"] channel.save() channel.assign_all_checks() - messages.success(request, - "The Pushbullet integration has been added!") + messages.success(request, "The Pushbullet integration has been added!") else: messages.warning(request, "Something went wrong") return redirect("hc-channels") redirect_uri = settings.SITE_ROOT + reverse("hc-add-pushbullet") - authorize_url = "https://www.pushbullet.com/authorize?" + urlencode({ - "client_id": settings.PUSHBULLET_CLIENT_ID, - "redirect_uri": redirect_uri, - "response_type": "code", - "state": _prepare_state(request, "pushbullet") - }) + authorize_url = "https://www.pushbullet.com/authorize?" + urlencode( + { + "client_id": settings.PUSHBULLET_CLIENT_ID, + "redirect_uri": redirect_uri, + "response_type": "code", + "state": _prepare_state(request, "pushbullet"), + } + ) ctx = { "page": "channels", "project": request.project, - "authorize_url": authorize_url + "authorize_url": authorize_url, } return render(request, "integrations/add_pushbullet.html", ctx) @@ -974,13 +982,16 @@ def add_discord(request): if code is None: return HttpResponseBadRequest() - result = requests.post("https://discordapp.com/api/oauth2/token", { - "client_id": settings.DISCORD_CLIENT_ID, - "client_secret": settings.DISCORD_CLIENT_SECRET, - "code": code, - "grant_type": "authorization_code", - "redirect_uri": redirect_uri - }) + result = requests.post( + "https://discordapp.com/api/oauth2/token", + { + "client_id": settings.DISCORD_CLIENT_ID, + "client_secret": settings.DISCORD_CLIENT_SECRET, + "code": code, + "grant_type": "authorization_code", + "redirect_uri": redirect_uri, + }, + ) doc = result.json() if "access_token" in doc: @@ -989,32 +1000,32 @@ def add_discord(request): channel.value = result.text channel.save() channel.assign_all_checks() - messages.success(request, - "The Discord integration has been added!") + messages.success(request, "The Discord integration has been added!") else: messages.warning(request, "Something went wrong") return redirect("hc-channels") - auth_url = "https://discordapp.com/api/oauth2/authorize?" + urlencode({ - "client_id": settings.DISCORD_CLIENT_ID, - "scope": "webhook.incoming", - "redirect_uri": redirect_uri, - "response_type": "code", - "state": _prepare_state(request, "discord") - }) + auth_url = "https://discordapp.com/api/oauth2/authorize?" + urlencode( + { + "client_id": settings.DISCORD_CLIENT_ID, + "scope": "webhook.incoming", + "redirect_uri": redirect_uri, + "response_type": "code", + "state": _prepare_state(request, "discord"), + } + ) - ctx = { - "page": "channels", - "project": request.project, - "authorize_url": auth_url - } + ctx = {"page": "channels", "project": request.project, "authorize_url": auth_url} return render(request, "integrations/add_discord.html", ctx) def add_pushover(request): - if settings.PUSHOVER_API_TOKEN is None or settings.PUSHOVER_SUBSCRIPTION_URL is None: + if ( + settings.PUSHOVER_API_TOKEN is None + or settings.PUSHOVER_SUBSCRIPTION_URL is None + ): raise Http404("pushover integration is not available") if not request.user.is_authenticated: @@ -1026,15 +1037,23 @@ def add_pushover(request): state = _prepare_state(request, "pushover") failure_url = settings.SITE_ROOT + reverse("hc-channels") - success_url = settings.SITE_ROOT + reverse("hc-add-pushover") + "?" + urlencode({ - "state": state, - "prio": request.POST.get("po_priority", "0"), - "prio_up": request.POST.get("po_priority_up", "0") - }) - subscription_url = settings.PUSHOVER_SUBSCRIPTION_URL + "?" + urlencode({ - "success": success_url, - "failure": failure_url, - }) + success_url = ( + settings.SITE_ROOT + + reverse("hc-add-pushover") + + "?" + + urlencode( + { + "state": state, + "prio": request.POST.get("po_priority", "0"), + "prio_up": request.POST.get("po_priority_up", "0"), + } + ) + ) + subscription_url = ( + settings.PUSHOVER_SUBSCRIPTION_URL + + "?" + + urlencode({"success": success_url, "failure": failure_url}) + ) return redirect(subscription_url) @@ -1091,11 +1110,7 @@ def add_opsgenie(request): else: form = AddUrlForm() - ctx = { - "page": "channels", - "project": request.project, - "form": form - } + ctx = {"page": "channels", "project": request.project, "form": form} return render(request, "integrations/add_opsgenie.html", ctx) @@ -1113,11 +1128,7 @@ def add_victorops(request): else: form = AddUrlForm() - ctx = { - "page": "channels", - "project": request.project, - "form": form - } + ctx = {"page": "channels", "project": request.project, "form": form} return render(request, "integrations/add_victorops.html", ctx) @@ -1140,9 +1151,10 @@ def telegram_bot(request): chat = doc["message"]["chat"] name = max(chat.get("title", ""), chat.get("username", "")) - invite = render_to_string("integrations/telegram_invite.html", { - "qs": signing.dumps((chat["id"], chat["type"], name)) - }) + invite = render_to_string( + "integrations/telegram_invite.html", + {"qs": signing.dumps((chat["id"], chat["type"], name))}, + ) Telegram.send(chat["id"], invite) return HttpResponse() @@ -1157,11 +1169,9 @@ def add_telegram(request): if request.method == "POST": channel = Channel(project=request.project, kind="telegram") - channel.value = json.dumps({ - "id": chat_id, - "type": chat_type, - "name": chat_name - }) + channel.value = json.dumps( + {"id": chat_id, "type": chat_type, "name": chat_name} + ) channel.save() channel.assign_all_checks() @@ -1174,7 +1184,7 @@ def add_telegram(request): "chat_id": chat_id, "chat_type": chat_type, "chat_name": chat_name, - "bot_name": settings.TELEGRAM_BOT_NAME + "bot_name": settings.TELEGRAM_BOT_NAME, } return render(request, "integrations/add_telegram.html", ctx) @@ -1190,9 +1200,7 @@ def add_sms(request): if form.is_valid(): channel = Channel(project=request.project, kind="sms") channel.name = form.cleaned_data["label"] - channel.value = json.dumps({ - "value": form.cleaned_data["value"] - }) + channel.value = json.dumps({"value": form.cleaned_data["value"]}) channel.save() channel.assign_all_checks() @@ -1204,7 +1212,7 @@ def add_sms(request): "page": "channels", "project": request.project, "form": form, - "profile": request.project.owner_profile + "profile": request.project.owner_profile, } return render(request, "integrations/add_sms.html", ctx) @@ -1222,19 +1230,21 @@ def add_trello(request): channel.assign_all_checks() return redirect("hc-channels") - authorize_url = "https://trello.com/1/authorize?" + urlencode({ - "expiration": "never", - "name": settings.SITE_NAME, - "scope": "read,write", - "response_type": "token", - "key": settings.TRELLO_APP_KEY, - "return_url": settings.SITE_ROOT + reverse("hc-add-trello") - }) + authorize_url = "https://trello.com/1/authorize?" + urlencode( + { + "expiration": "never", + "name": settings.SITE_NAME, + "scope": "read,write", + "response_type": "token", + "key": settings.TRELLO_APP_KEY, + "return_url": settings.SITE_ROOT + reverse("hc-add-trello"), + } + ) ctx = { "page": "channels", "project": request.project, - "authorize_url": authorize_url + "authorize_url": authorize_url, } return render(request, "integrations/add_trello.html", ctx) @@ -1268,7 +1278,7 @@ def add_matrix(request): "page": "channels", "project": request.project, "form": form, - "matrix_user_id": settings.MATRIX_USER_ID + "matrix_user_id": settings.MATRIX_USER_ID, } return render(request, "integrations/add_matrix.html", ctx) @@ -1278,17 +1288,16 @@ def add_matrix(request): def trello_settings(request): token = request.POST.get("token") - url = "https://api.trello.com/1/members/me/boards?" + urlencode({ - "key": settings.TRELLO_APP_KEY, - "token": token, - "fields": "id,name", - "lists": "open", - "list_fields": "id,name" - }) + url = "https://api.trello.com/1/members/me/boards?" + urlencode( + { + "key": settings.TRELLO_APP_KEY, + "token": token, + "fields": "id,name", + "lists": "open", + "list_fields": "id,name", + } + ) r = requests.get(url) - ctx = { - "token": token, - "data": r.json() - } + ctx = {"token": token, "data": r.json()} return render(request, "integrations/trello_settings.html", ctx) diff --git a/hc/lib/badges.py b/hc/lib/badges.py index 9fc06f4b..8847e882 100644 --- a/hc/lib/badges.py +++ b/hc/lib/badges.py @@ -3,21 +3,75 @@ from django.core.signing import base64_hmac from django.template.loader import render_to_string from django.urls import reverse -WIDTHS = {"a": 7, "b": 7, "c": 6, "d": 7, "e": 6, "f": 4, "g": 7, "h": 7, - "i": 3, "j": 3, "k": 7, "l": 3, "m": 10, "n": 7, "o": 7, "p": 7, - "q": 7, "r": 4, "s": 6, "t": 5, "u": 7, "v": 7, "w": 9, "x": 6, - "y": 7, "z": 7, "0": 7, "1": 6, "2": 7, "3": 7, "4": 7, "5": 7, - "6": 7, "7": 7, "8": 7, "9": 7, "A": 8, "B": 7, "C": 8, "D": 8, - "E": 7, "F": 6, "G": 9, "H": 8, "I": 3, "J": 4, "K": 7, "L": 6, - "M": 10, "N": 8, "O": 9, "P": 6, "Q": 9, "R": 7, "S": 7, "T": 7, - "U": 8, "V": 8, "W": 11, "X": 7, "Y": 7, "Z": 7, "-": 4, "_": 6} - -COLORS = { - "up": "#4c1", - "late": "#fe7d37", - "down": "#e05d44" +WIDTHS = { + "a": 7, + "b": 7, + "c": 6, + "d": 7, + "e": 6, + "f": 4, + "g": 7, + "h": 7, + "i": 3, + "j": 3, + "k": 7, + "l": 3, + "m": 10, + "n": 7, + "o": 7, + "p": 7, + "q": 7, + "r": 4, + "s": 6, + "t": 5, + "u": 7, + "v": 7, + "w": 9, + "x": 6, + "y": 7, + "z": 7, + "0": 7, + "1": 6, + "2": 7, + "3": 7, + "4": 7, + "5": 7, + "6": 7, + "7": 7, + "8": 7, + "9": 7, + "A": 8, + "B": 7, + "C": 8, + "D": 8, + "E": 7, + "F": 6, + "G": 9, + "H": 8, + "I": 3, + "J": 4, + "K": 7, + "L": 6, + "M": 10, + "N": 8, + "O": 9, + "P": 6, + "Q": 9, + "R": 7, + "S": 7, + "T": 7, + "U": 8, + "V": 8, + "W": 11, + "X": 7, + "Y": 7, + "Z": 7, + "-": 4, + "_": 6, } +COLORS = {"up": "#4c1", "late": "#fe7d37", "down": "#e05d44"} + def get_width(s): total = 0 @@ -37,7 +91,7 @@ def get_badge_svg(tag, status): "status_center_x": w1 + w2 / 2, "tag": tag, "status": status, - "color": COLORS[status] + "color": COLORS[status], } return render_to_string("badge.svg", ctx) diff --git a/hc/lib/emails.py b/hc/lib/emails.py index 63d5f6e1..68bd34ae 100644 --- a/hc/lib/emails.py +++ b/hc/lib/emails.py @@ -15,8 +15,9 @@ class EmailThread(Thread): self.headers = headers def run(self): - msg = EmailMultiAlternatives(self.subject, self.text, to=(self.to, ), - headers=self.headers) + msg = EmailMultiAlternatives( + self.subject, self.text, to=(self.to,), headers=self.headers + ) msg.attach_alternative(self.html, "text/html") msg.send() @@ -25,9 +26,9 @@ class EmailThread(Thread): def send(name, to, ctx, headers={}): ctx["SITE_ROOT"] = settings.SITE_ROOT - subject = render('emails/%s-subject.html' % name, ctx).strip() - text = render('emails/%s-body-text.html' % name, ctx) - html = render('emails/%s-body-html.html' % name, ctx) + subject = render("emails/%s-subject.html" % name, ctx).strip() + text = render("emails/%s-body-text.html" % name, ctx) + html = render("emails/%s-body-html.html" % name, ctx) t = EmailThread(subject, text, html, to, headers) if hasattr(settings, "BLOCKING_EMAILS"): @@ -62,11 +63,11 @@ def report(to, ctx, headers={}): def invoice(to, ctx, filename, pdf_data): ctx["SITE_ROOT"] = settings.SITE_ROOT - subject = render('emails/invoice-subject.html', ctx).strip() - text = render('emails/invoice-body-text.html', ctx) - html = render('emails/invoice-body-html.html', ctx) + subject = render("emails/invoice-subject.html", ctx).strip() + text = render("emails/invoice-body-text.html", ctx) + html = render("emails/invoice-body-html.html", ctx) - msg = EmailMultiAlternatives(subject, text, to=(to, )) + msg = EmailMultiAlternatives(subject, text, to=(to,)) msg.attach_alternative(html, "text/html") msg.attach(filename, pdf_data, "application/pdf") msg.send() diff --git a/hc/lib/jsonschema.py b/hc/lib/jsonschema.py index 53e33371..d7341c9c 100644 --- a/hc/lib/jsonschema.py +++ b/hc/lib/jsonschema.py @@ -24,8 +24,7 @@ def validate(obj, schema, obj_name="value"): try: croniter(obj) except: - raise ValidationError( - "%s is not a valid cron expression" % obj_name) + raise ValidationError("%s is not a valid cron expression" % obj_name) if schema.get("format") == "timezone" and obj not in all_timezones: raise ValidationError("%s is not a valid timezone" % obj_name) diff --git a/hc/lib/tests/test_badges.py b/hc/lib/tests/test_badges.py index d5390e1e..f46fb87a 100644 --- a/hc/lib/tests/test_badges.py +++ b/hc/lib/tests/test_badges.py @@ -4,7 +4,6 @@ from hc.lib.badges import get_width, get_badge_svg class BadgesTestCase(TestCase): - def test_get_width_works(self): self.assertEqual(get_width("mm"), 20) # Default width for unknown characters is 7 diff --git a/hc/lib/tests/test_date.py b/hc/lib/tests/test_date.py index 26dbe9dd..99be8e44 100644 --- a/hc/lib/tests/test_date.py +++ b/hc/lib/tests/test_date.py @@ -5,7 +5,6 @@ from hc.lib.date import format_hms class DateFormattingTestCase(TestCase): - def test_mins_secs_work(self): s = format_hms(td(seconds=0)) self.assertEqual(s, "0 sec") diff --git a/hc/lib/tests/test_jsonschema.py b/hc/lib/tests/test_jsonschema.py index 88a08990..b83b95b6 100644 --- a/hc/lib/tests/test_jsonschema.py +++ b/hc/lib/tests/test_jsonschema.py @@ -4,7 +4,6 @@ from hc.lib.jsonschema import ValidationError, validate class JsonSchemaTestCase(TestCase): - def test_it_validates_strings(self): validate("foo", {"type": "string"}) @@ -36,12 +35,10 @@ class JsonSchemaTestCase(TestCase): validate(5, {"type": "number", "maximum": 0}) def test_it_validates_objects(self): - validate({"foo": "bar"}, { - "type": "object", - "properties": { - "foo": {"type": "string"} - } - }) + validate( + {"foo": "bar"}, + {"type": "object", "properties": {"foo": {"type": "string"}}}, + ) def test_it_checks_dict_type(self): with self.assertRaises(ValidationError): @@ -49,39 +46,25 @@ class JsonSchemaTestCase(TestCase): def test_it_validates_objects_properties(self): with self.assertRaises(ValidationError): - validate({"foo": "bar"}, { - "type": "object", - "properties": { - "foo": {"type": "number"} - } - }) + validate( + {"foo": "bar"}, + {"type": "object", "properties": {"foo": {"type": "number"}}}, + ) def test_it_handles_required_properties(self): with self.assertRaises(ValidationError): - validate({"foo": "bar"}, { - "type": "object", - "required": ["baz"] - }) + validate({"foo": "bar"}, {"type": "object", "required": ["baz"]}) def test_it_validates_arrays(self): - validate(["foo", "bar"], { - "type": "array", - "items": {"type": "string"} - }) + validate(["foo", "bar"], {"type": "array", "items": {"type": "string"}}) def test_it_validates_array_type(self): with self.assertRaises(ValidationError): - validate("not-an-array", { - "type": "array", - "items": {"type": "string"} - }) + validate("not-an-array", {"type": "array", "items": {"type": "string"}}) def test_it_validates_array_elements(self): with self.assertRaises(ValidationError): - validate(["foo", "bar"], { - "type": "array", - "items": {"type": "number"} - }) + validate(["foo", "bar"], {"type": "array", "items": {"type": "number"}}) def test_it_validates_enum(self): validate("foo", {"enum": ["foo", "bar"]}) diff --git a/hc/payments/admin.py b/hc/payments/admin.py index 6f724988..54e9a3a2 100644 --- a/hc/payments/admin.py +++ b/hc/payments/admin.py @@ -8,16 +8,28 @@ from hc.payments.models import Subscription @admin.register(Subscription) class SubsAdmin(admin.ModelAdmin): - readonly_fields = ("email", ) - search_fields = ("customer_id", "payment_method_token", "subscription_id", - "user__email") - list_display = ("id", "email", "customer_id", "address_id", - "payment_method_token", "subscription_id", "plan_id", - "plan_name", "profile") - - list_filter = ("plan_id", ) - raw_id_fields = ("user", ) - actions = ("cancel", ) + readonly_fields = ("email",) + search_fields = ( + "customer_id", + "payment_method_token", + "subscription_id", + "user__email", + ) + list_display = ( + "id", + "email", + "customer_id", + "address_id", + "payment_method_token", + "subscription_id", + "plan_id", + "plan_name", + "profile", + ) + + list_filter = ("plan_id",) + raw_id_fields = ("user",) + actions = ("cancel",) def email(self, obj): return obj.user.email if obj.user else None @@ -25,8 +37,7 @@ class SubsAdmin(admin.ModelAdmin): @mark_safe def profile(self, obj): if obj.user.profile: - url = reverse("admin:accounts_profile_change", - args=[obj.user.profile.id]) + url = reverse("admin:accounts_profile_change", args=[obj.user.profile.id]) return "View Profile" % url return "" diff --git a/hc/payments/context_processors.py b/hc/payments/context_processors.py index 27da5020..a25e7039 100644 --- a/hc/payments/context_processors.py +++ b/hc/payments/context_processors.py @@ -2,4 +2,4 @@ from django.conf import settings def payments(request): - return {'show_pricing': settings.USE_PAYMENTS} + return {"show_pricing": settings.USE_PAYMENTS} diff --git a/hc/payments/invoices.py b/hc/payments/invoices.py index 5391cf8a..7edc8bdc 100644 --- a/hc/payments/invoices.py +++ b/hc/payments/invoices.py @@ -4,6 +4,7 @@ try: from reportlab.lib.pagesizes import A4 from reportlab.lib.units import inch from reportlab.pdfgen.canvas import Canvas + W, H = A4 except ImportError: # Don't crash if reportlab is not installed. @@ -70,8 +71,7 @@ class PdfInvoice(Canvas): self.linefeed() self.hr() - self.row(["Description", "Start", "End", tx.currency_iso_code], - bold=True) + self.row(["Description", "Start", "End", tx.currency_iso_code], bold=True) self.hr() start = f(tx.subscription_details.billing_period_start_date) end = f(tx.subscription_details.billing_period_end_date) diff --git a/hc/payments/migrations/0001_initial.py b/hc/payments/migrations/0001_initial.py index 48b241a7..54f225ee 100644 --- a/hc/payments/migrations/0001_initial.py +++ b/hc/payments/migrations/0001_initial.py @@ -7,19 +7,33 @@ from django.conf import settings class Migration(migrations.Migration): - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] + dependencies = [migrations.swappable_dependency(settings.AUTH_USER_MODEL)] operations = [ migrations.CreateModel( - name='Subscription', + name="Subscription", fields=[ - ('id', models.AutoField(serialize=False, primary_key=True, auto_created=True, verbose_name='ID')), - ('customer_id', models.CharField(blank=True, max_length=36)), - ('payment_method_token', models.CharField(blank=True, max_length=35)), - ('subscription_id', models.CharField(blank=True, max_length=10)), - ('user', models.OneToOneField(blank=True, null=True, to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)), + ( + "id", + models.AutoField( + serialize=False, + primary_key=True, + auto_created=True, + verbose_name="ID", + ), + ), + ("customer_id", models.CharField(blank=True, max_length=36)), + ("payment_method_token", models.CharField(blank=True, max_length=35)), + ("subscription_id", models.CharField(blank=True, max_length=10)), + ( + "user", + models.OneToOneField( + blank=True, + null=True, + to=settings.AUTH_USER_MODEL, + on_delete=models.CASCADE, + ), + ), ], - ), + ) ] diff --git a/hc/payments/migrations/0002_subscription_plan_id.py b/hc/payments/migrations/0002_subscription_plan_id.py index 03281f34..8fdac187 100644 --- a/hc/payments/migrations/0002_subscription_plan_id.py +++ b/hc/payments/migrations/0002_subscription_plan_id.py @@ -6,14 +6,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('payments', '0001_initial'), - ] + dependencies = [("payments", "0001_initial")] operations = [ migrations.AddField( - model_name='subscription', - name='plan_id', + model_name="subscription", + name="plan_id", field=models.CharField(blank=True, max_length=10), - ), + ) ] diff --git a/hc/payments/migrations/0003_subscription_address_id.py b/hc/payments/migrations/0003_subscription_address_id.py index 1df31f9d..4c3c1b5d 100644 --- a/hc/payments/migrations/0003_subscription_address_id.py +++ b/hc/payments/migrations/0003_subscription_address_id.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('payments', '0002_subscription_plan_id'), - ] + dependencies = [("payments", "0002_subscription_plan_id")] operations = [ migrations.AddField( - model_name='subscription', - name='address_id', + model_name="subscription", + name="address_id", field=models.CharField(blank=True, max_length=2), - ), + ) ] diff --git a/hc/payments/migrations/0004_subscription_send_invoices.py b/hc/payments/migrations/0004_subscription_send_invoices.py index 568a7894..48ba3d53 100644 --- a/hc/payments/migrations/0004_subscription_send_invoices.py +++ b/hc/payments/migrations/0004_subscription_send_invoices.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('payments', '0003_subscription_address_id'), - ] + dependencies = [("payments", "0003_subscription_address_id")] operations = [ migrations.AddField( - model_name='subscription', - name='send_invoices', + model_name="subscription", + name="send_invoices", field=models.BooleanField(default=True), - ), + ) ] diff --git a/hc/payments/migrations/0005_subscription_plan_name.py b/hc/payments/migrations/0005_subscription_plan_name.py index a2f8a339..18fb38da 100644 --- a/hc/payments/migrations/0005_subscription_plan_name.py +++ b/hc/payments/migrations/0005_subscription_plan_name.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('payments', '0004_subscription_send_invoices'), - ] + dependencies = [("payments", "0004_subscription_send_invoices")] operations = [ migrations.AddField( - model_name='subscription', - name='plan_name', + model_name="subscription", + name="plan_name", field=models.CharField(blank=True, max_length=50), - ), + ) ] diff --git a/hc/payments/migrations/0006_subscription_invoice_email.py b/hc/payments/migrations/0006_subscription_invoice_email.py index 81c2f2e0..d26d413f 100644 --- a/hc/payments/migrations/0006_subscription_invoice_email.py +++ b/hc/payments/migrations/0006_subscription_invoice_email.py @@ -7,14 +7,12 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ('payments', '0005_subscription_plan_name'), - ] + dependencies = [("payments", "0005_subscription_plan_name")] operations = [ migrations.AddField( - model_name='subscription', - name='invoice_email', + model_name="subscription", + name="invoice_email", field=models.EmailField(blank=True, max_length=254), - ), + ) ] diff --git a/hc/payments/models.py b/hc/payments/models.py index e7f068ce..5903791c 100644 --- a/hc/payments/models.py +++ b/hc/payments/models.py @@ -11,13 +11,18 @@ else: braintree = None -ADDRESS_KEYS = ("company", "street_address", - "extended_address", "locality", "region", "postal_code", - "country_code_alpha2") +ADDRESS_KEYS = ( + "company", + "street_address", + "extended_address", + "locality", + "region", + "postal_code", + "country_code_alpha2", +) class SubscriptionManager(models.Manager): - def for_user(self, user): sub, created = Subscription.objects.get_or_create(user_id=user.id) return sub @@ -74,16 +79,12 @@ class Subscription(models.Model): return self._sub def get_client_token(self): - return braintree.ClientToken.generate({ - "customer_id": self.customer_id - }) + return braintree.ClientToken.generate({"customer_id": self.customer_id}) def update_payment_method(self, nonce): # Create customer record if it does not exist: if not self.customer_id: - result = braintree.Customer.create({ - "email": self.user.email - }) + result = braintree.Customer.create({"email": self.user.email}) if not result.is_success: return result @@ -91,11 +92,13 @@ class Subscription(models.Model): self.save() # Create payment method - result = braintree.PaymentMethod.create({ - "customer_id": self.customer_id, - "payment_method_nonce": nonce, - "options": {"make_default": True} - }) + result = braintree.PaymentMethod.create( + { + "customer_id": self.customer_id, + "payment_method_nonce": nonce, + "options": {"make_default": True}, + } + ) if not result.is_success: return result @@ -105,9 +108,10 @@ class Subscription(models.Model): # Update an existing subscription to use this payment method if self.subscription_id: - result = braintree.Subscription.update(self.subscription_id, { - "payment_method_token": self.payment_method_token - }) + result = braintree.Subscription.update( + self.subscription_id, + {"payment_method_token": self.payment_method_token}, + ) if not result.is_success: return result @@ -115,9 +119,7 @@ class Subscription(models.Model): def update_address(self, post_data): # Create customer record if it does not exist: if not self.customer_id: - result = braintree.Customer.create({ - "email": self.user.email - }) + result = braintree.Customer.create({"email": self.user.email}) if not result.is_success: return result @@ -126,9 +128,9 @@ class Subscription(models.Model): payload = {key: str(post_data.get(key)) for key in ADDRESS_KEYS} if self.address_id: - result = braintree.Address.update(self.customer_id, - self.address_id, - payload) + result = braintree.Address.update( + self.customer_id, self.address_id, payload + ) else: payload["customer_id"] = self.customer_id result = braintree.Address.create(payload) @@ -140,10 +142,9 @@ class Subscription(models.Model): return result def setup(self, plan_id): - result = braintree.Subscription.create({ - "payment_method_token": self.payment_method_token, - "plan_id": plan_id - }) + result = braintree.Subscription.create( + {"payment_method_token": self.payment_method_token, "plan_id": plan_id} + ) if result.is_success: self.subscription_id = result.subscription.id @@ -186,8 +187,9 @@ class Subscription(models.Model): def address(self): if not hasattr(self, "_address"): try: - self._address = braintree.Address.find(self.customer_id, - self.address_id) + self._address = braintree.Address.find( + self.customer_id, self.address_id + ) except braintree.exceptions.NotFoundError: self._address = None @@ -206,6 +208,10 @@ class Subscription(models.Model): if not self.customer_id: self._tx = [] else: - self._tx = list(braintree.Transaction.search(braintree.TransactionSearch.customer_id == self.customer_id)) + self._tx = list( + braintree.Transaction.search( + braintree.TransactionSearch.customer_id == self.customer_id + ) + ) return self._tx diff --git a/hc/payments/tests/test_address.py b/hc/payments/tests/test_address.py index 2901860c..3333de6d 100644 --- a/hc/payments/tests/test_address.py +++ b/hc/payments/tests/test_address.py @@ -5,7 +5,6 @@ from hc.test import BaseTestCase class AddressTestCase(BaseTestCase): - @patch("hc.payments.models.braintree") def test_it_retrieves_address(self, mock): mock.Address.find.return_value = {"company": "FooCo"} diff --git a/hc/payments/tests/test_billing.py b/hc/payments/tests/test_billing.py index d62addbb..ce0c56dd 100644 --- a/hc/payments/tests/test_billing.py +++ b/hc/payments/tests/test_billing.py @@ -3,7 +3,6 @@ from hc.test import BaseTestCase class BillingCase(BaseTestCase): - def test_it_disables_invoice_emailing(self): self.client.login(username="alice@example.org", password="password") diff --git a/hc/payments/tests/test_billing_history.py b/hc/payments/tests/test_billing_history.py index e6c7a1ec..8ca67150 100644 --- a/hc/payments/tests/test_billing_history.py +++ b/hc/payments/tests/test_billing_history.py @@ -5,7 +5,6 @@ from hc.test import BaseTestCase class BillingHistoryTestCase(BaseTestCase): - def setUp(self): super(BillingHistoryTestCase, self).setUp() self.sub = Subscription(user=self.alice) diff --git a/hc/payments/tests/test_charge_webhook.py b/hc/payments/tests/test_charge_webhook.py index 99213881..7ca3faa3 100644 --- a/hc/payments/tests/test_charge_webhook.py +++ b/hc/payments/tests/test_charge_webhook.py @@ -13,7 +13,6 @@ except ImportError: class ChargeWebhookTestCase(BaseTestCase): - def setUp(self): super(ChargeWebhookTestCase, self).setUp() self.sub = Subscription(user=self.alice) diff --git a/hc/payments/tests/test_get_client_token.py b/hc/payments/tests/test_get_client_token.py index 3bd11d03..eb83a3c7 100644 --- a/hc/payments/tests/test_get_client_token.py +++ b/hc/payments/tests/test_get_client_token.py @@ -5,7 +5,6 @@ from hc.test import BaseTestCase class GetClientTokenTestCase(BaseTestCase): - @patch("hc.payments.models.braintree") def test_it_works(self, mock_braintree): mock_braintree.ClientToken.generate.return_value = "test-token" diff --git a/hc/payments/tests/test_payment_method.py b/hc/payments/tests/test_payment_method.py index 8720746a..1a2b7ec6 100644 --- a/hc/payments/tests/test_payment_method.py +++ b/hc/payments/tests/test_payment_method.py @@ -5,7 +5,6 @@ from hc.test import BaseTestCase class UpdatePaymentMethodTestCase(BaseTestCase): - def _setup_mock(self, mock): """ Set up Braintree calls that the controller will use. """ diff --git a/hc/payments/tests/test_pdf_invoice.py b/hc/payments/tests/test_pdf_invoice.py index 0c7d8cc3..64010f0f 100644 --- a/hc/payments/tests/test_pdf_invoice.py +++ b/hc/payments/tests/test_pdf_invoice.py @@ -12,7 +12,6 @@ except ImportError: class PdfInvoiceTestCase(BaseTestCase): - def setUp(self): super(PdfInvoiceTestCase, self).setUp() self.sub = Subscription(user=self.alice) diff --git a/hc/payments/tests/test_pricing.py b/hc/payments/tests/test_pricing.py index d1cd9cc6..f5becf87 100644 --- a/hc/payments/tests/test_pricing.py +++ b/hc/payments/tests/test_pricing.py @@ -5,7 +5,6 @@ from hc.test import BaseTestCase class PricingTestCase(BaseTestCase): - def test_anonymous(self): r = self.client.get("/pricing/") self.assertContains(r, "Unlimited Team Members", status_code=200) diff --git a/hc/payments/tests/test_set_plan.py b/hc/payments/tests/test_set_plan.py index c9529ede..50709478 100644 --- a/hc/payments/tests/test_set_plan.py +++ b/hc/payments/tests/test_set_plan.py @@ -5,7 +5,6 @@ from hc.test import BaseTestCase class SetPlanTestCase(BaseTestCase): - def _setup_mock(self, mock): """ Set up Braintree calls that the controller will use. """ diff --git a/hc/payments/urls.py b/hc/payments/urls.py index a6031796..e0fabb41 100644 --- a/hc/payments/urls.py +++ b/hc/payments/urls.py @@ -3,37 +3,25 @@ from django.urls import path from . import views urlpatterns = [ - path('pricing/', - views.pricing, - name="hc-pricing"), - - path('accounts/profile/billing/', - views.billing, - name="hc-billing"), - - path('accounts/profile/billing/history/', - views.billing_history, - name="hc-billing-history"), - - path('accounts/profile/billing/address/', - views.address, - name="hc-billing-address"), - - path('accounts/profile/billing/payment_method/', - views.payment_method, - name="hc-payment-method"), - - path('invoice/pdf//', - views.pdf_invoice, - name="hc-invoice-pdf"), - - path('pricing/set_plan/', - views.set_plan, - name="hc-set-plan"), - - path('pricing/get_client_token/', - views.get_client_token, - name="hc-get-client-token"), - - path('pricing/charge/', views.charge_webhook), + path("pricing/", views.pricing, name="hc-pricing"), + path("accounts/profile/billing/", views.billing, name="hc-billing"), + path( + "accounts/profile/billing/history/", + views.billing_history, + name="hc-billing-history", + ), + path("accounts/profile/billing/address/", views.address, name="hc-billing-address"), + path( + "accounts/profile/billing/payment_method/", + views.payment_method, + name="hc-payment-method", + ), + path( + "invoice/pdf//", views.pdf_invoice, name="hc-invoice-pdf" + ), + path("pricing/set_plan/", views.set_plan, name="hc-set-plan"), + path( + "pricing/get_client_token/", views.get_client_token, name="hc-get-client-token" + ), + path("pricing/charge/", views.charge_webhook), ] diff --git a/hc/payments/views.py b/hc/payments/views.py index b77e5027..98466bf6 100644 --- a/hc/payments/views.py +++ b/hc/payments/views.py @@ -2,8 +2,12 @@ from io import BytesIO from django.contrib import messages from django.contrib.auth.decorators import login_required -from django.http import (HttpResponseBadRequest, HttpResponseForbidden, - JsonResponse, HttpResponse) +from django.http import ( + HttpResponseBadRequest, + HttpResponseForbidden, + JsonResponse, + HttpResponse, +) from django.shortcuts import get_object_or_404, redirect, render from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_POST @@ -57,7 +61,7 @@ def billing(request): "send_invoices_status": send_invoices_status, "set_plan_status": "default", "address_status": "default", - "payment_method_status": "default" + "payment_method_status": "default", } if "set_plan_status" in request.session: @@ -67,8 +71,7 @@ def billing(request): ctx["address_status"] = request.session.pop("address_status") if "payment_method_status" in request.session: - ctx["payment_method_status"] = \ - request.session.pop("payment_method_status") + ctx["payment_method_status"] = request.session.pop("payment_method_status") return render(request, "accounts/billing.html", ctx) @@ -164,10 +167,7 @@ def payment_method(request): request.session["payment_method_status"] = "success" return redirect("hc-billing") - ctx = { - "sub": sub, - "pm": sub.payment_method - } + ctx = {"sub": sub, "pm": sub.payment_method} return render(request, "payments/payment_method.html", ctx) @@ -195,9 +195,9 @@ def pdf_invoice(request, transaction_id): if sub.user != request.user and not request.user.is_superuser: return HttpResponseForbidden() - response = HttpResponse(content_type='application/pdf') + response = HttpResponse(content_type="application/pdf") filename = "MS-HC-%s.pdf" % tx.id.upper() - response['Content-Disposition'] = 'attachment; filename="%s"' % filename + response["Content-Disposition"] = 'attachment; filename="%s"' % filename PdfInvoice(response).render(tx, sub.flattened_address()) return response diff --git a/hc/settings.py b/hc/settings.py index 9cd77c64..53f0e813 100644 --- a/hc/settings.py +++ b/hc/settings.py @@ -36,66 +36,65 @@ USE_PAYMENTS = envbool("USE_PAYMENTS", "False") REGISTRATION_OPEN = envbool("REGISTRATION_OPEN", "True") INSTALLED_APPS = ( - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.humanize', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'compressor', - - 'hc.accounts', - 'hc.api', - 'hc.front', - 'hc.payments' + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.humanize", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "compressor", + "hc.accounts", + "hc.api", + "hc.front", + "hc.payments", ) MIDDLEWARE = ( - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', - 'hc.accounts.middleware.TeamAccessMiddleware', + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", + "hc.accounts.middleware.TeamAccessMiddleware", ) AUTHENTICATION_BACKENDS = ( - 'hc.accounts.backends.EmailBackend', - 'hc.accounts.backends.ProfileBackend' + "hc.accounts.backends.EmailBackend", + "hc.accounts.backends.ProfileBackend", ) -ROOT_URLCONF = 'hc.urls' +ROOT_URLCONF = "hc.urls" TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [os.path.join(BASE_DIR, 'templates')], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - 'hc.payments.context_processors.payments' - ], + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [os.path.join(BASE_DIR, "templates")], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + "hc.payments.context_processors.payments", + ] }, - }, + } ] -WSGI_APPLICATION = 'hc.wsgi.application' -TEST_RUNNER = 'hc.api.tests.CustomRunner' +WSGI_APPLICATION = "hc.wsgi.application" +TEST_RUNNER = "hc.api.tests.CustomRunner" # Default database engine is SQLite. So one can just check out code, # install requirements.txt and do manage.py runserver and it works DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': os.getenv("DB_NAME", BASE_DIR + "/hc.sqlite"), + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": os.getenv("DB_NAME", BASE_DIR + "/hc.sqlite"), } } @@ -103,36 +102,38 @@ DATABASES = { # variable 'DB'. Travis CI does this. if os.getenv("DB") == "postgres": DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql', - 'HOST': os.getenv("DB_HOST", ""), - 'PORT': os.getenv("DB_PORT", ""), - 'NAME': os.getenv("DB_NAME", "hc"), - 'USER': os.getenv("DB_USER", "postgres"), - 'PASSWORD': os.getenv("DB_PASSWORD", ""), - 'CONN_MAX_AGE': envint("DB_CONN_MAX_AGE", "0"), - 'TEST': {'CHARSET': 'UTF8'}, - 'OPTIONS': { + "default": { + "ENGINE": "django.db.backends.postgresql", + "HOST": os.getenv("DB_HOST", ""), + "PORT": os.getenv("DB_PORT", ""), + "NAME": os.getenv("DB_NAME", "hc"), + "USER": os.getenv("DB_USER", "postgres"), + "PASSWORD": os.getenv("DB_PASSWORD", ""), + "CONN_MAX_AGE": envint("DB_CONN_MAX_AGE", "0"), + "TEST": {"CHARSET": "UTF8"}, + "OPTIONS": { "sslmode": os.getenv("DB_SSLMODE", "prefer"), - "target_session_attrs": os.getenv("DB_TARGET_SESSION_ATTRS", "read-write") - } + "target_session_attrs": os.getenv( + "DB_TARGET_SESSION_ATTRS", "read-write" + ), + }, } } if os.getenv("DB") == "mysql": DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.mysql', - 'HOST': os.getenv("DB_HOST", ""), - 'PORT': os.getenv("DB_PORT", ""), - 'NAME': os.getenv("DB_NAME", "hc"), - 'USER': os.getenv("DB_USER", "root"), - 'PASSWORD': os.getenv("DB_PASSWORD", ""), - 'TEST': {'CHARSET': 'UTF8'} + "default": { + "ENGINE": "django.db.backends.mysql", + "HOST": os.getenv("DB_HOST", ""), + "PORT": os.getenv("DB_PORT", ""), + "NAME": os.getenv("DB_NAME", "hc"), + "USER": os.getenv("DB_USER", "root"), + "PASSWORD": os.getenv("DB_PASSWORD", ""), + "TEST": {"CHARSET": "UTF8"}, } } -TIME_ZONE = 'UTC' +TIME_ZONE = "UTC" USE_I18N = True @@ -145,13 +146,13 @@ SITE_NAME = os.getenv("SITE_NAME", "Mychecks") MASTER_BADGE_LABEL = os.getenv("MASTER_BADGE_LABEL", SITE_NAME) PING_ENDPOINT = os.getenv("PING_ENDPOINT", SITE_ROOT + "/ping/") PING_EMAIL_DOMAIN = os.getenv("PING_EMAIL_DOMAIN", "localhost") -STATIC_URL = '/static/' +STATIC_URL = "/static/" STATICFILES_DIRS = [os.path.join(BASE_DIR, "static")] -STATIC_ROOT = os.path.join(BASE_DIR, 'static-collected') +STATIC_ROOT = os.path.join(BASE_DIR, "static-collected") STATICFILES_FINDERS = ( - 'django.contrib.staticfiles.finders.FileSystemFinder', - 'django.contrib.staticfiles.finders.AppDirectoriesFinder', - 'compressor.finders.CompressorFinder', + "django.contrib.staticfiles.finders.FileSystemFinder", + "django.contrib.staticfiles.finders.AppDirectoriesFinder", + "compressor.finders.CompressorFinder", ) COMPRESS_OFFLINE = True COMPRESS_CSS_HASHING_METHOD = "content" diff --git a/hc/test.py b/hc/test.py index 84579d12..cc28a82a 100644 --- a/hc/test.py +++ b/hc/test.py @@ -5,7 +5,6 @@ from hc.accounts.models import Member, Profile, Project class BaseTestCase(TestCase): - def setUp(self): super(BaseTestCase, self).setUp() diff --git a/hc/urls.py b/hc/urls.py index a9bce525..761250f7 100644 --- a/hc/urls.py +++ b/hc/urls.py @@ -4,13 +4,21 @@ from django.urls import include, path from hc.accounts import views as accounts_views urlpatterns = [ - path('admin/login/', accounts_views.login), - path('admin/', admin.site.urls), - path('accounts/', include('hc.accounts.urls')), - path('projects/add/', accounts_views.add_project, name="hc-add-project"), - path('projects//settings/', accounts_views.project, name="hc-project-settings"), - path('projects//remove/', accounts_views.remove_project, name="hc-remove-project"), - path('', include('hc.api.urls')), - path('', include('hc.front.urls')), - path('', include('hc.payments.urls')) + path("admin/login/", accounts_views.login), + path("admin/", admin.site.urls), + path("accounts/", include("hc.accounts.urls")), + path("projects/add/", accounts_views.add_project, name="hc-add-project"), + path( + "projects//settings/", + accounts_views.project, + name="hc-project-settings", + ), + path( + "projects//remove/", + accounts_views.remove_project, + name="hc-remove-project", + ), + path("", include("hc.api.urls")), + path("", include("hc.front.urls")), + path("", include("hc.payments.urls")), ]