Skip to content

Commit e1912cf

Browse files
feat: add settings/system/ API endpoint (#1064)
Co-authored-by: Alex <[email protected]>
1 parent a4ac860 commit e1912cf

File tree

7 files changed

+183
-0
lines changed

7 files changed

+183
-0
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Copyright 2024 Red Hat, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from rest_framework import serializers
16+
17+
from aap_eda.conf import settings_registry
18+
19+
20+
class SettingSerializer(serializers.Serializer):
21+
def __init__(self, *args, **kwargs):
22+
super(SettingSerializer, self).__init__(*args, **kwargs)
23+
24+
for key in settings_registry.get_registered_settings():
25+
v_type = settings_registry.get_setting_type(key)
26+
read_only = settings_registry.is_setting_read_only(key)
27+
if v_type == str:
28+
field = serializers.CharField(
29+
required=False, allow_blank=True, read_only=read_only
30+
)
31+
elif v_type == int:
32+
field = serializers.IntegerField(
33+
required=False, read_only=read_only
34+
)
35+
elif v_type == bool:
36+
field = serializers.BooleanField(
37+
required=False, read_only=read_only
38+
)
39+
elif v_type == dict:
40+
field = serializers.JSONField(
41+
required=False, read_only=read_only
42+
)
43+
else:
44+
raise TypeError(f"unsupported type {v_type}")
45+
self.fields[key] = field

src/aap_eda/api/urls.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@
8585

8686
eda_v1_urls = [
8787
path("config/", views.ConfigView.as_view(), name="config"),
88+
path(
89+
"settings/system/", views.SettingView.as_view(), name="setting-system"
90+
),
8891
path("status/", core_views.StatusView.as_view(), name="status"),
8992
path("", include(openapi_urls)),
9093
path(

src/aap_eda/api/views/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from .project import ProjectViewSet
2525
from .root import ApiRootView, ApiV1RootView
2626
from .rulebook import AuditRuleViewSet, RulebookViewSet
27+
from .setting import SettingView
2728
from .team import TeamViewSet
2829
from .user import CurrentUserAwxTokenViewSet, CurrentUserView, UserViewSet
2930

@@ -61,4 +62,5 @@
6162
"EventStreamViewSet",
6263
# External event stream
6364
"ExternalEventStreamViewSet",
65+
"SettingView",
6466
)

src/aap_eda/api/views/setting.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Copyright 2024 Red Hat, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from drf_spectacular.utils import OpenApiResponse, extend_schema
16+
from rest_framework import status
17+
from rest_framework.permissions import IsAdminUser
18+
from rest_framework.request import Request
19+
from rest_framework.response import Response
20+
from rest_framework.views import APIView
21+
22+
from aap_eda.api.serializers.setting import SettingSerializer
23+
from aap_eda.conf import settings_registry
24+
25+
26+
class SettingView(APIView):
27+
permission_classes = [IsAdminUser]
28+
29+
def get_serializer(self, *args, **kwargs):
30+
return SettingSerializer(*args, **kwargs)
31+
32+
@extend_schema(
33+
description="Get application system settings",
34+
responses={
35+
status.HTTP_200_OK: OpenApiResponse(
36+
SettingSerializer,
37+
description=("Return application system settings"),
38+
)
39+
},
40+
)
41+
def get(self, request):
42+
data = settings_registry.db_get_settings_for_display()
43+
return Response(SettingSerializer(data).data)
44+
45+
@extend_schema(
46+
description="Partially update application system settings",
47+
request=SettingSerializer,
48+
responses={
49+
status.HTTP_200_OK: OpenApiResponse(
50+
SettingSerializer,
51+
description="Return updated system settings.",
52+
),
53+
},
54+
)
55+
def patch(self, request: Request):
56+
serializer = SettingSerializer(data=request.data)
57+
serializer.is_valid(raise_exception=True)
58+
settings_registry.db_update_settings(serializer.validated_data)
59+
60+
return self.get(None)
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Copyright 2024 Red Hat, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import pytest
16+
from rest_framework import status
17+
from rest_framework.test import APIClient
18+
19+
from aap_eda.conf import settings_registry
20+
from tests.integration.constants import api_url_v1
21+
22+
23+
@pytest.fixture(autouse=True)
24+
def register() -> None:
25+
settings_registry.persist_registry_data()
26+
27+
28+
@pytest.mark.django_db
29+
def test_list_system_settings(superuser_client: APIClient):
30+
response = superuser_client.get(f"{api_url_v1}/settings/system/")
31+
assert response.status_code == status.HTTP_200_OK
32+
data = response.data
33+
assert len(data) == 10
34+
assert data["INSIGHTS_TRACKING_STATE"] is False
35+
assert data["AUTOMATION_ANALYTICS_GATHER_INTERVAL"] == 14400
36+
37+
38+
@pytest.mark.django_db
39+
def test_partial_update_system_settings(superuser_client: APIClient):
40+
pword = "secret"
41+
body = {"REDHAT_USERNAME": "auser", "REDHAT_PASSWORD": pword}
42+
response = superuser_client.patch(
43+
f"{api_url_v1}/settings/system/", data=body
44+
)
45+
assert response.status_code == status.HTTP_200_OK
46+
data = response.data
47+
assert len(data) == 10
48+
assert data["REDHAT_USERNAME"] == "auser"
49+
assert data["REDHAT_PASSWORD"] == "$encrypted$"
50+
51+
52+
@pytest.mark.django_db
53+
def test_list_settings_forbidden(user_client: APIClient):
54+
response = user_client.get(f"{api_url_v1}/settings/system/")
55+
assert response.status_code == status.HTTP_403_FORBIDDEN
56+
57+
58+
@pytest.mark.django_db
59+
def test_update_settings_forbidden(user_client: APIClient):
60+
response = user_client.patch(f"{api_url_v1}/settings/system/", data={})
61+
assert response.status_code == status.HTTP_403_FORBIDDEN
62+
63+
64+
@pytest.mark.django_db
65+
def test_update_settings_wrong_type(superuser_client: APIClient):
66+
data = {"AUTOMATION_ANALYTICS_GATHER_INTERVAL": "not number"}
67+
response = superuser_client.patch(
68+
f"{api_url_v1}/settings/system/", data=data
69+
)
70+
assert response.status_code == status.HTTP_400_BAD_REQUEST

tests/integration/api/test_root.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
"/organizations/",
4646
"/teams/",
4747
"/event-streams/",
48+
"/settings/system/",
4849
],
4950
True,
5051
id="with_shared_resource",
@@ -83,6 +84,7 @@
8384
"/organizations/",
8485
"/teams/",
8586
"/event-streams/",
87+
"/settings/system/",
8688
],
8789
False,
8890
id="no_shared_resource",

tests/integration/conftest.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ def super_user():
7474
password="superuser123",
7575
email="superuser@localhost",
7676
is_superuser=True,
77+
is_staff=True,
7778
)
7879

7980

0 commit comments

Comments
 (0)