From 6a72f9df4e5adb110d92b032daa688a9c726967d Mon Sep 17 00:00:00 2001 From: Mustafa Baser Date: Thu, 26 Sep 2024 14:43:19 +0300 Subject: [PATCH] feat(jans-cli-tui): client active tokens Signed-off-by: Mustafa Baser --- .../010_auth_server/edit_client_dialog.py | 142 +++++++++++++++++- jans-cli-tui/cli_tui/plugins/080_smtp/main.py | 9 +- jans-cli-tui/cli_tui/utils/static.py | 1 + 3 files changed, 142 insertions(+), 10 deletions(-) diff --git a/jans-cli-tui/cli_tui/plugins/010_auth_server/edit_client_dialog.py b/jans-cli-tui/cli_tui/plugins/010_auth_server/edit_client_dialog.py index b7e392cdf1e..c8c9be82383 100644 --- a/jans-cli-tui/cli_tui/plugins/010_auth_server/edit_client_dialog.py +++ b/jans-cli-tui/cli_tui/plugins/010_auth_server/edit_client_dialog.py @@ -12,6 +12,7 @@ HSplit, VSplit, DynamicContainer, + HorizontalAlign, ) from prompt_toolkit.widgets import ( Button, @@ -26,10 +27,10 @@ from prompt_toolkit.lexers import PygmentsLexer, DynamicLexer from prompt_toolkit.application.current import get_app from prompt_toolkit.buffer import Buffer -from prompt_toolkit.formatted_text import AnyFormattedText +from prompt_toolkit.formatted_text import AnyFormattedText, HTML from prompt_toolkit.eventloop import get_event_loop -from utils.static import DialogResult, cli_style, ISOFORMAT +from utils.static import DialogResult, cli_style, common_strings, ISOFORMAT from utils.multi_lang import _ from utils.utils import common_data, fromisoformat, DialogUtils from wui_components.jans_dialog_with_nav import JansDialogWithNav @@ -100,7 +101,9 @@ def __init__( self.title = title self.nav_dialog_width = int(self.myparent.dialog_width*1.1) self.client_scopes_entries = [] + self.active_tokes_buttons = VSplit([]) self.add_scope_checkbox = CheckboxList(values=[('', '')]) + self.activate_tokens_per_page = self.myparent.dialog_height-11 self.fill_client_scopes() self.prepare_tabs() self.create_window() @@ -798,7 +801,6 @@ def change_view_hide(me): (_("Transaction Token Enc for Encryption"), 'txTokenEncryptedResponseEnc', 'tx_token_encryption_enc_values_supported'), - ): self.drop_down_select_first.append(swagger_key) @@ -981,8 +983,142 @@ def allow_spontaneous_changed(cb): self.tabs['Client Scripts'] = HSplit(list(self.scripts_widget_dict.values()), width=D(), style=cli_style.tabs) + + self.active_tokens_list = JansVerticalNav( + myparent=common_data.app, + headers=[_("Delatable"), _("Expiration"), _("Token Type")], + preferred_size=[0, 0, 0], + data={}, + on_display=common_data.app.data_display_dialog, + on_delete=self.delete_active_token, + selectes=0, + headerColor=cli_style.navbar_headcolor, + entriesColor=cli_style.navbar_entriescolor, + all_data=[], + hide_headers=True + ) + + self.active_tokens_list.start_index = 0 + self.search_active_tokens_button = self.myparent.getButtonWithHandler( + text=_("Get Active Tokens"), + name='oauth:active-tokens:search', + jans_help=_("Gets active tokens associated with this client"), + handler=self.search_active_tokens, + centered=True + ) + + if self.data.get('inum'): + self.tabs['Active Tokens'] = HSplit([ + self.search_active_tokens_button, + self.active_tokens_list, + DynamicContainer(lambda: self.active_tokes_buttons) + ], + width=D()) + self.left_nav = list(self.tabs.keys())[0] + def delete_active_token(self, **kwargs: Any) -> None: + """This method for the deletion of the User + """ + + entry = self.active_tokens_list.all_data[kwargs['selected_idx']] + + if not entry.get('deletable'): + common_data.app.show_message(_(common_strings.warning), _("This token cannot be delated."), tobefocused=self.active_tokens_list) + return + + def do_delete_token(): + cli_args = {'operation_id': 'revoke-token', 'url_suffix': f"tknCde:{entry['tokenCode']}"} + + async def coroutine(): + common_data.app.start_progressing(_("Deleting token {}...").format(entry['tokenCode'])) + response = await common_data.app.loop.run_in_executor(common_data.app.executor, common_data.app.cli_requests, cli_args) + common_data.app.stop_progressing() + + if response is not None: + common_data.app.show_message(_(common_strings.error), _("Token was not delated"), tobefocused=self.active_tokens_list) + return + + self.get_client_active_tokens(start_index=self.active_tokens_list.start_index) + asyncio.ensure_future(coroutine()) + + + buttons = [Button(_("No")), Button(_("Yes"), handler=do_delete_token)] + + common_data.app.show_message( + title=_(common_strings.confirm), + message=HTML(_("Are you sure you want to delete token {}?").format(entry['tokenCode'])), + buttons=buttons, + ) + + + def search_active_tokens(self, button_name) -> None: + """This method handle the search for active tokens + + Args: + tbuffer (Buffer): Buffer returned from the TextArea widget > GetTitleText + """ + + #self.oauth_get_scopes(pattern=tbuffer.text) + + if not self.data.get('inum'): + return + + self.get_client_active_tokens() + + def get_client_active_tokens(self, start_index=0, pattern=''): + self.active_tokens_list.start_index = start_index + + endpoint_args = f"limit:{self.activate_tokens_per_page},startIndex:{start_index},fieldValuePair:clientId={self.data['inum']}" + if pattern: + endpoint_args += f',pattern:{pattern}' + + cli_args = {'operation_id': 'search-token', 'endpoint_args': endpoint_args} + + + def get_next(): + self.get_client_active_tokens(start_index=start_index+self.activate_tokens_per_page, pattern=pattern) + + def get_previous(): + self.get_client_active_tokens(start_index=start_index-self.activate_tokens_per_page, pattern=pattern) + + + async def coroutine(): + common_data.app.start_progressing(_("Retreiving tokens from server...")) + response = await common_data.app.loop.run_in_executor(common_data.app.executor, common_data.app.cli_requests, cli_args) + common_data.app.stop_progressing() + result = response.json() + common_data.app.logger.debug("Tokens: {}".format(result)) + + if not result.get('entries'): + self.active_tokes_buttons = VSplit([]) + common_data.app.show_message(_(common_strings.no_matching_result), _("No token found for this search."), tobefocused=self.search_active_tokens_button) + return + + self.active_tokens_list.clear() + all_data = result['entries'] + self.active_tokens_list.all_data = all_data + for entry in all_data: + #entry.pop('tokenCode', None) + self.active_tokens_list.add_item( + [str(entry.get('deletable', 'False')), + str(entry.get('expirationDate', '---')), + entry.get('tokenType', '---')] + ) + + buttons = [] + if start_index: + buttons.append(Button("Previous", handler=get_previous)) + if result['totalEntriesCount'] > start_index + self.activate_tokens_per_page: + buttons.append(Button("Next", handler=get_next)) + + self.active_tokes_buttons = VSplit(buttons, padding=1, align=HorizontalAlign.CENTER) + self.active_tokens_list.hide_headers = False + common_data.app.layout.focus(self.active_tokens_list) + + asyncio.ensure_future(coroutine()) + + def scope_exists(self, scope_dn: str) -> bool: for item_id, item_label in self.client_scopes.entries: diff --git a/jans-cli-tui/cli_tui/plugins/080_smtp/main.py b/jans-cli-tui/cli_tui/plugins/080_smtp/main.py index f7025046e38..d02d0d64302 100755 --- a/jans-cli-tui/cli_tui/plugins/080_smtp/main.py +++ b/jans-cli-tui/cli_tui/plugins/080_smtp/main.py @@ -5,15 +5,10 @@ import prompt_toolkit from prompt_toolkit.eventloop import get_event_loop -from prompt_toolkit.layout.containers import HSplit, DynamicContainer,\ - VSplit, Window, HorizontalAlign, Window +from prompt_toolkit.layout.containers import HSplit, VSplit, Window, HorizontalAlign from prompt_toolkit.layout.dimension import D -from prompt_toolkit.widgets import Frame, Button, Label, Box, Dialog +from prompt_toolkit.widgets import Button from prompt_toolkit.application import Application -from wui_components.jans_nav_bar import JansNavBar -from wui_components.jans_drop_down import DropDownWidget -from wui_components.jans_vetrical_nav import JansVerticalNav -from wui_components.jans_cli_dialog import JansGDialog from utils.multi_lang import _ from utils.utils import DialogUtils from utils.static import cli_style, common_strings diff --git a/jans-cli-tui/cli_tui/utils/static.py b/jans-cli-tui/cli_tui/utils/static.py index 9753a908018..46159255c24 100755 --- a/jans-cli-tui/cli_tui/utils/static.py +++ b/jans-cli-tui/cli_tui/utils/static.py @@ -37,6 +37,7 @@ class common_strings: oops = "Oops" success = "Success" warning = "Warning!" + confirm = "Confirm" help_enter = f' {_("Confirm or Edit current selection")}' help_esc = f' {_("Close the current dialog")}'