Commit graph

140 commits

Author SHA1 Message Date
Vadim Stepanov
6caacf4048
Handle Slack ratelimit on alert group deletion (#3038)
# What this PR does

- gracefully retry
`apps.alerts.tasks.delete_alert_group.delete_alert_group` when hitting
Slack ratelimits
- remove Slack messages from the DB as soon as they are deleted from
Slack, so the tasks are not retrying perpetually

## 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-09-19 08:41:47 +00:00
Linhua Tan
0c7281a255
Fix Slack access token length issue (#3016)
# What this PR does

fix the following error caused by too short varchar length of database
fields `access_token` and `bot_access_token` in table
`slack_slackteamidentity`

```
2023-09-12 18:34:07.448 | django.db.utils.DataError: value too long for type character varying(100) |  
-- | -- | --
  |   | 2023-09-12 18:34:07.448 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.448 | return self.cursor.execute(sql, params) |  
  |   | 2023-09-12 18:34:07.448 | File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 84, in _execute |  
  |   | 2023-09-12 18:34:07.448 | raise dj_exc_value.with_traceback(traceback) from exc_value |  
  |   | 2023-09-12 18:34:07.448 | File "/usr/local/lib/python3.11/site-packages/django/db/utils.py", line 90, in __exit__ |  
  |   | 2023-09-12 18:34:07.448 | with self.db.wrap_database_errors: |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 79, in _execute |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | return executor(sql, params, many, context) |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 75, in _execute_with_wrappers |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | return self._execute_with_wrappers(sql, params, many=False, executor=self._execute) |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 66, in execute |  
  |   | 2023-09-12 18:34:07.447 | cursor.execute(sql, params) |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/django/db/models/sql/compiler.py", line 1175, in execute_sql |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | cursor = super().execute_sql(result_type) |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/django/db/models/sql/compiler.py", line 1559, in execute_sql |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | return query.get_compiler(self.db).execute_sql(CURSOR) |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/django/db/models/query.py", line 802, in _update |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | return filtered._update(values) > 0 |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/django/db/models/base.py", line 912, in _do_update |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | updated = self._do_update(base_qs, using, pk_val, values, update_fields, |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/django/db/models/base.py", line 858, in _save_table |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | updated = self._save_table( |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/django/db/models/base.py", line 776, in save_base |  
  |   | 2023-09-12 18:34:07.447 | self.save_base(using=using, force_insert=force_insert, |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/django/db/models/base.py", line 739, in save |  
  |   | 2023-09-12 18:34:07.447 | self.save() |  
  |   | 2023-09-12 18:34:07.447 | File "/etc/app/apps/slack/models/slack_team_identity.py", line 72, in update_oauth_fields |  
  |   | 2023-09-12 18:34:07.447 | slack_team_identity.update_oauth_fields(user, organization, response) |  
  |   | 2023-09-12 18:34:07.447 | File "/etc/app/apps/social_auth/pipeline.py", line 102, in populate_slack_identities |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | result = func(*args, **out) or {} |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/social_core/backends/base.py", line 118, in run_pipeline |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | out = self.run_pipeline(pipeline, pipeline_index, *args, **kwargs) |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/social_core/backends/base.py", line 86, in pipeline |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | return self.pipeline(pipeline, *args, **kwargs) |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/social_core/backends/base.py", line 83, in authenticate |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | user = backend.authenticate(request, **credentials) |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/django/contrib/auth/__init__.py", line 76, in authenticate |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | return func(*func_args, **func_kwargs) |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/django/views/decorators/debug.py", line 42, in sensitive_variables_wrapper |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | return authenticate(*args, **kwargs) |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/social_django/strategy.py", line 105, in authenticate |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | return self.strategy.authenticate(*args, **kwargs) |  
  |   | 2023-09-12 18:34:07.447 | File "/etc/app/apps/social_auth/backends.py", line 100, in do_auth |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | return func(*args, **kwargs) |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/social_core/utils.py", line 253, in wrapper |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | return self.do_auth(access_token, response=response, *args, **kwargs) |  
  |   | 2023-09-12 18:34:07.447 | File "/etc/app/apps/social_auth/backends.py", line 88, in auth_complete |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | return func(*args, **kwargs) |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/social_core/utils.py", line 253, in wrapper |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | return self.auth_complete(*args, **kwargs) |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/social_core/backends/base.py", line 39, in complete |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | user = backend.complete(user=user, *args, **kwargs) |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/social_core/actions.py", line 49, in do_complete |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | result = do_complete( |  
  |   | 2023-09-12 18:34:07.447 | File "/etc/app/apps/api/views/auth.py", line 52, in overridden_complete_slack_auth |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | return func(request, backend, *args, **kwargs) |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/social_django/utils.py", line 46, in wrapper |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | return view_func(*args, **kwargs) |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | response = view_func(request, *args, **kwargs) |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | return func(*args, **kwargs) |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/rest_framework/decorators.py", line 50, in handler |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | response = handler(request, *args, **kwargs) |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/rest_framework/views.py", line 506, in dispatch |  
  |   | 2023-09-12 18:34:07.447 | raise exc |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception |  
  |   | 2023-09-12 18:34:07.447 | self.raise_uncaught_exception(exc) |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/rest_framework/views.py", line 469, in handle_exception |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | response = self.handle_exception(exc) |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/rest_framework/views.py", line 509, in dispatch |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | return self.dispatch(request, *args, **kwargs) |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/django/views/generic/base.py", line 70, in view |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | return view_func(*args, **kwargs) |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | response = wrapped_callback(request, *callback_args, **callback_kwargs) |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/django/core/handlers/base.py", line 181, in _get_response |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | response = get_response(request) |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/django/core/handlers/exception.py", line 47, in inner |  
  |   | 2023-09-12 18:34:07.447 | Traceback (most recent call last): |  
  |   | 2023-09-12 18:34:07.447 |   |  
  |   | 2023-09-12 18:34:07.447 | The above exception was the direct cause of the following exception: |  
  |   | 2023-09-12 18:34:07.447 |   |  
  |   | 2023-09-12 18:34:07.447 |   |  
  |   | 2023-09-12 18:34:07.447 | psycopg2.errors.StringDataRightTruncation: value too long for type character varying(100) |  
  |   | 2023-09-12 18:34:07.447 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |  
  |   | 2023-09-12 18:34:07.447 | return self.cursor.execute(sql, params) |  
  |   | 2023-09-12 18:34:07.447 | File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 84, in _execute |  
  |   | 2023-09-12 18:34:07.447 | Traceback (most recent call last): |  
  |   | 2023-09-12 18:34:07.447 | 2023-09-12 10:34:07 source=engine:app google_trace_id=50a15245db9b828e0ab33e8d115dd10a/3838538413005063100 logger=django.request Internal Server Error: /api/internal/v1/complete/slack-install-free/
```

---------

Co-authored-by: Vadim Stepanov <vadimkerr@gmail.com>
2023-09-13 11:53:17 +01:00
Vadim Stepanov
8b2212c7dc
Improve Slack error handling (#3000)
# What this PR does

- Rename `SlackClientWithErrorHandling` to just `SlackClient`
- Add more error classes + improve the way errors are raised based on
the Slack error code
- Add API call retries on Slack server errors (e.g. when Slack returns
`5xx` errors)
- Refactor some methods working with Slack API + add tests

## Which issue(s) this PR fixes

- https://github.com/grafana/oncall-private/issues/1837
- https://github.com/grafana/oncall-private/issues/1840
- https://github.com/grafana/oncall-private/issues/1842

## 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-09-12 09:49:16 +00:00
Joey Orlando
4b0bb86ce4
Notify user when their shift swap request is taken (#2992)
# What this PR does

Closes #2868

**Slack thread message**
<img width="442" alt="Screenshot 2023-09-07 at 15 47 30"
src="https://github.com/grafana/oncall/assets/9406895/f8f39341-4d18-4a43-88be-066993275fcd">

**Push notification**
Clicking on the push notification goes to the SSR detail view

<img width="423" alt="Screenshot 2023-09-07 at 15 48 59"
src="https://github.com/grafana/oncall/assets/9406895/5bb0fbf3-3e55-47e3-bf24-9cb5690dc17c">


## 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-09-07 14:59:54 +00:00
Matias Bordese
bf4d948449
Update slack schedule shift change notification (#2949)
Related to https://github.com/grafana/oncall/issues/2916

Updated notification:

![slack-shift-notification](https://github.com/grafana/oncall/assets/260710/825fda59-6636-44c1-9740-8976e7c109a7)
2023-09-07 13:00:12 +00:00
Vadim Stepanov
0d7352a17b
Fix handling Slack rate limits (#2991)
## Which issue(s) this PR fixes

https://github.com/grafana/oncall-private/issues/2156

## 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-09-07 11:25:29 +00:00
Vadim Stepanov
d90cf0f593
Fix Slack integration leftovers after disconnecting (#2986)
# What this PR does

Improve Slack disconnect cleanup:
- Reset Slack user group for schedules
- Reset Slack user identity for deleted users

## Which issue(s) this PR fixes

https://github.com/grafana/oncall-private/issues/1962

## 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-09-07 08:42:30 +00:00
Vadim Stepanov
31759fdf80
Don't update Slack user groups for deleted organizations (#2985)
# What this PR does

Make sure that Slack user groups are not getting updated for deleted
orgs.
Without this change, there could be issues with backends in multiple
clusters trying to update a single Slack user group after migrating an
org to another cluster (organizations get soft deleted from the original
cluster after migration).

## Which issue(s) this PR fixes

https://github.com/grafana/support-escalations/issues/6936

## 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-09-06 16:02:01 +00:00
Matias Bordese
5b052afb36
Handle slack resolution note errors consistently (#2976) 2023-09-06 12:15:28 +00:00
Joey Orlando
0d30a9ee67
Merge branch 'dev' of github.com:grafana/oncall into dev 2023-09-05 14:32:34 +02:00
Joey Orlando
3f9d392be9
address another slack-sdk issue 2023-09-05 14:32:28 +02:00
Joey Orlando
293eff2325
fix slack-sdk issue (#2969)
<img width="1488" alt="Screenshot 2023-09-05 at 12 59 16"
src="https://github.com/grafana/oncall/assets/9406895/61518425-da47-4363-8400-fc46b043f64f">


[logs](https://ops.grafana-ops.net/explore?panes=%7B%22FZ0%22:%7B%22datasource%22:%22000000193%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22expr%22:%22%7Bcluster%3D~%5C%22%28prod-us-central-0%7Cprod-eu-west-0%7Cops-us-east-0%29%5C%22,%20namespace%3D~%5C%22amixr-%28staging%7Cprod%29%5C%22%7D%20%7C%3D%20%60KeyError%28%27cursor%27%60%22,%22queryType%22:%22range%22,%22datasource%22:%7B%22type%22:%22loki%22,%22uid%22:%22000000193%22%7D,%22editorMode%22:%22code%22%7D%5D,%22range%22:%7B%22from%22:%22now-6h%22,%22to%22:%22now%22%7D%7D%7D&schemaVersion=1&orgId=1)
2023-09-05 13:06:22 +02:00
Joey Orlando
395977d934
fix issue with slack_sdk call update (#2966)
# What this PR does

## 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-09-05 12:25:11 +02:00
Joey Orlando
a9155130df
update slack_sdk dependency to latest version (#2947)
# What this PR does

- update `slackclient` dependency to latest version. The version we were
using was 5 years old 😲
- first followed the v2 migration guide
[here](https://github.com/slackapi/python-slack-sdk/wiki/Migrating-to-2.x)
followed by the v3 migration guide
[here](https://slack.dev/python-slack-sdk/v3-migration/). The main
changes were:
    - The PyPI project was renamed from `slackclient` to `slack_sdk`
- it is discouraged/harder to call `api_call` and encouraged to call the
helper methods (ex. `chat_postMessage`;
[note](https://github.com/slackapi/python-slack-sdk/wiki/Migrating-to-2.x#web-client-api-changes)
in migration guide docs)
- In 1.x, a failed api call would return the error payload to you and
have you handle the error. In 2.x, a failed api call will throw an
exception. To handle this in your code, you will have to wrap api calls
with a try except block. Since we overload `WebClient.api_call` this was
an easy change and only required a one line change
- remove `apps.slack.slack_client.slack_server.SlackClientServer` class.
The new version of `slack_sdk` handles the case that we needed to
overload for in the first place.
- merged `apps/slack/slack_client/slack_client.py` and
`apps/slack/slack_client/exceptions.py` into `apps/slack/client.py`

## 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-09-05 11:31:59 +02:00
Vadim Stepanov
a2851d3f81
Refactor AlertGroup.slack_message (#2957)
# What this PR does

Refactors the foreign key relationship between `AlertGroup` and
`SlackMessage` models (see
https://github.com/grafana/oncall-private/issues/1867 for more info).

## Which issue(s) this PR fixes

https://github.com/grafana/oncall-private/issues/1867

## 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-09-04 18:03:18 +00:00
Vadim Stepanov
f7bdcf3d36
Fix SlackMessage._alert_group issue (#2945)
# What this PR does

Fixes  https://github.com/grafana/oncall-private/issues/2091

## 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-09-01 14:47:10 +00:00
Joey Orlando
1d089aa7a3
fix IntegrityErrors occuring when creating ResolutionNoteSlackMessage objects (#2933)
# What this PR does

## Which issue(s) this PR fixes

Closes https://github.com/grafana/oncall-private/issues/1822

## 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-09-01 08:14:59 +00:00
Joey Orlando
73da83274a
Update Shift Swap Request Slack message formatting (#2918)
# What this PR does

Updates Shift Swap Request Slack message formatting to be consistent
with UI mockups:

**New Request**
![Screenshot 2023-08-30 at 12 18
54](https://github.com/grafana/oncall/assets/9406895/712a13e2-b768-4be6-b066-c5daa98446eb)

**Accepted**
![Screenshot 2023-08-30 at 12 19
41](https://github.com/grafana/oncall/assets/9406895/84d14adf-bb48-4ba8-bee2-eb7931ef2d55)


**Deleted**
![Screenshot 2023-08-30 at 12 19
01](https://github.com/grafana/oncall/assets/9406895/9bda06c8-5ce7-405b-9303-b160eac4d635)


## 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-09-01 07:53:27 +02:00
Matias Bordese
0e75be96df
Fix slack schedule notification settings dialog (#2902)
Fixes https://github.com/grafana/oncall/issues/2647
2023-08-29 15:07:02 +00:00
Joey Orlando
c811a2ad15
Address bug when taking a Shift Swap Request and the Slack message is not updated (#2886)
# What this PR does

Address bug when a Shift Swap Request is accepted either via the web or
mobile UI, and the Slack message is not
updated to reflect the latest state.

## 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-28 11:55:17 +02:00
Joey Orlando
d5e1e9ade2
add interactive api endpoint integration test
for accepting shift swap requests
2023-08-28 10:02:55 +02:00
Vadim Stepanov
93b3521542
Shift swap request Slack follow-ups (#2798)
# What this PR does

Add Slack follow-up messages for shift swap requests:

<img width="377" alt="Screenshot 2023-08-15 at 20 19 49"
src="https://github.com/grafana/oncall/assets/20116910/14053838-c8f2-49f6-81cd-383d3fbc061c">

## Which issue(s) this PR fixes

https://github.com/grafana/oncall/issues/2679

## 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-16 08:38:07 +00:00
Vadim Stepanov
d5defd10d2
Add more logging for SlackUserGroup.update_oncall_members (#2741)
# What this PR does

Adds more logging for `SlackUserGroup.update_oncall_members` so it's
easier to debug.

## Which issue(s) this PR fixes

Related to https://github.com/grafana/support-escalations/issues/6936

## 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-03 15:25:37 +01:00
Vadim Stepanov
6f3c62e05f
Add stack slug to organization options for direct paging (#2743)
# What this PR does

Adds stack slug to organization options for `/escalate` (a single
Grafana org might have multiple stacks).

<img width="514" alt="Screenshot 2023-08-03 at 14 24 58"
src="https://github.com/grafana/oncall/assets/20116910/4a43867d-6f6e-4050-a30e-204aeaded663">

## 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-03 14:36:07 +01:00
Yulya Artyukhina
0494afac85
Update schedule slack notifications (#2710)
# What this PR does

Update schedule slack notifications to use schedule final events instead
of getting events from iCal

## 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-03 12:38:01 +00:00
Joey Orlando
d6140cbe8d
Re-enable a few mypy rules + fix existing errors (#2725)
# What this PR does

Related to https://github.com/grafana/oncall/issues/2392

- Re-enable the following `mypy` rules + fix their pre-existing errors:
  - `no-redef`
  - `valid-type`
  - `var-annotated`
- Add stronger return typing to the `GrafanaAPIClient` by use of
generics + add some links to documentation in the method docstrings

## 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-03 09:43:03 +00:00
Joey Orlando
33c5e89299
remove unused dynamic settings (#2735)
# What this PR does

While working on https://github.com/grafana/oncall/pull/2734 I removed a
block of code that was the last reference to a dynamic setting
(`enabled_web_schedules_orgs`).

That led me to see which dynamic settings we still have references to
(at the database level), and create this cleanup migration for
deprecated dynamic settings.

## 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-03 05:11:52 -04:00
Joey Orlando
225e4e4882
remove django admin panel (#2731)
# What this PR does

Disables the Django admin panel + removes the URLs associated with it

**NOTE**: this doesn't affect things like `python manage.py
createsuperuser` which are still needed for a few things

## 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-02 14:26:50 -04:00
Joey Orlando
2576954b51
add shifts property to shift swap request response schema + finalize slack message layout (#2712)
# What this PR does

- drop `GET /api/internal/v1/shift_swaps/<id>/shifts` endpoint in favour
of adding a `shifts` property to the response schema for all shift swap
endpoints (expect `GET /api/internal/v1/shift_swaps` (ie. list all))
- Update the Slack message layout:

<img width="590" alt="Screenshot 2023-08-01 at 17 28 44"
src="https://github.com/grafana/oncall/assets/9406895/84a51614-5dd6-48ec-ae81-fef4bc32fec9">

**Note**: about the highlighted lines. This is a small issue w/ the
`ShiftSwapRequest.shifts` method. @matiasb is already helping out here 🙏

**Other stuff**
- adds some type hints related to the code I was working around with
- slightly refactor `apps.slack.utils.format_datetime_to_slack` to make
it more generic for the use case in this 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-01 14:21:02 -04:00
Joey Orlando
f77a54b518
Shift Swap Requests in Slack + improve typing for Slack django app (#2653)
# What this PR does

**Shift Swap Requests**

https://www.loom.com/share/860c3337b338412cbd2ac4024260f3e8?sid=3d91b558-b4de-4351-8b45-8a99b7302346

**Other**
- Drastically improve the typing in the `slack` Django app, and several
other models/functions that were consumed by logic within the `slack`
Django app (ex. setting `RelatedManager` type hints on various models)
https://www.loom.com/share/da6b9984519c48d59a45d3c93c08d7dc

## 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-07-28 15:11:38 +00:00
Vadim Stepanov
f977f9faee
Minor formatting changes (#2641)
# What this PR does

- Updates `black` and `flake8` to latest
- Removes `F541` from flake8 ignore (`F541 f-string is missing
placeholders`)
- Enables ["float to top"
option](https://pycqa.github.io/isort/docs/configuration/options.html#float-to-top)
for `isort`
2023-07-26 14:45:44 +01:00
Vadim Stepanov
faa7099297
Direct paging: page if acked or silenced, show warning when resolved (#2639)
# What this PR does

The current implementation of the direct paging feature doesn't page
additional responders if the alert group is acknowledged, silenced, or
resolved, and doesn't show any warnings for such cases.
This PR makes so that adding responders for silenced & acknowledged
alert groups actually pages the selected user / schedule. For resolved
alert groups, a warning message will be shown both in web UI and Slack.

## Which issue(s) this PR fixes

Related to https://github.com/grafana/oncall/issues/2442

## 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-07-26 13:25:26 +01:00
Vadim Stepanov
b2f4ffb98a
apps.get_model -> import (#2619)
# What this PR does

Remove
[`apps.get_model`](https://docs.djangoproject.com/en/3.2/ref/applications/#django.apps.apps.get_model)
invocations and use inline `import` statements in places where models
are imported within functions/methods to avoid circular imports.

I believe `import` statements are more appropriate for most use cases as
they allow for better static code analysis & formatting, and solve the
issue of circular imports without being unnecessarily dynamic as
`apps.get_model`. With `import` statements, it's possible to:

- Jump to model definitions in most IDEs
- Automatically sort inline imports with `isort`
- Find import errors faster/easier (most IDEs highlight broken imports)
- Have more consistency across regular & inline imports when importing
models

This PR also adds a flake8 rule to ban imports of `django.apps.apps`, so
it's harder to use `apps.get_model` by mistake (it's possible to ignore
this rule by using `# noqa: I251`). The rule is not enforced on
directories with migration files, because `apps.get_model` is often used
to get a historical state of a model, which is useful when writing
migrations ([see this SO answer for more
details](https://stackoverflow.com/a/37769213)). So `apps.get_model` is
considered OK in migrations (even necessary in some cases).

## 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-07-25 09:43:23 +00:00
Vadim Stepanov
ed6389ca8f
Update direct paging docs (#2600)
# What this PR does

Updates public docs on direct paging after introducing numerous changes
to the feature.

## Preview


https://github.com/grafana/oncall/assets/20116910/f141e8b1-ac2c-455c-81f8-9c62c4c75234


## 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-07-20 15:57:00 +01:00
Vadim Stepanov
fa1ca0dfa6
Fix Slack direct paging issue when there are >100 schedules (#2594)
# What this PR does

Fix Slack direct paging issue when there are >100 schedules.

## 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-07-19 13:52:05 +00:00
Yulya Artyukhina
adfb496a81
Fix slack channels sync (#2571)
# What this PR does
- Fixes issue with slack channels sync periodic tasks when we get slack
rate limit exception.
- Adds check for active task id to avoid starting multiple tasks for one
slack team.

Collecting channels for slack for some teams causes rate limit
exception, which causes the task to restart and start collecting slack
channels from the beginning. This PR adds new paginated api call and
refactors the slack channel sync task to continue collect data after
rate limit from the step before it was raised using `cursor` value from
the slack response.


## Checklist

- [x] Unit, integration, and e2e (if applicable) tests updated
- [ ] 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)

---------

Co-authored-by: Joey Orlando <joey.orlando@grafana.com>
2023-07-19 07:17:21 +00:00
Joey Orlando
9cc74e5b67
remove references to AlertGroup.is_archived and AlertGroup.unarchived_objects (#2524)
# What this PR does

This is a follow up to #2502 which started to remove logic to
"archiving" alert groups. This PR:
- removes all references to `AlertGroup.is_archived` and marks the
column as deprecated. We will remove it in the next release
- removes the `AlertGroup.unarchived_objects` `Manager`
- renames the `AlertGroup.all_objects` `Manager` to `AlertGroup.objects`

## Checklist

- [x] Unit, integration, and e2e (if applicable) tests updated
- [ ] 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-07-18 11:48:34 +00:00
Vadim Stepanov
56743857ee
Update Slack "invite" feature to use direct paging (#2562)
# What this PR does

Refactors the "invite" functionality in Slack to use direct paging and
be more consistent with the web UI and `/escalate` Slack command.

## Screenshots

### Alert group buttons

Before:

<img width="609" alt="Screenshot 2023-07-17 at 22 40 47"
src="https://github.com/grafana/oncall/assets/20116910/68fad5a4-5011-4d74-b1c7-362bdb4f8cf0">


After (replace "Invite..." dropdown with "Responders" button, swap it
with the silence button):
<img width="587" alt="Screenshot 2023-07-17 at 22 37 19"
src="https://github.com/grafana/oncall/assets/20116910/50b42057-f46b-4558-ab1c-56c34a15af5e">


### What happens when clicking on "Responders"

The following modal opens up with a list of currently paged users and
inputs to page more users/schedules:

<img width="514" alt="Screenshot 2023-07-17 at 22 37 52"
src="https://github.com/grafana/oncall/assets/20116910/70bd2853-d459-4343-8b25-8519ac0098f7">

This is supposed to be the Slack equivalent of this part of the web UI:

<img width="601" alt="Screenshot 2023-07-17 at 22 47 17"
src="https://github.com/grafana/oncall/assets/20116910/101e1229-a5c4-404f-8388-eceee3e4820f">


## Which issue(s) this PR fixes

https://github.com/grafana/oncall/issues/2336

## 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-07-18 08:36:11 +00:00
Vadim Stepanov
69bafb61f1
Direct paging improvements (#2537)
# What this PR does

- Deprecates `/oncall` Slack command in favour of `/esalate` (direct
paging) + fixes a regression bug in both commands
- Unifies direct paging UX across Slack & Web UI (or at least makes an
attempt to make things more similar). Kudos to @iskhakov for all the
great work on this recently!
- A bunch of minor changes that hopefully make direct paging more usable
- TODO: documentation updates will be added in a separate PR

## Screenshots

### No issues scenario

Slack:

<img width="522" alt="Screenshot 2023-07-14 at 23 53 11"
src="https://github.com/grafana/oncall/assets/20116910/ec15a18f-d817-4177-b1f2-6b89d79bb361">


Web UI: 

<img width="1172" alt="Screenshot 2023-07-14 at 23 52 25"
src="https://github.com/grafana/oncall/assets/20116910/813f967c-2fdd-4868-9287-487dbfa7cea6">


### Not configured scenario

Slack:

<img width="519" alt="Screenshot 2023-07-14 at 23 45 22"
src="https://github.com/grafana/oncall/assets/20116910/932fa05c-81ea-42ca-be80-41b05f767d3e">

Web UI:

<img width="1172" alt="Screenshot 2023-07-14 at 23 47 31"
src="https://github.com/grafana/oncall/assets/20116910/6bcb07e4-2e50-4120-9fac-be8b0277e181">

### `/oncall` deprecation warning

<img width="521" alt="Screenshot 2023-07-17 at 10 31 56"
src="https://github.com/grafana/oncall/assets/20116910/4ff28337-1693-4af0-81d9-9eda90099c1b">


## Which issue(s) this PR fixes

https://github.com/grafana/oncall/issues/2442

## 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-07-17 14:21:56 +01:00
Joey Orlando
d24dc4b630
remove organization maintenance mode + fix integration maintenance mode (#2511) 2023-07-12 16:41:44 -04:00
Joey Orlando
385e1377d6
remove deprecated backend code (#2502)
# What this PR does

See more details comments alongside the code.

Regarding frontend changes, the main changes in this PR are to remove
unused fields on the `Team` interface + unused methods on the `Team`
model.

## Checklist

- [x] Unit, integration, and e2e (if applicable) tests updated
- [ ] Documentation added (or `pr:no public docs` PR label added if not
required) (N/A)
- [ ] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not
required) (N/A)
2023-07-12 02:07:45 -04:00
Vadim Stepanov
b2fc9635bf
Bring back /oncall Slack command (#2500)
Reverts grafana/oncall#2499

`/oncall` command was removed by mistake.
2023-07-11 14:43:06 +01:00
Vadim Stepanov
028cb7d7fc
Remove ability to create alert groups via Slack message shortcut (#2499)
# What this PR does

Removes an ability to create alert groups via Slack message shortcut
(three dots menu near to a message), since this feature is outdated and
not documented anywhere.

## Which issue(s) this PR fixes

Related to https://github.com/grafana/oncall/issues/2442

## 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-07-11 13:09:02 +00:00
Joey Orlando
01b1be85af
fix mypy return errors (#2408)
# What this PR does

Fix the following `return` `mypy` errors (related to #2392):

```bash
❯ mypy .
apps/telegram/updates/update_manager.py:36: error: Missing return statement  [return]
apps/slack/scenarios/step_mixins.py:109: error: Missing return statement  [return]
apps/mobile_app/tasks.py:368: error: Missing return statement  [return]
apps/telegram/updates/update_handlers/button_press.py:48: error: Missing return statement  [return]
apps/twilioapp/phone_provider.py:28: error: Missing return statement  [return]
apps/twilioapp/phone_provider.py:61: error: Missing return statement  [return]
Found 6 errors in 5 files (checked 595 source files)
```

## Checklist

- [ ] Unit, integration, and e2e (if applicable) tests updated
- [ ] Documentation added (or `pr:no public docs` PR label added if not
required)
- [ ] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not
required)
2023-07-05 11:36:59 +00:00
Vadim Stepanov
aa2bb81519
Simplify SlackEventApiEndpointView methods (#2384)
# What this PR does

Simplifies `_get_organization_from_payload` and
`_get_slack_team_identity_from_payload` methods on
`SlackEventApiEndpointView`, so it's (hopefully) easier to grasp.

## 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-06-29 16:23:33 +00:00
Joey Orlando
cc20c9dfdd
re-enable mypy GitHub Actions CI job (#2390)
# What this PR does

```bash
❯ mypy .
Success: no issues found in 595 source files
```

- re-enable the mypy CI check
- fixes all `django-manager-missing` mypy errors
- disable all other rules currently giving mypy errors
- changing the approach here. rather than enforcing that backend
contributors fix >= 1 `mypy` error on their PR, lets simply disable all
the rules that're currently returning errors and slowly re-enable these
one at a time #2392

## Checklist

- [ ] Unit, integration, and e2e (if applicable) tests updated (N/A)
- [ ] Documentation added (or `pr:no public docs` PR label added if not
required) (N/A)
- [ ] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not
required) (N/A)
2023-06-29 14:01:52 +00:00
Vadim Stepanov
3ebfd9c8b2
Remove outdated Slack functionality to create alerts (#2383)
# What this PR does

There's an outdated Slack handler that creates alerts when a file is
shared in a channel. I can't remember why it was introduced in the first
place, but I'm pretty sure that it's deprecated a long time ago, and
this feature is not documented anywhere. The PR also removes
`AlertReceiveChannel.integration_slack_channel_id` as it's no longer
used.

## 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-06-29 10:09:02 +00:00
Joey Orlando
75028d0427
continue addressing mypy violations (#2170)
# What this PR does

See #2173 

Also, closes #2187 . All of the new files under `type_stubs/icalendar`
were autogenerated by running:

```bash
stubgen -p icalendar -o type_stubs
```

## Checklist

- [ ] Unit, integration, and e2e (if applicable) tests updated
- [ ] Documentation added (or `pr:no public docs` PR label added if not
required)
- [ ] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not
required)
2023-06-27 10:23:08 +00:00
Joey Orlando
90e0b21d3e
remove SlackActionRecord model/table (#2201)
# What this PR does

Closes #2169 

## Checklist

- [x] Unit, integration, and e2e (if applicable) tests updated
- [ ] 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-06-13 10:56:06 +00:00
Joey Orlando
9dde1805aa
add mypy static type checker to backend codebase (#2151)
# What this PR does

- Adds [`mypy` static type checking](https://mypy-lang.org/) to our CI
pipeline. Currently there is still a **ton** of errors being returned by
the tool, as we'll need to fix pre-existing errors. I think we can
slowly chip away at these errors in small PRs, doing them all in one
large PR is likely very risky.
- Also, this PR starts chipping away at one of the main type errors that
we have which is accessing the `datetime` class (from the `datetime`
library) or `timedelta` function on the `django.utils.timezone` module.
Basically we should be instead accessing these two objects from the
native `datetime` module. This makes sense because the [`__all__`
attribute](https://github.com/django/django/blob/main/django/utils/timezone.py#L14-L30)
in `django.utils.timezone` does not re-export `datetime` or `timedelta`.
- splits `engine` dependencies out into `requirements.txt` and
`requirements-dev.txt`

## Checklist

- [ ] Unit, integration, and e2e (if applicable) tests updated (N/A)
- [ ] Documentation added (or `pr:no public docs` PR label added if not
required) (N/A)
- [ ] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not
required) (N/A)
2023-06-12 12:50:33 -04:00