Skip to content

Commit

Permalink
Pull request update/250205
Browse files Browse the repository at this point in the history
c6d5bbb OSN-275. Update error message alignment
daf0563 OSN-601. Update chart legend anchor position to top-right
7f33866 OSN-229. Add validation for user_id on creating recipient + fixed swagger
  • Loading branch information
stanfra authored Feb 5, 2025
2 parents 51e09ee + c6d5bbb commit 3a73eb9
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 28 deletions.
16 changes: 16 additions & 0 deletions katara/katara_service/controllers/recipient.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import json
import logging
from requests.exceptions import HTTPError
from sqlalchemy import and_, exists

from tools.optscale_exceptions.common_exc import (
ConflictException,
WrongArgumentsException,
)
from optscale_client.auth_client.client_v2 import Client as AuthClient
from optscale_client.rest_api_client.client_v2 import Client as RestClient

from katara.katara_service.controllers.base import BaseController
Expand All @@ -23,11 +25,19 @@
class RecipientController(BaseController):
def __init__(self, db_session=None, config=None, engine=None):
super().__init__(db_session, config, engine)
self._auth_cl = None
self._rest_cl = None

def _get_model_type(self):
return Recipient

@property
def auth_cl(self):
if self._auth_cl is None:
self._auth_cl = AuthClient(url=self._config.auth_url(),
secret=self._config.cluster_secret())
return self._auth_cl

@property
def rest_cl(self):
if self._rest_cl is None:
Expand Down Expand Up @@ -61,6 +71,12 @@ def _validate(self, recipient, is_new=True, **kwargs):
RolePurpose(recipient.role_purpose)
except ValueError:
raise WrongArgumentsException(Err.OKA0025, ["role_purpose"])
if recipient.user_id:
try:
_, user = self.auth_cl.user_get(recipient.user_id)
except HTTPError:
raise WrongArgumentsException(Err.OKA0004,
["User", recipient.user_id])

def delete(self, **kwargs):
payload_dict = kwargs.pop("payload")
Expand Down
3 changes: 2 additions & 1 deletion katara/katara_service/handlers/v2/recipients.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ async def patch(self, recipient_id, **kwargs):
Modifies a recipient with specified id \n\n
Required permission: CLUSTER_SECRET
parameters:
- name: id
- name: recipient_id
in: path
description: Recipient ID
required: true
Expand Down Expand Up @@ -264,6 +264,7 @@ async def post(self, **url_params):
400:
description: |
Wrong arguments:
- OKA0004: User does not exist
- OKA0009: Incorrect request body received
- OKA0012: Unexpected parameters
- OKA0016: Incorrect meta format
Expand Down
1 change: 1 addition & 0 deletions katara/katara_service/tests/unittests/test_api_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def db_session(self):
def setUp(self):
super().setUp()
secret = gen_id()
patch('optscale_client.config_client.client.Client.auth_url').start()
patch('optscale_client.config_client.client.Client.cluster_secret',
return_value=secret).start()
http_provider = FetchMethodHttpProvider(self.fetch, rethrow=False)
Expand Down
26 changes: 24 additions & 2 deletions katara/katara_service/tests/unittests/test_api_recipient.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import json
import uuid

from unittest.mock import patch
from requests.exceptions import HTTPError
from requests.models import Response
from katara.katara_service.tests.unittests.test_api_base import TestBase


Expand Down Expand Up @@ -90,8 +92,11 @@ def test_recipient_create(self):
self.assertEqual(recipient['scope_id'], payload['scope_id'])

def test_recipient_create_user_id(self):
user_id = str(uuid.uuid4())
patch('optscale_client.auth_client.client_v2.Client.user_get',
return_value=(200, {'user_id': user_id})).start()
payload = {
"user_id": str(uuid.uuid4()),
"user_id": user_id,
"scope_id": str(uuid.uuid4()),
}
code, recipient = self.client.recipient_create(**payload)
Expand All @@ -100,6 +105,23 @@ def test_recipient_create_user_id(self):
self.assertEqual(recipient['user_id'], payload['user_id'])
self.assertEqual(recipient['scope_id'], payload['scope_id'])

def test_recipient_create_user_id_not_exists(self):
def raise_404(*_args, **_kwargs):
err = HTTPError('User not found')
err.response = Response()
err.response.status_code = 404
raise err

patch('optscale_client.auth_client.client_v2.Client.user_get',
side_effect=raise_404).start()
payload = {
"user_id": str(uuid.uuid4()),
"scope_id": str(uuid.uuid4()),
}
code, response = self.client.recipient_create(**payload)
self.assertEqual(code, 400)
self.assertEqual(response['error']['error_code'], 'OKA0004')

def test_recipient_create_unassigned(self):
payload = {
"scope_id": str(uuid.uuid4()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ const FIELD_NAME = FIELD_NAMES.BUCKETS;

const MAX_SELECTED_BUCKETS = 100;

const TableField = ({ buckets, value, dataSources, onChange, errors }) => {
const VALIDATION_TYPE = {
AT_LEAST_ONE_SELECTED: "atLeastOneSelected",
MAX_BUCKETS: "maxBuckets"
} as const;

const TableField = ({ buckets, value, dataSources, onChange }) => {
const tableData = useMemo(
() =>
buckets.map((bucket) => {
Expand Down Expand Up @@ -54,25 +59,22 @@ const TableField = ({ buckets, value, dataSources, onChange, errors }) => {
);

return (
<>
<Table
columns={columns}
withSearch
enableSearchQueryParam={false}
data={tableData}
memoBodyCells
withSelection
rowSelection={value}
getRowId={(row) => getCloudResourceIdentifier(row)}
onRowSelectionChange={onChange}
pageSize={10}
enablePaginationQueryParam={false}
localization={{
emptyMessageId: "noBuckets"
}}
/>
{!!errors[FIELD_NAME] && <FormHelperText error>{errors[FIELD_NAME].message}</FormHelperText>}
</>
<Table
columns={columns}
withSearch
enableSearchQueryParam={false}
data={tableData}
memoBodyCells
withSelection
rowSelection={value}
getRowId={(row) => getCloudResourceIdentifier(row)}
onRowSelectionChange={onChange}
pageSize={10}
enablePaginationQueryParam={false}
localization={{
emptyMessageId: "noBuckets"
}}
/>
);
};

Expand Down Expand Up @@ -102,13 +104,13 @@ const BucketsField = ({ buckets, dataSources, isLoading }) => {
name={FIELD_NAME}
rules={{
validate: {
atLeastOneSelected: (value) =>
[VALIDATION_TYPE.AT_LEAST_ONE_SELECTED]: (value) =>
isEmptyObject(value)
? intl.formatMessage({
id: "atLeastOneBucketMustBeSelected"
})
: true,
maxBuckets: (value) => {
[VALIDATION_TYPE.MAX_BUCKETS]: (value) => {
const bucketsCount = Object.keys(value).length;
return bucketsCount > MAX_SELECTED_BUCKETS
? intl.formatMessage(
Expand Down Expand Up @@ -137,6 +139,7 @@ const BucketsField = ({ buckets, dataSources, isLoading }) => {
<strong>{Object.keys(selectedBuckets).join(", ")}</strong>
</Typography>
)}
{!!errors[FIELD_NAME] && <FormHelperText error>{errors[FIELD_NAME].message}</FormHelperText>}
</>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ import {
} from "utils/constants";
import { getXDaysAgoRange } from "utils/datetime";

type AddInstanceToScheduleContainerProps = {
powerScheduleId: string;
handleClose: () => void;
};

const INSTANCES_COUNT_LIMIT = 5000;

const useGetInstances = (range, selectedDataSourceIds, appliedFilters) => {
Expand Down Expand Up @@ -46,7 +51,7 @@ const useGetInstances = (range, selectedDataSourceIds, appliedFilters) => {
};
};

const useGetAvailableFilter = (range) => {
const useGetAvailableFilter = (range: { start: number; end: number }) => {
const { start, end } = range;

const { useGet: useGetFilters } = AvailableFiltersService();
Expand All @@ -65,7 +70,7 @@ const useGetAvailableFilter = (range) => {
};
};

const AddInstanceToScheduleContainer = ({ powerScheduleId, handleClose }) => {
const AddInstanceToScheduleContainer = ({ powerScheduleId, handleClose }: AddInstanceToScheduleContainerProps) => {
const { useAttachInstancesToSchedule } = PowerScheduleService();

const { onAttach, isLoading: isAttachLoading } = useAttachInstancesToSchedule();
Expand Down
6 changes: 6 additions & 0 deletions ngui/ui/src/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,12 @@ const getThemeConfig = (settings = {}) => {
MuiFormHelperText: {
defaultProps: {
margin: "dense"
},
styleOverrides: {
contained: () => ({
marginLeft: 0,
marginRight: 0
})
}
},
MuiIconButton: {
Expand Down
2 changes: 1 addition & 1 deletion ngui/ui/src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@ export const DEFAULT_LINE_CHART_MARGIN = Object.freeze({ top: 20, right: 35, lef
export const CHART_LEGEND_WIDTH = 200;

export const CHART_LEGEND_LAYOUT_SETTINGS = {
anchor: "bottom-right",
anchor: "top-right",
direction: "column",
translateX: 8,
itemWidth: 0,
Expand Down

1 comment on commit 3a73eb9

@nitin-invincibleOcean
Copy link

Choose a reason for hiding this comment

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

@stanfra how can i connect to you i wish to contribute to the project but dont know how to run a specific server since i am not very well used to contributing to monoreps . Hope you can guide me @api_monk_61674 this is my discord username

Please sign in to comment.