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:
parent
54d14d1025
commit
dc6fcf5c05
7 changed files with 30 additions and 14 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue