oncall-engine/engine/apps/base/models/live_setting.py

316 lines
15 KiB
Python
Raw Permalink Normal View History

from django.conf import settings
from django.core.validators import MinLengthValidator
from django.db import models
from django.db.models import JSONField
fix a few flaky e2e tests + allow running project locally via k8s/helm (#2751) # What this PR does - updates the GitHub Actions workflow to move the e2e tests into a "[reusable workflow](https://docs.github.com/en/actions/using-workflows/reusing-workflows#creating-a-reusable-workflow)" which are run in two scenarios: - all tests _except_ those annotated as `@expensive` are run against `grafana/grafana:latest` on all feature branches - all tests _including_ `@expensive` tests are run on weekdays @ 07h00 UTC, against a matrix of 6 grafana versions. Results of these builds will be posted to `#irm-amixr-flux` Slack channel. - local development will now be: ```bash make build-dev-images init-k8s start-k8s ``` - `build-dev-images` - builds the engine and UI docker images (only need to run first time) - `init-k8s` - creates a `kind` cluster and loads the two Docker images onto the cluster nodes (only need to run first time) - `start-k8s` - switches `kubectl` context to the created `kind` cluster, and uses `helm` to deploy everything as defined in `./dev/helm-local.yml` and `./dev/helm-local.dev.yml` (that latter file is `.gitignored` and specific to how _you_ want your setup to look like. Hot reloading works as before. This is the _start_ of #2381. (I've marked these `make` commands as beta, because they've not yet been thoroughly tested for local development). - modifies the `helm` chart to add the concept of `oncall.devMode`, `ui`, and ability to run oncall w/ sqlite - `oncall.devMode` will essentially just add `volumes` and `volumeMounts` to the various engine/migrate containers + - `ui.enabled` + `ui.env` - create a ui container (which is needed for hot reloading locally) - `sqlite` - this was useful for the e2e test environments where Github runner resources are scarce. Running `mariadb` eats up precious resources, instead lets just use sqlite here - fixes an issue that caused sporadic HTTP 502s from the grafana plugin-proxy, which led to flaky tests. See [this comment](https://github.com/grafana/oncall/pull/2751/files#diff-09040e8df192699b9c5742110ebbe8d9d5c3938cb156cc1cb99fa1c3fdee4fefR72-R77) for more context + a link to a relevant Slack conversation. **tldr;** there is a bug with the Grafana plugin proxy in Grafana >= v10.0.3. Let's stop using the `latest`/`main` docker tags in our test and pin to `10.0.2` for now - ~~re-enables the e2e test which validates a phone number via SMS, and asserts that we can receive an alert escalation via SMS (new Mailslurp API Key has been added as a repo secret)~~ update: this is still blocked by procurement, will be done in a future PR ## Checklist - [x] Unit, integration, and e2e (if applicable) tests updated - [x] Documentation added (or `pr:no public docs` PR label added if not required) - [x] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not required)
2023-08-22 19:03:29 +02:00
from django.db.utils import IntegrityError
from apps.base.utils import LiveSettingValidator
from common.public_primary_keys import generate_public_primary_key, increase_public_primary_key_length
def generate_public_primary_key_for_live_setting():
prefix = "L"
new_public_primary_key = generate_public_primary_key(prefix)
failure_counter = 0
while LiveSetting.objects.filter(public_primary_key=new_public_primary_key).exists():
new_public_primary_key = increase_public_primary_key_length(
failure_counter=failure_counter, prefix=prefix, model_name="LiveSetting"
)
failure_counter += 1
return new_public_primary_key
class LiveSetting(models.Model):
public_primary_key = models.CharField(
max_length=20,
validators=[MinLengthValidator(settings.PUBLIC_PRIMARY_KEY_MIN_LENGTH + 1)],
unique=True,
default=generate_public_primary_key_for_live_setting,
)
name = models.CharField(max_length=50, unique=True)
value = JSONField(null=True, default=None)
error = models.TextField(null=True, default=None)
AVAILABLE_NAMES = (
"EMAIL_HOST",
"EMAIL_PORT",
"EMAIL_HOST_USER",
"EMAIL_HOST_PASSWORD",
"EMAIL_USE_TLS",
"EMAIL_USE_SSL",
"EMAIL_FROM_ADDRESS",
"INBOUND_EMAIL_ESP",
"INBOUND_EMAIL_DOMAIN",
"INBOUND_EMAIL_WEBHOOK_SECRET",
"TWILIO_ACCOUNT_SID",
"TWILIO_AUTH_TOKEN",
"TWILIO_API_KEY_SID",
"TWILIO_API_KEY_SECRET",
"TWILIO_NUMBER",
"TWILIO_VERIFY_SERVICE_SID",
"TELEGRAM_TOKEN",
"TELEGRAM_WEBHOOK_HOST",
"SLACK_CLIENT_OAUTH_ID",
"SLACK_CLIENT_OAUTH_SECRET",
"SLACK_SIGNING_SECRET",
2022-06-13 15:33:56 +03:00
"SLACK_INSTALL_RETURN_REDIRECT_HOST",
"SEND_ANONYMOUS_USAGE_STATS",
"GRAFANA_CLOUD_ONCALL_TOKEN",
"GRAFANA_CLOUD_ONCALL_HEARTBEAT_ENABLED",
2022-06-03 14:59:43 -03:00
"GRAFANA_CLOUD_NOTIFICATIONS_ENABLED",
"DANGEROUS_WEBHOOKS_ENABLED",
Phone provider refactoring (#1713) # What this PR does This PR moves phone notification logic into separate object PhoneBackend and introduces PhoneProvider interface to hide actual implementation of external phone services provider. It should allow add new phone providers just by implementing one class (See SimplePhoneProvider for example). # Why [Asterisk PR](https://github.com/grafana/oncall/pull/1282) showed that our phone notification system is not flexible. However this is one of the most frequent community questions - how to add "X" phone provider. Also, this refactoring move us one step closer to unifying all notification backends, since with PhoneBackend all phone notification logic is collected in one place and independent from concrete realisation. # Highligts 1. PhoneBackend object - contains all phone notifications business logic. 2. PhoneProvider - interface to external phone services provider. 3. TwilioPhoneProvider and SimplePhoneProvider - two examples of PhoneProvider implementation. 4. PhoneCallRecord and SMSRecord models. I introduced these models to keep phone notification limits logic decoupled from external providers. Existing TwilioPhoneCall and TwilioSMS objects will be migrated to the new table to not to reset limits counter. To be able to receive status callbacks and gather from Twilio TwilioPhoneCall and TwilioSMS still exists, but they are linked to PhoneCallRecord and SMSRecord via fk, to not to leat twilio logic into core code. --------- Co-authored-by: Yulia Shanyrova <yulia.shanyrova@grafana.com>
2023-05-24 14:27:48 +08:00
"PHONE_PROVIDER",
"ZVONOK_API_KEY",
"ZVONOK_CAMPAIGN_ID",
"ZVONOK_AUDIO_ID",
"ZVONOK_SPEAKER_ID",
"ZVONOK_POSTBACK_CALL_ID",
"ZVONOK_POSTBACK_CAMPAIGN_ID",
"ZVONOK_POSTBACK_STATUS",
"ZVONOK_POSTBACK_USER_CHOICE",
"ZVONOK_POSTBACK_USER_CHOICE_ACK",
"ZVONOK_VERIFICATION_CAMPAIGN_ID",
"EXOTEL_ACCOUNT_SID",
"EXOTEL_API_KEY",
"EXOTEL_API_TOKEN",
"EXOTEL_APP_ID",
"EXOTEL_CALLER_ID",
"EXOTEL_SMS_SENDER_ID",
"EXOTEL_SMS_VERIFICATION_TEMPLATE",
"EXOTEL_SMS_DLT_ENTITY_ID",
"MATTERMOST_CLIENT_OAUTH_ID",
"MATTERMOST_CLIENT_OAUTH_SECRET",
"MATTERMOST_HOST",
"MATTERMOST_BOT_TOKEN",
"MATTERMOST_LOGIN_RETURN_REDIRECT_HOST",
"MATTERMOST_SIGNING_SECRET",
)
DESCRIPTIONS = {
"EMAIL_HOST": "SMTP server host. This email server will be used to notify users via email.",
"EMAIL_PORT": "SMTP server port",
"EMAIL_HOST_USER": "SMTP server user",
"EMAIL_HOST_PASSWORD": "SMTP server password",
"EMAIL_USE_TLS": "SMTP enable/disable TLS",
"EMAIL_USE_SSL": "SMTP enable/disable SSL. Should be used mutually exclusively with EMAIL_USE_TLS.",
"EMAIL_FROM_ADDRESS": "Email address used to send emails. If not specified, EMAIL_HOST_USER will be used.",
"INBOUND_EMAIL_DOMAIN": "Inbound email domain",
"INBOUND_EMAIL_ESP": (
"Inbound email ESP name. "
"Available options: amazon_ses, mailgun, mailjet, mandrill, postal, postmark, sendgrid, sparkpost"
),
"INBOUND_EMAIL_WEBHOOK_SECRET": "Inbound email webhook secret",
"SLACK_SIGNING_SECRET": (
"Check <a href='"
"https://grafana.com/docs/oncall/latest/open-source/#slack-setup"
"' target='_blank'>instruction</a> for details how to set up Slack. "
"Slack secrets can't be verified on the backend, please try installing the Slack Bot "
2022-06-13 15:33:56 +03:00
"after you update them."
),
"SLACK_CLIENT_OAUTH_SECRET": (
"Check <a href='"
"https://grafana.com/docs/oncall/latest/open-source/#slack-setup"
"' target='_blank'>instruction</a> for details how to set up Slack. "
"Slack secrets can't be verified on the backend, please try installing the Slack Bot "
2022-06-13 15:33:56 +03:00
"after you update them."
),
"SLACK_CLIENT_OAUTH_ID": (
"Check <a href='"
"https://grafana.com/docs/oncall/latest/open-source/#slack-setup"
"' target='_blank'>instruction</a> for details how to set up Slack. "
"Slack secrets can't be verified on the backend, please try installing the Slack Bot "
2022-06-13 15:33:56 +03:00
"after you update them."
),
"SLACK_INSTALL_RETURN_REDIRECT_HOST": (
"Check <a href='"
"https://grafana.com/docs/oncall/latest/open-source/#slack-setup"
"' target='_blank'>instruction</a> for details how to set up Slack. "
2022-06-13 15:33:56 +03:00
"Slack secrets can't be verified on the backend, please try installing the Slack Bot "
"after you update them."
),
"TWILIO_ACCOUNT_SID": (
2022-10-12 11:01:17 +02:00
"Twilio account SID/username to allow OnCall to send SMSes and make phone calls, see "
"<a href='https://support.twilio.com/hc/en-us/articles/223136027-Auth-Tokens-and-How-to-Change-Them' target='_blank'>"
2022-10-12 11:01:17 +02:00
"here</a> for more info. Required."
),
"TWILIO_API_KEY_SID": (
"Twilio API key SID/username to allow OnCall to send SMSes and make phone calls, see "
"<a href='https://www.twilio.com/docs/iam/keys/api-key' target='_blank'>"
2022-10-12 11:01:17 +02:00
"here</a> for more info. Either (TWILIO_API_KEY_SID + TWILIO_API_KEY_SECRET) or TWILIO_AUTH_TOKEN is required."
),
"TWILIO_API_KEY_SECRET": (
"Twilio API key secret/password to allow OnCall to send SMSes and make phone calls, see "
"<a href='https://www.twilio.com/docs/iam/keys/api-key' target='_blank'>"
2022-10-12 11:01:17 +02:00
"here</a> for more info. Either (TWILIO_API_KEY_SID + TWILIO_API_KEY_SECRET) or TWILIO_AUTH_TOKEN is required."
),
"TWILIO_AUTH_TOKEN": (
"Twilio password to allow OnCall to send SMSes and make calls, see "
"<a href='https://support.twilio.com/hc/en-us/articles/223136027-Auth-Tokens-and-How-to-Change-Them' target='_blank'>"
2022-10-12 11:01:17 +02:00
"here</a> for more info. Either (TWILIO_API_KEY_SID + TWILIO_API_KEY_SECRET) or TWILIO_AUTH_TOKEN is required."
),
"TWILIO_NUMBER": (
"Number from which you will receive calls and SMSes, "
"<a href='https://www.twilio.com/docs/phone-numbers' target='_blank'>more info</a>."
),
"TWILIO_VERIFY_SERVICE_SID": (
"SID of Twilio service for number verification. "
"You can create a service in Twilio web interface. "
"twilio.com -> verify -> create new service."
),
"TELEGRAM_TOKEN": (
"Secret token for Telegram bot, you can get one via <a href='https://t.me/BotFather' target='_blank'>BotFather</a>."
),
"TELEGRAM_WEBHOOK_HOST": (
"Externally available URL for Telegram to make requests. Must use https and ports 80, 88, 443, 8443."
),
"SEND_ANONYMOUS_USAGE_STATS": (
"Grafana OnCall will send anonymous, but uniquely-identifiable usage analytics to Grafana Labs."
Merge dev to main (#69) * Log (failed) attempt to notify a user with viewer role * Remove https:// prefix from BASE_URL docker env var * Fix cloud heartbeat name * Polishing telegram * Update docker-compose.yml * Update plugin README (#48) * Update README and screenshot, remove plop for build info since version is now displayed prominently * Sign build Co-authored-by: Michael Derynck <michael.derynck@grafana.com> * Build actions (#38) * Drone, github action changes * Minor version updates * Update frontend dependencies * Re-enable unit test Co-authored-by: Michael Derynck <michael.derynck@grafana.com> * Revert stylelint version (#52) * Revert stylelint version * Build plugin as well as lint * Build in previous step Co-authored-by: Michael Derynck <michael.derynck@grafana.com> * Update screenshot (#53) Co-authored-by: Michael Derynck <michael.derynck@grafana.com> * oncall images for docs (#55) * Update README.md * Top menu fix * Fix db encoding * Add api key docs * Reverting utf8 fix * bug fixes * fix for link for OSS version * Fixing utf8 and docker compose * 8080 -> 8000 port for consistency * makeReq * Fixing images * Fixing port * Fixing port * Fixing port * Fixing port * Fixing port * Fixing port * Fixing port * Fixing port * Replace symlink with file for CHANGELOG.MD (#68) Co-authored-by: Michael Derynck <michael.derynck@grafana.com> Co-authored-by: Matias Bordese <mbordese@gmail.com> Co-authored-by: Matvey Kukuy <Matvey-Kuk@users.noreply.github.com> Co-authored-by: Innokentii Konstantinov <innokenty.konstantinov@grafana.com> Co-authored-by: Matvey Kukuy <matvey@amixr.io> Co-authored-by: Michael Derynck <michael.derynck@grafana.com> Co-authored-by: Alyssa Wada <101596687+alyssawada@users.noreply.github.com> Co-authored-by: Yulia Shanyrova <yulia.shanyrova@grafana.com>
2022-06-14 09:14:45 -06:00
" These statistics are sent to https://stats.grafana.org/. For more information on what's sent, look at the "
"<a href='https://github.com/grafana/oncall/blob/dev/engine/apps/oss_installation/usage_stats.py#L29' target='_blank'> source code</a>."
),
"GRAFANA_CLOUD_ONCALL_TOKEN": "Secret token for Grafana Cloud OnCall instance.",
2022-06-25 11:19:40 +02:00
"GRAFANA_CLOUD_ONCALL_HEARTBEAT_ENABLED": "Enable heartbeat integration with Grafana Cloud OnCall.",
2022-06-03 14:59:43 -03:00
"GRAFANA_CLOUD_NOTIFICATIONS_ENABLED": "Enable SMS/call notifications via Grafana Cloud OnCall",
"DANGEROUS_WEBHOOKS_ENABLED": "Enable outgoing webhooks to private networks",
Phone provider refactoring (#1713) # What this PR does This PR moves phone notification logic into separate object PhoneBackend and introduces PhoneProvider interface to hide actual implementation of external phone services provider. It should allow add new phone providers just by implementing one class (See SimplePhoneProvider for example). # Why [Asterisk PR](https://github.com/grafana/oncall/pull/1282) showed that our phone notification system is not flexible. However this is one of the most frequent community questions - how to add "X" phone provider. Also, this refactoring move us one step closer to unifying all notification backends, since with PhoneBackend all phone notification logic is collected in one place and independent from concrete realisation. # Highligts 1. PhoneBackend object - contains all phone notifications business logic. 2. PhoneProvider - interface to external phone services provider. 3. TwilioPhoneProvider and SimplePhoneProvider - two examples of PhoneProvider implementation. 4. PhoneCallRecord and SMSRecord models. I introduced these models to keep phone notification limits logic decoupled from external providers. Existing TwilioPhoneCall and TwilioSMS objects will be migrated to the new table to not to reset limits counter. To be able to receive status callbacks and gather from Twilio TwilioPhoneCall and TwilioSMS still exists, but they are linked to PhoneCallRecord and SMSRecord via fk, to not to leat twilio logic into core code. --------- Co-authored-by: Yulia Shanyrova <yulia.shanyrova@grafana.com>
2023-05-24 14:27:48 +08:00
"PHONE_PROVIDER": f"Phone provider name. Available options: {','.join(list(settings.PHONE_PROVIDERS.keys()))}",
"ZVONOK_API_KEY": "API public key. You can get it in Profile->Settings section.",
"ZVONOK_CAMPAIGN_ID": "Calls by API campaign ID. You can get it after campaign creation.",
"ZVONOK_AUDIO_ID": "Calls with specific audio. You can get it in Audioclips section.",
"ZVONOK_SPEAKER_ID": "Calls with speaker.",
"ZVONOK_POSTBACK_CALL_ID": "'Postback' call id (ct_call_id) query parameter name to validate a postback request.",
"ZVONOK_POSTBACK_CAMPAIGN_ID": "'Postback' company id (ct_campaign_id) query parameter name to validate a postback request.",
"ZVONOK_POSTBACK_STATUS": "'Postback' status (ct_status) query parameter name to validate a postback request.",
"ZVONOK_POSTBACK_USER_CHOICE": "'Postback' user choice (ct_user_choice) query parameter name (optional).",
"ZVONOK_POSTBACK_USER_CHOICE_ACK": "'Postback' user choice (ct_user_choice) query parameter value for acknowledge alert group (optional).",
"ZVONOK_VERIFICATION_CAMPAIGN_ID": "The phone number verification campaign ID. You can get it after verification campaign creation.",
"EXOTEL_ACCOUNT_SID": "Exotel account SID. You can get it in DEVELOPER SETTINGS -> API Settings",
"EXOTEL_API_KEY": "API Key (username)",
"EXOTEL_API_TOKEN": "API Token (password)",
"EXOTEL_APP_ID": "Identifier of the flow (or applet)",
"EXOTEL_CALLER_ID": "Exophone / Exotel virtual number",
"EXOTEL_SMS_SENDER_ID": "Exotel SMS Sender ID to use for verification SMS",
"EXOTEL_SMS_VERIFICATION_TEMPLATE": "SMS text template to be used for sending SMS, add $verification_code as a placeholder for the verification code",
"EXOTEL_SMS_DLT_ENTITY_ID": "DLT Entity ID registered with TRAI.",
"MATTERMOST_CLIENT_OAUTH_ID": (
"Check <a href='"
"https://grafana.com/docs/oncall/latest/open-source/#mattermost-setup"
"' target='_blank'>instruction</a> for details how to set up Mattermost. "
),
"MATTERMOST_CLIENT_OAUTH_SECRET": (
"Check <a href='"
"https://grafana.com/docs/oncall/latest/open-source/#mattermost-setup"
"' target='_blank'>instruction</a> for details how to set up Mattermost. "
),
"MATTERMOST_HOST": (
"Check <a href='"
"https://grafana.com/docs/oncall/latest/open-source/#mattermost-setup"
"' target='_blank'>instruction</a> for details how to set up Mattermost. "
),
"MATTERMOST_BOT_TOKEN": (
"Check <a href='"
"https://grafana.com/docs/oncall/latest/open-source/#mattermost-setup"
"' target='_blank'>instruction</a> for details how to set up Mattermost. "
),
"MATTERMOST_LOGIN_RETURN_REDIRECT_HOST": (
"Check <a href='"
"https://grafana.com/docs/oncall/latest/open-source/#mattermost-setup"
"' target='_blank'>instruction</a> for details how to set up Mattermost. "
),
"MATTERMOST_SIGNING_SECRET": (
"Check <a href='"
"https://grafana.com/docs/oncall/latest/open-source/#mattermost-setup"
"' target='_blank'>instruction</a> for details how to set up Mattermost. "
),
}
SECRET_SETTING_NAMES = (
"EMAIL_HOST_PASSWORD",
"INBOUND_EMAIL_WEBHOOK_SECRET",
"TWILIO_ACCOUNT_SID",
"TWILIO_AUTH_TOKEN",
"TWILIO_API_KEY_SID",
"TWILIO_API_KEY_SECRET",
"TWILIO_VERIFY_SERVICE_SID",
"SLACK_CLIENT_OAUTH_ID",
"SLACK_CLIENT_OAUTH_SECRET",
"SLACK_SIGNING_SECRET",
"TELEGRAM_TOKEN",
"GRAFANA_CLOUD_ONCALL_TOKEN",
"ZVONOK_API_KEY",
"EXOTEL_ACCOUNT_SID",
"EXOTEL_API_TOKEN",
"MATTERMOST_CLIENT_OAUTH_ID",
"MATTERMOST_CLIENT_OAUTH_SECRET",
"MATTERMOST_BOT_TOKEN",
)
def __str__(self):
return self.name
@property
def description(self):
return self.DESCRIPTIONS.get(self.name)
@property
def default_value(self):
return self._get_setting_from_setting_file(self.name)
@property
def is_secret(self):
return self.name in self.SECRET_SETTING_NAMES
@classmethod
def get_setting(cls, setting_name):
if not settings.FEATURE_LIVE_SETTINGS_ENABLED:
return cls._get_setting_from_setting_file(setting_name)
if setting_name not in cls.AVAILABLE_NAMES:
raise ValueError(
f"Setting with name '{setting_name}' is not in list of available names {cls.AVAILABLE_NAMES}"
)
live_setting = cls.objects.filter(name=setting_name).first()
if live_setting is not None:
return live_setting.value
else:
return cls._get_setting_from_setting_file(setting_name)
@classmethod
def populate_settings_if_needed(cls):
settings_in_db = cls.objects.filter(name__in=cls.AVAILABLE_NAMES).values_list("name", flat=True)
setting_names_to_populate = set(cls.AVAILABLE_NAMES) - set(settings_in_db)
if len(setting_names_to_populate) == 0:
return
for setting_name in setting_names_to_populate:
fix a few flaky e2e tests + allow running project locally via k8s/helm (#2751) # What this PR does - updates the GitHub Actions workflow to move the e2e tests into a "[reusable workflow](https://docs.github.com/en/actions/using-workflows/reusing-workflows#creating-a-reusable-workflow)" which are run in two scenarios: - all tests _except_ those annotated as `@expensive` are run against `grafana/grafana:latest` on all feature branches - all tests _including_ `@expensive` tests are run on weekdays @ 07h00 UTC, against a matrix of 6 grafana versions. Results of these builds will be posted to `#irm-amixr-flux` Slack channel. - local development will now be: ```bash make build-dev-images init-k8s start-k8s ``` - `build-dev-images` - builds the engine and UI docker images (only need to run first time) - `init-k8s` - creates a `kind` cluster and loads the two Docker images onto the cluster nodes (only need to run first time) - `start-k8s` - switches `kubectl` context to the created `kind` cluster, and uses `helm` to deploy everything as defined in `./dev/helm-local.yml` and `./dev/helm-local.dev.yml` (that latter file is `.gitignored` and specific to how _you_ want your setup to look like. Hot reloading works as before. This is the _start_ of #2381. (I've marked these `make` commands as beta, because they've not yet been thoroughly tested for local development). - modifies the `helm` chart to add the concept of `oncall.devMode`, `ui`, and ability to run oncall w/ sqlite - `oncall.devMode` will essentially just add `volumes` and `volumeMounts` to the various engine/migrate containers + - `ui.enabled` + `ui.env` - create a ui container (which is needed for hot reloading locally) - `sqlite` - this was useful for the e2e test environments where Github runner resources are scarce. Running `mariadb` eats up precious resources, instead lets just use sqlite here - fixes an issue that caused sporadic HTTP 502s from the grafana plugin-proxy, which led to flaky tests. See [this comment](https://github.com/grafana/oncall/pull/2751/files#diff-09040e8df192699b9c5742110ebbe8d9d5c3938cb156cc1cb99fa1c3fdee4fefR72-R77) for more context + a link to a relevant Slack conversation. **tldr;** there is a bug with the Grafana plugin proxy in Grafana >= v10.0.3. Let's stop using the `latest`/`main` docker tags in our test and pin to `10.0.2` for now - ~~re-enables the e2e test which validates a phone number via SMS, and asserts that we can receive an alert escalation via SMS (new Mailslurp API Key has been added as a repo secret)~~ update: this is still blocked by procurement, will be done in a future PR ## Checklist - [x] Unit, integration, and e2e (if applicable) tests updated - [x] Documentation added (or `pr:no public docs` PR label added if not required) - [x] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not required)
2023-08-22 19:03:29 +02:00
try:
cls.objects.create(name=setting_name, value=cls._get_setting_from_setting_file(setting_name))
except IntegrityError:
# prevent the rare case where concurrent requests try inserting the same live setting and lead to:
# django.db.utils.IntegrityError: duplicate key value violates unique constraint "base_livesetting_name_key"
# this infers that a setting with this name already exists, and we can safely skip this
continue
2022-11-01 18:24:44 -06:00
cls.validate_settings()
@classmethod
2022-11-01 18:24:44 -06:00
def validate_settings(cls):
settings_to_validate = cls.objects.filter(name__in=cls.AVAILABLE_NAMES)
for setting in settings_to_validate:
setting.error = LiveSettingValidator(live_setting=setting).get_error()
setting.save(update_fields=["error"])
@staticmethod
def _get_setting_from_setting_file(setting_name):
return getattr(settings, setting_name)
def save(self, *args, **kwargs):
if self.name not in self.AVAILABLE_NAMES:
raise ValueError(
f"Setting with name '{self.name}' is not in list of available names {self.AVAILABLE_NAMES}"
)
super().save(*args, **kwargs)