commit
e1449ff7d2
52 changed files with 225 additions and 10 deletions
29
.github/workflows/ci.yml
vendored
29
.github/workflows/ci.yml
vendored
|
|
@ -23,6 +23,9 @@ jobs:
|
|||
cd grafana-plugin/
|
||||
yarn --network-timeout 500000
|
||||
yarn build
|
||||
# pre-commit uses git, which is not working in the action without this workaround
|
||||
# see https://github.com/actions/runner-images/issues/6775
|
||||
- run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
- name: Lint All
|
||||
run: |
|
||||
pre-commit run --all-files
|
||||
|
|
@ -55,6 +58,32 @@ jobs:
|
|||
run: |
|
||||
docker run -v ${PWD}/docs/sources:/hugo/content/docs/oncall/latest -e HUGO_REFLINKSERRORLEVEL=ERROR --rm grafana/docs-base:latest /bin/bash -c 'make hugo'
|
||||
|
||||
lint-migrations-backend-mysql-rabbitmq:
|
||||
name: "Lint migrations"
|
||||
runs-on: ubuntu-latest
|
||||
container: python:3.9
|
||||
env:
|
||||
DJANGO_SETTINGS_MODULE: settings.ci-test
|
||||
SLACK_CLIENT_OAUTH_ID: 1
|
||||
services:
|
||||
rabbit_test:
|
||||
image: rabbitmq:3.7.19
|
||||
env:
|
||||
RABBITMQ_DEFAULT_USER: rabbitmq
|
||||
RABBITMQ_DEFAULT_PASS: rabbitmq
|
||||
mysql_test:
|
||||
image: mysql:5.7.25
|
||||
env:
|
||||
MYSQL_DATABASE: oncall_local_dev
|
||||
MYSQL_ROOT_PASSWORD: local_dev_pwd
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Lint migrations
|
||||
run: |
|
||||
cd engine/
|
||||
pip install -r requirements.txt
|
||||
python manage.py lintmigrations
|
||||
|
||||
unit-test-backend-mysql-rabbitmq:
|
||||
name: "Backend Tests: MySQL + RabbitMQ (RBAC enabled: ${{ matrix.rbac_enabled }})"
|
||||
runs-on: ubuntu-latest
|
||||
|
|
|
|||
|
|
@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## v1.1.23 (2023-02-06)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix bug with email case sensitivity for ICal on-call schedules ([1297](https://github.com/grafana/oncall/pull/1297))
|
||||
|
||||
## v1.1.22 (2023-02-03)
|
||||
|
||||
### Fixed
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
- [symbol not found in flat namespace '\_EVP_DigestSignUpdate'](#symbol-not-found-in-flat-namespace-_evp_digestsignupdate)
|
||||
- [IDE Specific Instructions](#ide-specific-instructions)
|
||||
- [PyCharm](#pycharm)
|
||||
- [How to write database migrations](#how-to-write-database-migrations)
|
||||
|
||||
Related: [How to develop integrations](/engine/config_integrations/README.md)
|
||||
|
||||
|
|
@ -397,3 +398,15 @@ make run-backend-celery
|
|||
5. Create a new Django Server run configuration to Run/Debug the engine
|
||||
- Use a plugin such as EnvFile to load the .env.dev file
|
||||
- Change port from 8000 to 8080
|
||||
|
||||
## How to write database migrations
|
||||
|
||||
We use [django-migration-linter](https://github.com/3YOURMIND/django-migration-linter) to keep database migrations
|
||||
backwards compatible
|
||||
|
||||
- we can automatically run migrations and they are zero-downtime, e.g. old code can work with the migrated database
|
||||
- we can run and rollback migrations without worrying about data safety
|
||||
- OnCall is deployed to the multiple environments core team is not able to control
|
||||
|
||||
See [django-migration-linter checklist](https://github.com/3YOURMIND/django-migration-linter/blob/main/docs/incompatibilities.md)
|
||||
for the common mistakes and best practices
|
||||
|
|
|
|||
|
|
@ -88,12 +88,19 @@ The Grafana OnCall Slack app includes helpful message shortcuts and slash comman
|
|||
|
||||
### Slack commands
|
||||
|
||||
Use the `/oncall` Slack command to create a new alert group directly from Slack.
|
||||
Use the `/oncall` Slack command to create a new alert group directly from Slack targetting a team and/or route.
|
||||
|
||||
1. Type `/oncall` in the message box of the desired Slack channel then click **Send**.
|
||||
1. Fill out the **Start New Escalation** creation form then click **Submit**.
|
||||
1. Once the Grafana OnCall app sends a Slack message with the newly created alert, the alert group is open and firing.
|
||||
|
||||
Use the `/escalate` Slack command to create a new alert group directly from Slack and specifically paging a user or
|
||||
a schedule.
|
||||
|
||||
1. Type `/escalate` in the message box of any Slack channel then click **Send**.
|
||||
1. Fill out the **Create alert group** form then click **Submit**.
|
||||
1. Once the Grafana OnCall app sends a Slack message with the newly created alert, the alert group is open and firing.
|
||||
|
||||
### Message shortcuts
|
||||
|
||||
Use message shortcuts to add resolution notes directly from Slack. Message shortcuts are available in the More actions menu from any message.
|
||||
|
|
|
|||
|
|
@ -96,7 +96,11 @@ features:
|
|||
slash_commands:
|
||||
- command: /oncall
|
||||
url: <ONCALL_ENGINE_PUBLIC_URL>/slack/interactive_api_endpoint/
|
||||
description: oncall
|
||||
description: Create a manual alert group
|
||||
should_escape: false
|
||||
- command: /escalate
|
||||
url: <ONCALL_ENGINE_PUBLIC_URL>/slack/interactive_api_endpoint/
|
||||
description: Direct page user(s) or schedule(s)
|
||||
should_escape: false
|
||||
oauth_config:
|
||||
redirect_urls:
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import django.core.validators
|
|||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django.db.models.manager
|
||||
import django_migration_linter as linter
|
||||
|
||||
from apps.alerts.integration_options_mixin import IntegrationOptionsMixin
|
||||
|
||||
|
|
@ -27,6 +28,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.CreateModel(
|
||||
name='Alert',
|
||||
fields=[
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django.db.models.manager
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -18,6 +19,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.AddField(
|
||||
model_name='userhasnotification',
|
||||
name='user',
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# Generated by Django 3.2.13 on 2022-06-14 15:18
|
||||
|
||||
from django.db import migrations, models
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -10,6 +11,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.AddField(
|
||||
model_name='grafanaalertingcontactpoint',
|
||||
name='datasource_uid',
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# Generated by Django 3.2.13 on 2022-07-11 11:06
|
||||
|
||||
from django.db import migrations
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -17,6 +18,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
# migrations.RemoveField(
|
||||
# model_name='alertgroup',
|
||||
# name='active_cache_for_web_calculation_id',
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# Generated by Django 3.2.13 on 2022-07-20 09:04
|
||||
|
||||
from django.db import migrations, models, OperationalError, ProgrammingError
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class AddFieldIfNotExists(migrations.AddField):
|
||||
|
|
@ -36,6 +37,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
AddFieldIfNotExists(
|
||||
model_name='alertgroup',
|
||||
name='cached_render_for_web',
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# Generated by Django 3.2.13 on 2022-07-27 10:51
|
||||
|
||||
from django.db import migrations, models
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -10,6 +11,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.AddIndex(
|
||||
model_name='alertgroup',
|
||||
index=models.Index(fields=['channel_id', 'resolved', 'acknowledged', 'silenced', 'root_alert_group_id', 'is_archived'], name='alerts_aler_channel_ee84a7_idx'),
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ from django.db import migrations
|
|||
|
||||
from apps.alerts.models import AlertReceiveChannel
|
||||
from apps.alerts.tasks import update_web_title_cache_for_alert_receive_channel
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
def populate_web_title_cache(apps, _):
|
||||
|
|
@ -19,6 +20,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.RenameField(
|
||||
model_name='alertgroup',
|
||||
old_name='verbose_name',
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# Generated by Django 3.2.16 on 2023-01-19 18:06
|
||||
|
||||
from django.db import migrations, models
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -10,6 +11,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.AlterField(
|
||||
model_name='alertgrouplogrecord',
|
||||
name='type',
|
||||
|
|
|
|||
|
|
@ -2,17 +2,30 @@ import logging
|
|||
|
||||
from rest_framework import serializers
|
||||
|
||||
from apps.alerts.models import AlertGroup
|
||||
from common.api_helpers.mixins import EagerLoadingMixin
|
||||
from apps.alerts.models import Alert, AlertGroup
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AlertGroupSerializer(EagerLoadingMixin, serializers.ModelSerializer):
|
||||
class AlertSerializer(serializers.ModelSerializer):
|
||||
|
||||
id_oncall = serializers.CharField(read_only=True, source="public_primary_key")
|
||||
payload = serializers.JSONField(read_only=True, source="raw_request_data")
|
||||
|
||||
class Meta:
|
||||
model = Alert
|
||||
fields = [
|
||||
"id_oncall",
|
||||
"payload",
|
||||
]
|
||||
|
||||
|
||||
class AlertGroupSerializer(serializers.ModelSerializer):
|
||||
|
||||
id = serializers.CharField(read_only=True, source="public_primary_key")
|
||||
status = serializers.SerializerMethodField(source="get_status")
|
||||
link = serializers.CharField(read_only=True, source="web_link")
|
||||
alerts = AlertSerializer(many=True, read_only=True)
|
||||
|
||||
def get_status(self, obj):
|
||||
return next(filter(lambda status: status[0] == obj.status, AlertGroup.STATUS_CHOICES))[1].lower()
|
||||
|
|
@ -20,7 +33,8 @@ class AlertGroupSerializer(EagerLoadingMixin, serializers.ModelSerializer):
|
|||
class Meta:
|
||||
model = AlertGroup
|
||||
fields = [
|
||||
"id_oncall",
|
||||
"id",
|
||||
"link",
|
||||
"status",
|
||||
"alerts",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ from django.utils import timezone
|
|||
|
||||
import apps.auth_token.models.slack_auth_token
|
||||
from django.db import migrations, models
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -13,6 +14,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.CreateModel(
|
||||
name='ApiAuthToken',
|
||||
fields=[
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -15,6 +16,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.AddField(
|
||||
model_name='userscheduleexportauthtoken',
|
||||
name='organization',
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# Generated by Django 3.2.16 on 2022-11-21 16:10
|
||||
|
||||
from django.db import migrations
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -10,6 +11,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.RemoveField(
|
||||
model_name='mobileappverificationtoken',
|
||||
name='organization',
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import datetime
|
|||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -17,6 +18,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.CreateModel(
|
||||
name='DynamicSetting',
|
||||
fields=[
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -14,6 +15,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.AddField(
|
||||
model_name='usernotificationpolicylogrecord',
|
||||
name='author',
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# Generated by Django 3.2.5 on 2022-08-23 12:03
|
||||
|
||||
from django.db import migrations
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -10,6 +11,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.DeleteModel(
|
||||
name='OrganizationLogRecord',
|
||||
),
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -16,6 +17,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.CreateModel(
|
||||
name='EmailMessage',
|
||||
fields=[
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import apps.heartbeat.models
|
|||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -15,6 +16,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.CreateModel(
|
||||
name='IntegrationHeartBeat',
|
||||
fields=[
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import apps.mobile_app.models
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -15,6 +16,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.CreateModel(
|
||||
name='MobileAppVerificationToken',
|
||||
fields=[
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
from django.db import migrations, models
|
||||
import uuid
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -12,6 +13,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.CreateModel(
|
||||
name='CloudHeartbeat',
|
||||
fields=[
|
||||
|
|
|
|||
|
|
@ -72,7 +72,11 @@ def users_in_ical(
|
|||
|
||||
if users_to_filter is not None:
|
||||
return list(
|
||||
{user for user in users_to_filter if user.username in usernames_from_ical or user.email in emails_from_ical}
|
||||
{
|
||||
user
|
||||
for user in users_to_filter
|
||||
if user.username in usernames_from_ical or user.email.lower() in emails_from_ical
|
||||
}
|
||||
)
|
||||
|
||||
users_found_in_ical = organization.users
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import django.core.validators
|
|||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -16,6 +17,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.CreateModel(
|
||||
name='CustomOnCallShift',
|
||||
fields=[
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -16,6 +17,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.AddField(
|
||||
model_name='oncallschedule',
|
||||
name='organization',
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# Generated by Django 3.2.5 on 2022-06-28 13:06
|
||||
|
||||
from django.db import migrations, models
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -10,6 +11,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.AlterField(
|
||||
model_name='customoncallshift',
|
||||
name='frequency',
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# Generated by Django 3.2.5 on 2022-06-28 13:07
|
||||
|
||||
from django.db import migrations, models
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -10,6 +11,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.AddField(
|
||||
model_name='customoncallshift',
|
||||
name='until',
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -11,6 +12,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.CreateModel(
|
||||
name='OnCallScheduleWeb',
|
||||
fields=[
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
from django.db import migrations, models
|
||||
from django.db.models import F
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
def fill_rotation_start_field(apps, schema_editor):
|
||||
|
|
@ -16,6 +17,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.AddField(
|
||||
model_name='customoncallshift',
|
||||
name='rotation_start',
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -11,6 +12,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.AddField(
|
||||
model_name='customoncallshift',
|
||||
name='updated_shift',
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ from django.db import migrations
|
|||
from django.db.models import Q
|
||||
|
||||
from common.timezones import is_valid_timezone
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
def fix_bad_timezone_values(model):
|
||||
|
|
@ -34,6 +35,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.RunPython(fix_bad_timezone_values('CustomOnCallShift')),
|
||||
migrations.RunPython(fix_bad_timezone_values('OnCallScheduleCalendar')),
|
||||
migrations.RunPython(fix_bad_timezone_values('OnCallScheduleWeb')),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
BEGIN:VCALENDAR
|
||||
PRODID:-//Google Inc//Google Calendar 70.9054//EN
|
||||
VERSION:2.0
|
||||
CALSCALE:GREGORIAN
|
||||
METHOD:PUBLISH
|
||||
X-WR-CALNAME:test
|
||||
X-WR-TIMEZONE:Europe/London
|
||||
BEGIN:VEVENT
|
||||
DTSTART:20230206T110000Z
|
||||
DTEND:20230206T120000Z
|
||||
DTSTAMP:20230206T112228Z
|
||||
UID:16m6o1qji0fdg49coeflc202ss@google.com
|
||||
CREATED:20230206T112217Z
|
||||
DESCRIPTION:
|
||||
LAST-MODIFIED:20230206T112217Z
|
||||
SEQUENCE:0
|
||||
STATUS:CONFIRMED
|
||||
SUMMARY:Test@TEST.test
|
||||
TRANSP:OPAQUE
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
||||
|
|
@ -1382,6 +1382,37 @@ def test_get_oncall_users_for_multiple_schedules(
|
|||
)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_get_oncall_users_for_multiple_schedules_emails_case_insensitive(
|
||||
get_ical,
|
||||
make_organization,
|
||||
make_user_for_organization,
|
||||
make_on_call_shift,
|
||||
make_schedule,
|
||||
):
|
||||
"""
|
||||
Test that emails are case insensitive when matching users to on-call shifts.
|
||||
https://github.com/grafana/oncall/issues/1296
|
||||
"""
|
||||
organization = make_organization()
|
||||
|
||||
# user's email case is the opposite of the one in the ICal file below (Test@TEST.test)
|
||||
user = make_user_for_organization(organization, email="tEST@test.TEST")
|
||||
schedule = make_schedule(organization, schedule_class=OnCallScheduleCalendar)
|
||||
|
||||
# Load ICal file with an event for user with email Test@TEST.test for 6 February 2023, 11:00 UTC - 12:00 UTC
|
||||
calendar = get_ical("override_email_case_sensitivity.ics")
|
||||
schedule.cached_ical_file_overrides = calendar.to_ical().decode()
|
||||
schedule.save(update_fields=["cached_ical_file_overrides"])
|
||||
|
||||
# Get on-call users for 6 February 2023 11:30 UTC
|
||||
events_datetime = timezone.datetime(2023, 2, 6, 11, 30, tzinfo=timezone.utc)
|
||||
schedules = OnCallSchedule.objects.filter(pk=schedule.pk)
|
||||
oncall_users = schedules.get_oncall_users(events_datetime=events_datetime)
|
||||
|
||||
assert oncall_users == {schedule.pk: [user]}
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_shift_convert_to_ical(make_organization_and_user, make_on_call_shift):
|
||||
organization, user = make_organization_and_user()
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import django.core.validators
|
|||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -17,6 +18,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.CreateModel(
|
||||
name='SlackActionRecord',
|
||||
fields=[
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -14,6 +15,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.AddField(
|
||||
model_name='slackmessage',
|
||||
name='organization',
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import django.core.validators
|
|||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -17,6 +18,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.CreateModel(
|
||||
name='TelegramVerificationCode',
|
||||
fields=[
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# Generated by Django 3.2.16 on 2022-12-29 14:42
|
||||
|
||||
from django.db import migrations, models
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -10,6 +11,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.AlterField(
|
||||
model_name='telegrammessage',
|
||||
name='message_type',
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -15,6 +16,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.CreateModel(
|
||||
name='TwilioLogRecord',
|
||||
fields=[
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# Generated by Django 3.2.5 on 2022-06-04 10:08
|
||||
|
||||
from django.db import migrations, models
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -10,6 +11,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.AddField(
|
||||
model_name='phonecall',
|
||||
name='grafana_cloud_notification',
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import django.core.validators
|
|||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import mirage.fields
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -20,6 +21,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.CreateModel(
|
||||
name='Organization',
|
||||
fields=[
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import apps.user_management.models.user
|
||||
from django.db import migrations, models
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -11,6 +12,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='_timezone',
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# Generated by Django 3.2.5 on 2022-08-25 08:51
|
||||
|
||||
from django.db import migrations, models
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -10,6 +11,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='hide_phone_number',
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -11,6 +12,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.CreateModel(
|
||||
name='Region',
|
||||
fields=[
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# Generated by Django 3.2.15 on 2022-10-25 11:18
|
||||
|
||||
from django.db import migrations, models
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -10,6 +11,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='is_rbac_permissions_enabled',
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
from django.db import migrations, models
|
||||
import uuid
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
def fill_org_uuid(apps, schema_editor):
|
||||
|
|
@ -20,6 +21,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='uuid',
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# Generated by Django 3.2.16 on 2023-01-04 05:06
|
||||
|
||||
from django.db import migrations, models
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -10,6 +11,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='deleted_at',
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# Generated by Django 3.2.16 on 2023-01-16 09:41
|
||||
|
||||
from django.db import migrations, models
|
||||
import django_migration_linter as linter
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
|
@ -10,6 +11,7 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
linter.IgnoreMigration(),
|
||||
migrations.AddField(
|
||||
model_name='organization',
|
||||
name='is_grafana_incident_enabled',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
django==3.2.16
|
||||
django==3.2.17
|
||||
djangorestframework==3.12.4
|
||||
slackclient==1.3.0
|
||||
whitenoise==5.3.0
|
||||
|
|
@ -41,6 +41,7 @@ psycopg2==2.9.3
|
|||
emoji==1.7.0
|
||||
regex==2021.11.2
|
||||
psutil==5.9.4
|
||||
django-migration-linter==4.1.0
|
||||
opentelemetry-instrumentation-celery==0.36b0
|
||||
opentelemetry-instrumentation-pymysql==0.36b0
|
||||
opentelemetry-instrumentation-wsgi==0.36b0
|
||||
|
|
|
|||
|
|
@ -219,6 +219,7 @@ INSTALLED_APPS = [
|
|||
"debug_toolbar",
|
||||
"social_django",
|
||||
"polymorphic",
|
||||
"django_migration_linter",
|
||||
"fcm_django",
|
||||
"django_dbconn_retry",
|
||||
]
|
||||
|
|
@ -654,6 +655,10 @@ if OSS_INSTALLATION:
|
|||
"args": (),
|
||||
} # noqa
|
||||
|
||||
MIGRATION_LINTER_OPTIONS = {"exclude_apps": ["social_django", "silk", "fcm_django"]}
|
||||
# Run migrations linter on each `python manage.py makemigrations`
|
||||
MIGRATION_LINTER_OVERRIDE_MAKEMIGRATIONS = True
|
||||
|
||||
PYROSCOPE_PROFILER_ENABLED = getenv_boolean("PYROSCOPE_PROFILER_ENABLED", default=False)
|
||||
if PYROSCOPE_PROFILER_ENABLED:
|
||||
import pyroscope
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
--primary-text-color: rgb(36, 41, 46);
|
||||
--secondary-text-color: rgba(36, 41, 46, 0.75);
|
||||
--disabled-text-color: rgba(36, 41, 46, 0.5);
|
||||
--warning-text-color: #8a6c00;
|
||||
--warning-text-color: rgb(255, 120, 10);
|
||||
--success-text-color: rgb(10, 118, 78);
|
||||
--error-text-color: rgb(207, 14, 91);
|
||||
--primary-text-link: #1f62e0;
|
||||
|
|
@ -56,7 +56,7 @@
|
|||
--primary-text-color: rgb(204, 204, 220);
|
||||
--secondary-text-color: rgba(204, 204, 220, 0.65);
|
||||
--disabled-text-color: rgba(204, 204, 220, 0.4);
|
||||
--warning-text-color: #f8d06b;
|
||||
--warning-text-color: rgb(255, 120, 10);
|
||||
--success-text-color: rgb(108, 207, 142);
|
||||
--error-text-color: rgb(255, 82, 134);
|
||||
--primary-text-link: #6e9fff;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue