Add internal API fields for the mobile app (#910)

* add permalinks list to internal API alertgroup view

* add user's name and full avatar URL to the user view

* make avatar_full_url a property

* fix tests

* fix user connection criteria
This commit is contained in:
Vadim Stepanov 2022-11-28 15:52:31 +00:00 committed by GitHub
parent 54d14d1025
commit dc6fcf5c05
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 30 additions and 14 deletions

View file

@ -1,7 +1,6 @@
import logging
import typing
from collections import namedtuple
from typing import Optional
from typing import Optional, TypedDict
from urllib.parse import urljoin
from uuid import uuid1
@ -46,8 +45,9 @@ def generate_public_primary_key_for_alert_group():
return new_public_primary_key
class Permalinks(typing.TypedDict):
slack: str
class Permalinks(TypedDict):
slack: Optional[str]
telegram: Optional[str]
class AlertGroupQuerySet(models.QuerySet):
@ -401,12 +401,12 @@ class AlertGroup(AlertGroupSlackRenderingMixin, EscalationSnapshotMixin, models.
raise NotImplementedError
@property
def slack_permalink(self):
def slack_permalink(self) -> Optional[str]:
if self.slack_message is not None:
return self.slack_message.permalink
@property
def telegram_permalink(self) -> typing.Optional[str]:
def telegram_permalink(self) -> Optional[str]:
"""
This property will attempt to access an attribute, `prefetched_telegram_messages`, representing a list of
prefetched telegram messages. If this attribute does not exist, it falls back to performing a query.

View file

@ -132,7 +132,8 @@ class AlertGroupSerializer(AlertGroupListSerializer):
fields = AlertGroupListSerializer.Meta.fields + [
"alerts",
"render_after_resolve_report_json",
"slack_permalink",
"slack_permalink", # TODO: make plugin frontend use "permalinks" field to get Slack link
"permalinks",
"last_alert_at",
]

View file

@ -36,7 +36,7 @@ class UserSerializer(DynamicFieldsModelSerializer, EagerLoadingMixin):
timezone = serializers.CharField(allow_null=True, required=False)
avatar = serializers.URLField(source="avatar_url", read_only=True)
avatar_full = serializers.URLField(source="avatar_full_url", read_only=True)
permissions = serializers.SerializerMethodField()
notification_chain_verbal = serializers.SerializerMethodField()
cloud_connection_status = serializers.SerializerMethodField()
@ -51,8 +51,10 @@ class UserSerializer(DynamicFieldsModelSerializer, EagerLoadingMixin):
"current_team",
"email",
"username",
"name",
"role",
"avatar",
"avatar_full",
"timezone",
"working_hours",
"unverified_phone_number",
@ -68,6 +70,7 @@ class UserSerializer(DynamicFieldsModelSerializer, EagerLoadingMixin):
read_only_fields = [
"email",
"username",
"name",
"role",
"verified_phone_number",
]

View file

@ -68,6 +68,7 @@ def test_update_user_cant_change_email_and_username(
"email": admin.email,
"hide_phone_number": False,
"username": admin.username,
"name": admin.name,
"role": admin.role,
"timezone": None,
"working_hours": default_working_hours(),
@ -84,6 +85,7 @@ def test_update_user_cant_change_email_and_username(
"notification_chain_verbal": {"default": "", "important": ""},
"slack_user_identity": None,
"avatar": admin.avatar_url,
"avatar_full": admin.avatar_full_url,
}
response = client.put(url, data, format="json", **make_user_auth_headers(admin, token))
assert response.status_code == status.HTTP_200_OK
@ -117,6 +119,7 @@ def test_list_users(
"email": admin.email,
"hide_phone_number": False,
"username": admin.username,
"name": admin.name,
"role": admin.role,
"timezone": None,
"working_hours": default_working_hours(),
@ -132,6 +135,7 @@ def test_list_users(
"notification_chain_verbal": {"default": "", "important": ""},
"slack_user_identity": None,
"avatar": admin.avatar_url,
"avatar_full": admin.avatar_full_url,
"cloud_connection_status": 0,
},
{
@ -141,6 +145,7 @@ def test_list_users(
"email": editor.email,
"hide_phone_number": False,
"username": editor.username,
"name": editor.name,
"role": editor.role,
"timezone": None,
"working_hours": default_working_hours(),
@ -156,6 +161,7 @@ def test_list_users(
"notification_chain_verbal": {"default": "", "important": ""},
"slack_user_identity": None,
"avatar": editor.avatar_url,
"avatar_full": editor.avatar_full_url,
"cloud_connection_status": 0,
},
],

View file

@ -1,5 +1,3 @@
from push_notifications.models import APNSDevice
from apps.base.messaging import BaseMessagingBackend
from apps.mobile_app.tasks import notify_user_async
@ -28,8 +26,9 @@ class MobileAppBackend(BaseMessagingBackend):
token.delete()
def serialize_user(self, user):
# TODO: add Android support using GCMDevice
return {"connected": APNSDevice.objects.filter(user_id=user.pk).exists()}
from apps.mobile_app.models import MobileAppAuthToken
return {"connected": MobileAppAuthToken.objects.filter(user=user).exists()}
def notify_user(self, user, alert_group, notification_policy, critical=False):
notify_user_async.delay(

View file

@ -1,4 +1,5 @@
import logging
from urllib.parse import urljoin
from django.apps import apps
from django.conf import settings
@ -161,6 +162,10 @@ class User(models.Model):
def is_authenticated(self):
return True
@property
def avatar_full_url(self):
return urljoin(self.organization.grafana_url, self.avatar_url)
@property
def verified_phone_number(self):
"""

View file

@ -10,7 +10,7 @@ from apps.user_management.sync import cleanup_organization, sync_organization
@pytest.mark.django_db
def test_sync_users_for_organization(make_organization, make_user_for_organization):
organization = make_organization()
organization = make_organization(grafana_url="https://test.test")
users = tuple(make_user_for_organization(organization, user_id=user_id) for user_id in (1, 2))
api_users = tuple(
@ -20,7 +20,7 @@ def test_sync_users_for_organization(make_organization, make_user_for_organizati
"name": "Test",
"login": "test",
"role": "admin",
"avatarUrl": "test.test/test",
"avatarUrl": "/test/1234",
}
for user_id in (2, 3)
)
@ -37,12 +37,14 @@ def test_sync_users_for_organization(make_organization, make_user_for_organizati
assert updated_user is not None
assert updated_user.name == api_users[0]["name"]
assert updated_user.email == api_users[0]["email"]
assert updated_user.avatar_full_url == "https://test.test/test/1234"
# check that missing users are created
created_user = organization.users.filter(user_id=api_users[1]["userId"]).first()
assert created_user is not None
assert created_user.user_id == api_users[1]["userId"]
assert created_user.name == api_users[1]["name"]
assert created_user.avatar_full_url == "https://test.test/test/1234"
@pytest.mark.django_db