Implemented OTP Activities and OTP Revoke

This commit is contained in:
2025-10-27 12:14:01 -04:00
parent c52767b3a3
commit 595f19ab27
4 changed files with 218 additions and 31 deletions
+96 -18
View File
@@ -1,11 +1,10 @@
import logging
from typing import Any, Callable, List, Optional, Union
import pandas as pd
from utils.utils import colorText, get_sanitized_input
logger = logging.getLogger(__name__)
class Selector:
@staticmethod
def _get_sorted_items(items: List[Any], label_func: Callable[[Any], str]) -> List[Any]:
@@ -18,6 +17,11 @@ class Selector:
num_columns: int = 4,
header: str = "Available Choices:"
) -> None:
# Force single column if items are DataFrame rows
if items and isinstance(items[0], (pd.Series, dict)):
num_columns = 1
rows = (len(items) + num_columns - 1) // num_columns
print(f"\n{header}")
for row in range(rows):
@@ -39,7 +43,6 @@ class Selector:
if not selected:
print(" (none)")
return
sorted_selected = sorted(selected, key=lambda item: label_func(item).lower())
rows = (len(sorted_selected) + num_columns - 1) // num_columns
for row in range(rows):
@@ -72,7 +75,8 @@ class Selector:
label_func: Callable[[Any], str],
allow_multiple: bool = False,
prompt_each: bool = False,
header: str = "Available Choices:"
header: str = "Available Choices:",
num_columns: int = 4
) -> Union[Optional[Any], List[Any]]:
if not items:
logger.warning("No items available for selection.")
@@ -84,11 +88,9 @@ class Selector:
if allow_multiple:
while True:
Selector._display_choices(remaining_items, label_func, header=header)
Selector._display_selected_items(selected, label_func)
Selector._display_choices(remaining_items, label_func, num_columns=num_columns, header=header)
Selector._display_selected_items(selected, label_func, num_columns=num_columns)
choice = get_sanitized_input("Select item(s) by number (e.g. 1,3-5), R to reset, Q to finish: ").strip().lower()
if choice == "q":
break
elif choice == "r":
@@ -96,10 +98,8 @@ class Selector:
remaining_items = full_sorted_items.copy()
print(colorText("🔄 Selections reset.", "yellow"))
continue
indices = Selector._parse_selection_input(choice, len(remaining_items))
newly_selected = []
for index in indices:
item = remaining_items[index - 1]
if item not in selected:
@@ -109,13 +109,10 @@ class Selector:
logger.info(f"Selected: {label_func(item)}")
else:
logger.warning("Item already selected.")
# Remove newly selected items from remaining list
remaining_items = [item for item in remaining_items if item not in newly_selected]
return selected if selected else None
else:
Selector._display_choices(full_sorted_items, label_func, header=header)
Selector._display_choices(full_sorted_items, label_func, num_columns=num_columns, header=header)
try:
choice = int(get_sanitized_input("Select one item by number: "))
if 1 <= choice <= len(full_sorted_items):
@@ -136,7 +133,6 @@ class Selector:
) -> List[Any]:
print(colorText("Choose selection mode: [I]nclude only selected, [E]xclude selected, [A]ll (skip):", "white"))
mode = get_sanitized_input("").strip().lower()
if mode == "a":
return items
selected = Selector._select_from_list(
@@ -146,10 +142,8 @@ class Selector:
prompt_each=False,
header=header
)
if not selected:
return items
if mode == "i":
print(colorText(f"✅ Included {len(selected)} item(s).", "green"))
return selected
@@ -237,4 +231,88 @@ class Selector:
logger.info("User declined action.")
return False
else:
logger.warning("Invalid confirmation input. Expected 'Y' or 'N'.")
logger.warning("Invalid confirmation input. Expected 'Y' or 'N'.")
@staticmethod
def select_dataframe_rows(
df: pd.DataFrame,
columns: Optional[List[str]] = None,
allow_multiple: bool = False,
prompt_each: bool = False,
header: str = "Available Rows:"
) -> List[pd.Series]:
if df.empty:
print("DataFrame is empty.")
return []
if columns:
df = df[columns]
items = [row for _, row in df.iterrows()]
label_func = lambda row: str(row.to_dict())
result = Selector._select_from_list(
items,
label_func=label_func,
allow_multiple=allow_multiple,
prompt_each=prompt_each,
header=header
)
if isinstance(result, pd.Series):
return [result]
elif isinstance(result, list):
return result
else:
return []
@staticmethod
def select_dataframe_with_mode(
df: pd.DataFrame,
columns: Optional[List[str]] = None,
header: str = "Available Rows:"
) -> List[pd.Series]:
if df.empty:
print("⚠️ DataFrame is empty.")
return []
# Filter columns if specified
if columns:
df = df[columns]
items = df.to_dict("records")
label_func = lambda row: " | ".join(str(row[col]) for col in df.columns)
# Show rows first
print(colorText(header, "cyan"))
for i, row in enumerate(items):
print(f"{i}: {label_func(row)}")
# Prompt for mode once
print(colorText("\nChoose selection mode: [I]nclude only selected, [E]xclude selected, [A]ll (skip):", "white"))
mode = get_sanitized_input("").strip().lower()
if mode == "a":
return [pd.Series(row) for row in items]
# Prompt for selection only once
selected = Selector._select_from_list(
items,
label_func=label_func,
allow_multiple=True,
prompt_each=False,
header=header
)
if not selected:
return [pd.Series(row) for row in items]
if mode == "i":
print(colorText(f"✅ Included {len(selected)} row(s).", "green"))
return [pd.Series(row) for row in selected]
elif mode == "e":
print(colorText(f"🚫 Excluded {len(selected)} row(s).", "yellow"))
return [pd.Series(row) for row in items if row not in selected]
else:
print(colorText("⚠️ Invalid mode. Returning all rows.", "yellow"))
return [pd.Series(row) for row in items]