Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return API URL as part of status #2791

Merged
merged 10 commits into from
Aug 22, 2023
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

### Changed

- Grafana plugin app to use common PluginAuthentication, allow mobile app to access status endpoint @mderynck ([#2791](https://github.com/grafana/oncall/pull/2791))

### Fixed

- Ignore ical cancelled events when calculating shifts ([#2776](https://github.com/grafana/oncall/pull/2776))
Expand Down
28 changes: 0 additions & 28 deletions engine/apps/grafana_plugin/permissions.py

This file was deleted.

24 changes: 22 additions & 2 deletions engine/apps/grafana_plugin/tests/test_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,28 @@ def test_allow_signup(make_organization_and_user_with_plugin_token, make_user_au
)
response = client.get(reverse("grafana-plugin:status"), format="json", **auth_headers)

# if the org doesn't exist this will never return 200 due to
# the PluginTokenVerified permission class..
# should consider removing the DynamicSetting logic because technically this
# condition will never be reached in the code...
assert response.status_code == status.HTTP_403_FORBIDDEN


@pytest.mark.django_db
def test_status_mobile_app_auth_token(
make_organization_and_user_with_mobile_app_auth_token,
make_user_auth_headers,
):
organization, user, auth_token = make_organization_and_user_with_mobile_app_auth_token()

client = APIClient()
url = reverse("grafana-plugin:status")

response = client.post(url)
assert response.status_code == status.HTTP_403_FORBIDDEN

auth_headers = make_user_auth_headers(
user,
auth_token,
)

response = client.post(url, format="json", **auth_headers)
assert response.status_code == status.HTTP_200_OK
4 changes: 2 additions & 2 deletions engine/apps/grafana_plugin/views/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
from rest_framework.response import Response
from rest_framework.views import APIView

from apps.grafana_plugin.permissions import PluginTokenVerified
from apps.auth_token.auth import PluginAuthentication
from apps.user_management.models import Organization
from apps.user_management.sync import sync_organization
from common.api_helpers.mixins import GrafanaHeadersMixin


class InstallView(GrafanaHeadersMixin, APIView):
permission_classes = (PluginTokenVerified,)
authentication_classes = (PluginAuthentication,)

def post(self, request: Request) -> Response:
stack_id = self.instance_context["stack_id"]
Expand Down
15 changes: 11 additions & 4 deletions engine/apps/grafana_plugin/views/status.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@
from apps.auth_token.auth import PluginAuthentication
from apps.base.models import DynamicSetting
from apps.grafana_plugin.helpers import GrafanaAPIClient
from apps.grafana_plugin.permissions import PluginTokenVerified
from apps.grafana_plugin.tasks.sync import plugin_sync_organization_async
from apps.mobile_app.auth import MobileAppAuthTokenAuthentication
from apps.user_management.models import Organization
from common.api_helpers.mixins import GrafanaHeadersMixin


class StatusView(GrafanaHeadersMixin, APIView):
permission_classes = (PluginTokenVerified,)
authentication_classes = (
MobileAppAuthTokenAuthentication,
PluginAuthentication,
)

def post(self, request: Request) -> Response:
"""
Expand All @@ -36,11 +39,14 @@ def post(self, request: Request) -> Response:
is_installed = False
token_ok = False
allow_signup = True
api_url = settings.BASE_URL

# Check if organization is in OnCall database
if organization := Organization.objects.get(stack_id=stack_id, org_id=org_id):
is_installed = True
token_ok = organization.api_token_status == Organization.API_TOKEN_STATUS_OK
if organization.is_moved:
api_url = organization.migration_destination.oncall_backend_url
else:
allow_signup = DynamicSetting.objects.get_or_create(
name="allow_plugin_organization_signup", defaults={"boolean_value": True}
Expand All @@ -64,11 +70,12 @@ def post(self, request: Request) -> Response:
"is_installed": is_installed,
"token_ok": token_ok,
"allow_signup": allow_signup,
"is_user_anonymous": self.grafana_context["IsAnonymous"],
"is_user_anonymous": self.grafana_context.get("IsAnonymous", False),
"license": settings.LICENSE,
"version": settings.VERSION,
"recaptcha_site_key": settings.RECAPTCHA_V3_SITE_KEY,
"currently_undergoing_maintenance_message": settings.CURRENTLY_UNDERGOING_MAINTENANCE_MESSAGE,
"api_url": api_url,
}
)

Expand Down Expand Up @@ -96,7 +103,7 @@ def get(self, _request: Request) -> Response:
"is_installed": is_installed,
"token_ok": token_ok,
"allow_signup": allow_signup,
"is_user_anonymous": self.grafana_context["IsAnonymous"],
"is_user_anonymous": self.grafana_context.get("IsAnonymous", False),
"license": settings.LICENSE,
"version": settings.VERSION,
}
Expand Down
3 changes: 1 addition & 2 deletions engine/apps/grafana_plugin/views/sync.py
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!

Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from rest_framework.views import APIView

from apps.auth_token.auth import PluginAuthentication
from apps.grafana_plugin.permissions import PluginTokenVerified
from apps.grafana_plugin.tasks.sync import plugin_sync_organization_async
from apps.user_management.models import Organization
from common.api_helpers.mixins import GrafanaHeadersMixin
Expand All @@ -16,7 +15,7 @@


class PluginSyncView(GrafanaHeadersMixin, APIView):
permission_classes = (PluginTokenVerified,)
authentication_classes = (PluginAuthentication,)

def post(self, request: Request) -> Response:
"""Deprecated. May be used for the plugins with versions < 1.3.17"""
Expand Down
4 changes: 2 additions & 2 deletions engine/apps/grafana_plugin/views/sync_organization.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
from rest_framework.response import Response
from rest_framework.views import APIView

from apps.grafana_plugin.permissions import PluginTokenVerified
from apps.auth_token.auth import PluginAuthentication
from apps.user_management.models import Organization
from apps.user_management.sync import sync_organization
from common.api_helpers.mixins import GrafanaHeadersMixin


class SyncOrganizationView(GrafanaHeadersMixin, APIView):
permission_classes = (PluginTokenVerified,)
authentication_classes = (PluginAuthentication,)

def post(self, request: Request) -> Response:
stack_id = self.instance_context["stack_id"]
Expand Down
6 changes: 0 additions & 6 deletions engine/apps/mobile_app/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from rest_framework.authentication import BaseAuthentication, get_authorization_header

from apps.auth_token.exceptions import InvalidToken
from apps.user_management.exceptions import OrganizationDeletedException, OrganizationMovedException
from apps.user_management.models import User

from .models import MobileAppAuthToken, MobileAppVerificationToken
Expand Down Expand Up @@ -43,9 +42,4 @@ def authenticate_credentials(self, token_string: str) -> Tuple[Optional[User], O
except InvalidToken:
return None, None

if auth_token.organization.is_moved:
mderynck marked this conversation as resolved.
Show resolved Hide resolved
raise OrganizationMovedException(auth_token.organization)
if auth_token.organization.deleted_at:
raise OrganizationDeletedException(auth_token.organization)

return auth_token.user, auth_token