Skip to content

Commit

Permalink
feat(jans-cli-tui): message configuration (#7198)
Browse files Browse the repository at this point in the history
Signed-off-by: Mustafa Baser <mbaser@mail.com>
Signed-off-by: Yuriy Movchan <Yuriy.Movchan@gmail.com>
  • Loading branch information
devrimyatar authored and yurem committed Jan 1, 2024
1 parent 3196566 commit 9a2b6c9
Show file tree
Hide file tree
Showing 4 changed files with 232 additions and 4 deletions.
3 changes: 3 additions & 0 deletions jans-cli-tui/cli_tui/cli/config_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -991,6 +991,9 @@ def patch_requests(self, endpoint, url_param_dict, data):
response = requests.patch(**patch_params)
self.log_response(response)

if self.wrapped:
return response

try:
return response.json()
except:
Expand Down
16 changes: 15 additions & 1 deletion jans-cli-tui/cli_tui/plugins/010_auth_server/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
from ssa import SSA
from agama import Agama
from authn import Authn
from message import Message
from attributes import Attributes

from prompt_toolkit.widgets import (
Expand Down Expand Up @@ -70,6 +71,7 @@ def __init__(
self.ssa = SSA(app)
self.agama = Agama(app)
self.authn = Authn(app)
self.message = Message()
self.attributes = Attributes(app)
self.oauth_containers = {}

Expand Down Expand Up @@ -245,6 +247,7 @@ def oauth_prepare_containers(self) -> None:
self.oauth_containers['authn'] = self.authn.main_container
self.oauth_containers['attributes'] = self.attributes.main_container
self.oauth_containers['logging'] = DynamicContainer(lambda: self.oauth_data_container['logging'])
self.oauth_containers['message'] = self.message.main_container

self.oauth_main_container = HSplit([
Box(self.nav_bar.nav_window, style='class:sub-navbar', height=1),
Expand All @@ -259,7 +262,18 @@ def oauth_prepare_navbar(self) -> None:
"""
self.nav_bar = JansNavBar(
self.app,
entries=[('clients', 'C[l]ients'), ('scopes', 'Sc[o]pes'), ('keys', '[K]eys'), ('authn', 'Au[t]hn'), ('properties', 'Properti[e]s'), ('logging', 'Lo[g]ging'), ('ssa', '[S]SA'), ('agama', 'Aga[m]a'), ('attributes', 'Attri[b]utes')],
entries=[
('clients', 'C[l]ients'),
('scopes', 'Sc[o]pes'),
('keys', '[K]eys'),
('authn', 'Au[t]hn'),
('properties', 'Properti[e]s'),
('logging', 'Lo[g]ging'),
('ssa', '[S]SA'),
('agama', 'Aga[m]a'),
('attributes', 'Attri[b]utes'),
('message', 'Message')
],
selection_changed=self.oauth_nav_selection_changed,
select=0,
jans_name='oauth:nav_bar'
Expand Down
128 changes: 128 additions & 0 deletions jans-cli-tui/cli_tui/plugins/010_auth_server/message.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import asyncio

from prompt_toolkit.layout.dimension import D
from prompt_toolkit.eventloop import get_event_loop
from prompt_toolkit.layout.containers import HSplit, VSplit, DynamicContainer, HorizontalAlign
from prompt_toolkit.widgets import Button, Frame, RadioList

from utils.multi_lang import _
from utils.utils import DialogUtils
from utils.static import cli_style, common_strings
from utils.utils import common_data

class Message(DialogUtils):
def __init__(self) -> None:

self.first_enter = False
self.data = {}
self.message_provider_container = VSplit([])
self.working_container = VSplit([])
self.main_container = DynamicContainer(lambda: self.working_container)

self.main_container.on_page_enter = self.on_page_enter

def on_page_enter(self) -> None:

if not self.first_enter:
self.get_message_configuration()
self.schema = common_data.app.cli_object.get_schema_from_reference('', '#/components/schemas/MessageConfiguration')

self.message_provider_type_widget = common_data.app.getTitledRadioButton(
_("Message Provider Type"),
name='messageProviderType',
values=[(mtype, mtype) for mtype in self.schema['properties']['messageProviderType']['enum']],
current_value='NULL',
jans_help="Message provider Type",
on_selection_changed=self.display_message_provider_type,
style=cli_style.radio_button)
self.working_container = HSplit([
Frame(self.message_provider_type_widget),
DynamicContainer(lambda: self.message_provider_container)
])

self.first_enter = True

def display_message_provider_type(self, rlwidget: RadioList):
provider_type = rlwidget.current_value

save_button = Button(text=_("Save"), handler=self.save)

if provider_type == 'NULL':
widgets = []
self.provider_widgets = []
else:
styles = {'widget_style':cli_style.black_bg_widget, 'string': cli_style.edit_text, 'boolean': cli_style.check_box}
schema_prop_name = f'{provider_type.lower()}Configuration'
properties = self.schema['properties'][schema_prop_name]['properties']
self.provider_widgets = self.get_widgets(
properties=properties,
values=self.data.get(schema_prop_name),
styles=styles
)
widgets = [Frame(body=HSplit(self.provider_widgets),title=f'{provider_type} Configuration')]

widgets.append(VSplit([save_button], align=HorizontalAlign.CENTER))
self.message_provider_container = HSplit(widgets, width=D())

def save(self):
provider_type = self.message_provider_type_widget.me.current_value

# save provider type

async def provider_type_coroutine():
cli_args = {'operation_id': 'patch-config-message', 'data':[{'op':'replace', 'path': 'messageProviderType', 'value': provider_type}]}
common_data.app.start_progressing(_("Saving provider type"))
response = await get_event_loop().run_in_executor(common_data.app.executor, common_data.app.cli_requests, cli_args)
common_data.app.stop_progressing()
if response.status_code not in (200, 201):
common_data.app.show_message(common_strings.error, str(response.text), tobefocused=self.main_container)
else:
self.data = response.json()

asyncio.ensure_future(provider_type_coroutine())


# save prpvider data

async def provider_coroutine(pcli_args):
common_data.app.start_progressing(_("Saving message configuration"))
response = await get_event_loop().run_in_executor(common_data.app.executor, common_data.app.cli_requests, pcli_args)
common_data.app.stop_progressing()
if response.status_code not in (200, 201):
common_data.app.show_message(common_strings.error, str(response.text), tobefocused=self.main_container)
else:
self.data = response.json()

if provider_type != 'NULL':
data = {}
for widget in self.provider_widgets:
item_data = self.get_item_data(widget)
if item_data:
data[item_data['key']] = item_data['value']
cli_args = {'operation_id': 'put-config-message-' + provider_type.lower(), 'data': data}


asyncio.ensure_future(provider_coroutine(cli_args))


def get_message_configuration(self):
async def coroutine():
cli_args = {'operation_id': 'get-config-message'}
common_data.app.start_progressing(_("Retreiving message configuration"))
response = await get_event_loop().run_in_executor(common_data.app.executor, common_data.app.cli_requests, cli_args)
common_data.app.stop_progressing()

if response.status_code not in (200, 201):
common_data.app.show_message(common_strings.error, str(response.text), tobefocused=self.main_container)

try:
self.data = response.json()
except Exception as e:
common_data.app.show_message(common_strings.error, str(e), tobefocused=self.main_container)
return

self.message_provider_type_widget.me.current_value = self.data.get('messageProviderType', 'NULL')
self.display_message_provider_type(self.message_provider_type_widget.me)

asyncio.ensure_future(coroutine())

89 changes: 86 additions & 3 deletions jans-cli-tui/cli_tui/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from wui_components.jans_drop_down import DropDownWidget
from wui_components.jans_spinner import Spinner
from wui_components.jans_vetrical_nav import JansVerticalNav

from utils.static import cli_style
from wui_components.jans_date_picker import DateSelectWidget
from utils.multi_lang import _

Expand Down Expand Up @@ -90,12 +90,95 @@ def check_required_fields(self, container=None, data=None, tobefocused=None):
missing_fields.append(item.children[1].jans_name)

if missing_fields:
app = self.app if hasattr(self, 'app') else self.myparent
app.show_message(_("Please fill required fields"), _("The following fields are required:\n") + ', '.join(missing_fields), tobefocused=tobefocused)
common_data.app.show_message(_("Please fill required fields"), _("The following fields are required:\n") + ', '.join(missing_fields), tobefocused=tobefocused)
return False

return True

def get_widgets(
self,
properties:dict,
values: dict=None,
styles: dict=None
) -> list:
"""Returns list of widgets for properties
Args:
properties (dict): properties to get widget
values (dict): values of properties
styes (dict): styles for widgets
"""

if not values:
values = {}
if not styles:
styles = {'widget_style':'', 'string': cli_style.edit_text, 'boolean': cli_style.check_box}

widgets = []
for item_name in properties:
item = properties[item_name]
if item['type'] in ('integer', 'string'):
if item.get('enum'):
widgets.append(
common_data.app.getTitledWidget(
item_name,
name=item_name,
widget=DropDownWidget(
values=[(str(enum), str(enum)) for enum in item['enum']],
value=str(values.get(item_name) or '')
),
style=styles['string'],
)
)
else:
widgets.append(
common_data.app.getTitledText(
item_name,
name=item_name,
value=str(values.get(item_name) or ''),
text_type=item['type'],
style=styles['string'],
widget_style=styles['widget_style']
)
)

elif item['type'] == 'boolean':
widgets.append(
common_data.app.getTitledCheckBox(
item_name,
name=item_name,
checked=values.get(item_name, False),
style=styles['boolean'],
widget_style=styles['widget_style']
)
)

elif item['type'] == 'array' and item['items'].get('enum'):
widgets.append(
common_data.app.getTitledCheckBoxList(
item_name,
name=item_name,
values=item['items']['enum'],
current_values=values.get(item_name, []),
style=styles['boolean'],
widget_style=styles['widget_style']
)
)

elif item['type'] == 'array' and item['items'].get('type') in ('string', 'integer'):
titled_text = common_data.app.getTitledText(
item_name,
name=item_name,
height=4,
text_type = item['items']['type'],
value='\n'.join(values.get(item_name, [])),
style=styles['string'],
widget_style=styles['widget_style']
)
titled_text.jans_list_type = True
widgets.append(titled_text)

return widgets

def fromisoformat(dt_str):
dt, _, us = dt_str.partition(".")
Expand Down

0 comments on commit 9a2b6c9

Please sign in to comment.