Add CloudUsersView and CloudUserView
This commit is contained in:
parent
5e494531eb
commit
75f319fb5d
9 changed files with 125 additions and 20 deletions
|
|
@ -4,11 +4,13 @@ from rest_framework.response import Response
|
|||
from rest_framework.views import APIView
|
||||
|
||||
from apps.auth_token.auth import PluginAuthentication
|
||||
from apps.base.utils import live_settings
|
||||
|
||||
FEATURE_SLACK = "slack"
|
||||
FEATURE_TELEGRAM = "telegram"
|
||||
FEATURE_LIVE_SETTINGS = "live_settings"
|
||||
MOBILE_APP_PUSH_NOTIFICATIONS = "mobile_app"
|
||||
FEATURE_GRAFANA_CLOUD_NOTIFICATIONS = "grafana_cloud_notifications"
|
||||
|
||||
|
||||
class FeaturesAPIView(APIView):
|
||||
|
|
@ -34,6 +36,9 @@ class FeaturesAPIView(APIView):
|
|||
if settings.FEATURE_LIVE_SETTINGS_ENABLED:
|
||||
enabled_features.append(FEATURE_LIVE_SETTINGS)
|
||||
|
||||
if live_settings.GRAFANA_CLOUD_NOTIFICATIONS_ENABLED:
|
||||
enabled_features.append(FEATURE_GRAFANA_CLOUD_NOTIFICATIONS)
|
||||
|
||||
if settings.MOBILE_APP_PUSH_NOTIFICATIONS_ENABLED:
|
||||
DynamicSetting = apps.get_model("base", "DynamicSetting")
|
||||
mobile_app_settings = DynamicSetting.objects.get_or_create(
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
import json
|
||||
import re
|
||||
from urllib.parse import urljoin
|
||||
|
||||
import requests.exceptions
|
||||
from django.apps import apps
|
||||
from django.conf import settings
|
||||
from python_http_client import UnauthorizedError
|
||||
from sendgrid import SendGridAPIClient
|
||||
from telegram import Bot
|
||||
|
|
@ -94,6 +97,20 @@ class LiveSettingValidator:
|
|||
except Exception as e:
|
||||
return f"Telegram error: {str(e)}"
|
||||
|
||||
@classmethod
|
||||
def _check_grafana_cloud_oncall_token(cls, grafan_oncall_token):
|
||||
try:
|
||||
info_url = urljoin(settings.GRAFANA_CLOUD_ONCALL_API_URL, "api/v1/info/")
|
||||
r = requests.get(info_url, headers={"AUTHORIZATION": grafan_oncall_token}, timeout=5)
|
||||
if r.status_code == 200:
|
||||
return
|
||||
elif r.status_code == 403:
|
||||
return f"Invalid token."
|
||||
else:
|
||||
return f"Non-200 HTTP code. Got {r.status_code}"
|
||||
except requests.exceptions.RequestException as e:
|
||||
return f"Error {str(e)}"
|
||||
|
||||
@staticmethod
|
||||
def _is_email_valid(email):
|
||||
return re.match(r"^[^@]+@[^@]+\.[^@]+$", email)
|
||||
|
|
|
|||
|
|
@ -1 +1,6 @@
|
|||
CLOUD_URL = "https://a-prod-us-central-0.grafana.net/"
|
||||
|
||||
CLOUD_NOT_SYNCED = 0
|
||||
CLOUD_SYNCED_USER_NOT_FOUND = 1
|
||||
CLOUD_SYNCED_PHONE_NOT_VERIFIED = 2
|
||||
CLOUD_SYNCED_PHONE_VERIFIED = 3
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from .cloud_organization_connector import CloudOrganizationConnector # noqa: F401
|
||||
from .cloud_users import CloudUserIdentity # noqa: F401
|
||||
from .cloud_user_identity import CloudUserIdentity # noqa: F401
|
||||
from .heartbeat import CloudHeartbeat # noqa: F401
|
||||
from .oss_installation import OssInstallation # noqa: F401
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ from django.db import models
|
|||
|
||||
from apps.base.utils import live_settings
|
||||
from apps.oss_installation.constants import CLOUD_URL
|
||||
from apps.oss_installation.models.cloud_users import CloudUserIdentity
|
||||
from apps.oss_installation.models.cloud_user_identity import CloudUserIdentity
|
||||
from apps.user_management.models import User
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -59,7 +59,7 @@ class CloudOrganizationConnector(models.Model):
|
|||
users_url = urljoin(CLOUD_URL, "api/v1/users")
|
||||
|
||||
existing_cloud_identities = list(CloudUserIdentity.objects.filter(organization=self.organization))
|
||||
existing_cloud_ids = list(map(lambda u: u.cloud_id, existing_cloud_identities))
|
||||
existing_cloud_ids = list(map(lambda identity: identity.cloud_id, existing_cloud_identities))
|
||||
|
||||
fetch_next_page = True
|
||||
page = 1
|
||||
|
|
@ -102,7 +102,6 @@ class CloudOrganizationConnector(models.Model):
|
|||
i.email = cloud_users_identities_to_update[i.cloud_id]["email"]
|
||||
i.phone_number_verified = cloud_users_identities_to_update[i.cloud_id]["is_phone_number_verified"]
|
||||
|
||||
# TODO: Grafana CN: check if data validation needed.
|
||||
CloudUserIdentity.objects.bulk_create(cloud_users_identities_to_create, batch_size=1000)
|
||||
CloudUserIdentity.objects.bulk_update(
|
||||
existing_cloud_identities, ["email", "phone_number_verified"], batch_size=1000
|
||||
|
|
|
|||
|
|
@ -1,8 +1,20 @@
|
|||
from django.urls import path
|
||||
|
||||
from common.api_helpers.optional_slash_router import optional_slash_path
|
||||
|
||||
from .views import CloudHeartbeatStatusView, CloudUsersView
|
||||
from .views.cloud_user import CloudUserView
|
||||
|
||||
urlpatterns = [
|
||||
optional_slash_path("cloud_heartbeat_status", CloudHeartbeatStatusView.as_view(), name="cloud_heartbeat_status"),
|
||||
optional_slash_path("cloud_users", CloudUsersView.as_view(), name="cloud_users"),
|
||||
optional_slash_path("cloud_users", CloudUsersView.as_view(), name="cloud-users-list"),
|
||||
path(
|
||||
"cloud_users/<str:pk>",
|
||||
CloudUserView.as_view(
|
||||
{
|
||||
"get": "retrieve",
|
||||
}
|
||||
),
|
||||
name="cloud-user-detail",
|
||||
),
|
||||
]
|
||||
|
|
|
|||
61
engine/apps/oss_installation/views/cloud_user.py
Normal file
61
engine/apps/oss_installation/views/cloud_user.py
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
from urllib.parse import urljoin
|
||||
|
||||
from rest_framework import mixins, serializers, viewsets
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
|
||||
import apps.oss_installation.constants as cloud_constants
|
||||
from apps.api.permissions import ActionPermission, IsOwnerOrAdmin
|
||||
from apps.auth_token.auth import PluginAuthentication
|
||||
from apps.oss_installation.models import CloudOrganizationConnector, CloudUserIdentity
|
||||
from apps.user_management.models import User
|
||||
from common.api_helpers.mixins import PublicPrimaryKeyMixin
|
||||
|
||||
|
||||
class CloudUserSerializer(serializers.ModelSerializer):
|
||||
cloud_data = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ["sync_data"]
|
||||
|
||||
def get_cloud_data(self, obj):
|
||||
link = None
|
||||
status = cloud_constants.CLOUD_NOT_SYNCED
|
||||
connector = CloudOrganizationConnector.objects.filter(
|
||||
organization=self.context["request"].auth.organization
|
||||
).first()
|
||||
if connector is not None:
|
||||
cloud_user_identity = CloudUserIdentity.objects.filter(email=obj.email).first()
|
||||
if cloud_user_identity is None:
|
||||
status = cloud_constants.CLOUD_SYNCED_USER_NOT_FOUND
|
||||
link = connector.cloud_url
|
||||
elif not cloud_user_identity.phone_number_verified:
|
||||
status = cloud_constants.CLOUD_SYNCED_USER_NOT_FOUND
|
||||
link = urljoin(
|
||||
connector.cloud_url, f"a/grafana-oncall-app/?page=users&p=1&id={cloud_user_identity.cloud_id}"
|
||||
)
|
||||
else:
|
||||
status = cloud_constants.CLOUD_SYNCED_PHONE_VERIFIED
|
||||
link = urljoin(
|
||||
connector.cloud_url, f"a/grafana-oncall-app/?page=users&p=1&id={cloud_user_identity.cloud_id}"
|
||||
)
|
||||
cloud_data = {"status": status, "link": link}
|
||||
return cloud_data
|
||||
|
||||
|
||||
class CloudUserView(
|
||||
PublicPrimaryKeyMixin,
|
||||
mixins.RetrieveModelMixin,
|
||||
viewsets.GenericViewSet,
|
||||
):
|
||||
authentication_classes = (PluginAuthentication,)
|
||||
permission_classes = (IsAuthenticated, ActionPermission)
|
||||
|
||||
action_object_permissions = {
|
||||
IsOwnerOrAdmin: ("retrieve",),
|
||||
}
|
||||
serializer_class = CloudUserSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = User.objects.filter(organization=self.request.user.organization)
|
||||
return queryset
|
||||
|
|
@ -3,6 +3,8 @@ from urllib.parse import urljoin
|
|||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.views import APIView
|
||||
|
||||
import apps.oss_installation.constants as cloud_constants
|
||||
from apps.api.permissions import IsAdmin
|
||||
from apps.auth_token.auth import PluginAuthentication
|
||||
from apps.oss_installation.models import CloudOrganizationConnector, CloudUserIdentity
|
||||
from apps.user_management.models import User
|
||||
|
|
@ -11,8 +13,7 @@ from common.api_helpers.paginators import HundredPageSizePaginator
|
|||
|
||||
class CloudUsersView(HundredPageSizePaginator, APIView):
|
||||
authentication_classes = (PluginAuthentication,)
|
||||
# TODO: Grafana CN - permissions, ratelimit
|
||||
permission_classes = (IsAuthenticated,)
|
||||
permission_classes = (IsAuthenticated, IsAdmin)
|
||||
|
||||
def get(self, request):
|
||||
queryset = User.objects.filter(organization=self.request.user.organization)
|
||||
|
|
@ -31,23 +32,28 @@ class CloudUsersView(HundredPageSizePaginator, APIView):
|
|||
response = []
|
||||
|
||||
connector = CloudOrganizationConnector.objects.first()
|
||||
|
||||
for user in results:
|
||||
cloud_identity = cloud_identities.get(user.email, None)
|
||||
link = None
|
||||
status = 0
|
||||
if cloud_identity:
|
||||
status = 1
|
||||
is_phone_verified = cloud_identity.phone_number_verified
|
||||
if is_phone_verified:
|
||||
status = 2
|
||||
link = urljoin(
|
||||
connector.cloud_url, f"a/grafana-oncall-app/?page=users&p=1&id={cloud_identity.cloud_id}"
|
||||
)
|
||||
status = cloud_constants.CLOUD_NOT_SYNCED
|
||||
if connector is not None:
|
||||
status = cloud_constants.CLOUD_SYNCED_USER_NOT_FOUND
|
||||
cloud_identity = cloud_identities.get(user.email, None)
|
||||
if cloud_identity:
|
||||
status = cloud_constants.CLOUD_SYNCED_PHONE_NOT_VERIFIED
|
||||
is_phone_verified = cloud_identity.phone_number_verified
|
||||
if is_phone_verified:
|
||||
status = cloud_constants.CLOUD_SYNCED_PHONE_VERIFIED
|
||||
link = urljoin(
|
||||
connector.cloud_url, f"a/grafana-oncall-app/?page=users&p=1&id={cloud_identity.cloud_id}"
|
||||
)
|
||||
|
||||
# TODO: Grafana CN - decide if emails is needed. If yes - don't forget to check that they mustn't be shown to users
|
||||
response.append(
|
||||
{"id": user.public_primary_key, "username": user.username, "cloud_sync_status": status, "link": link}
|
||||
{
|
||||
"id": user.public_primary_key,
|
||||
"email": user.email,
|
||||
"username": user.username,
|
||||
"cloud_data": {"status": status, "link": link},
|
||||
}
|
||||
)
|
||||
|
||||
return self.get_paginated_response(response)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue