ungana

Unnamed repository; edit this file 'description' to name the repository.
Info | Log | Files | Refs | README

commit e86d18c274dc4097ef28f9c3bb774af7b9a67dba
parent 7c17d01b7abe1d5b73cc09e6cd5803772b803306
Author: Carlosokumu <carlosokumu254@gmail.com>
Date:   Fri, 29 Aug 2025 12:52:46 +0300

add user input validation

Diffstat:
Mungana/cmd/args_parser.py | 99+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
1 file changed, 64 insertions(+), 35 deletions(-)

diff --git a/ungana/cmd/args_parser.py b/ungana/cmd/args_parser.py @@ -3,6 +3,7 @@ from pathlib import Path from datetime import datetime, timedelta import re import logging +import sys from ungana.attachment.attachment_manager import AttachmentManager from ungana.ical.ical_manager import ICalManager from ungana.logging.logging_manager import LoggingManager @@ -128,44 +129,72 @@ class ArgsParser: self.logger = self.logging.get_logger("ArgsParser") return args - + + def _prompt_datetime(self, prompt: str, allow_blank: bool = False): + """Prompt user for a datetime in YYYY-MM-DD HH:MM format (with retry).""" + while True: + value = input(prompt).strip() + if allow_blank and not value: + return None + try: + return datetime.strptime(value, "%Y-%m-%d %H:%M") + except ValueError: + prog = self.parser.prog if hasattr(self, "parser") else "program" + print(f"{prog}: error: invalid datetime format, expected YYYY-MM-DD HH:MM") + + def _prompt_timezone(self): + """Prompt for timezone ID with validation.""" + while True: + try: + tzid = input("Enter timezone ID (e.g. Europe/Berlin) [default: UTC]: ").strip() or "UTC" + tzinfo = tz.gettz(tzid) + if tzinfo is None: + print(f"Invalid timezone ID: {tzid}. Please try again.") + else: + return tzid + except KeyboardInterrupt: + prog = self.parser.prog if hasattr(self, "parser") else "program" + print(f"\n{prog}: cancelled by user") + sys.exit(1) + def prompt_compulsory_event_fields(self): - """Prompt user for compulsory event fields interactively.""" - summary = input("Enter event summary (title): ").strip() - description = input("Enter description: ").strip() - start = input("Enter start datetime (YYYY-MM-DD HH:MM): ").strip() - - end = input("Enter end datetime (YYYY-MM-DD HH:MM) [leave blank if using duration]: ").strip() - start_dt = datetime.strptime(start, "%Y-%m-%d %H:%M") + try: + summary = input("Enter event summary (title): ").strip() + description = input("Enter description: ").strip() + + start_dt = self._prompt_datetime("Enter start datetime (YYYY-MM-DD HH:MM): ") + end_dt = self._prompt_datetime( + "Enter end datetime (YYYY-MM-DD HH:MM) [leave blank if using duration]: ", + allow_blank=True + ) + + if end_dt: + duration_dt = end_dt - start_dt + duration = f"{duration_dt.seconds//3600}h{(duration_dt.seconds%3600)//60}m" + else: + duration = input("Enter duration (e.g. 1h, 30m): ").strip() + + location = input("Enter location: ").strip() + organizer = input("Enter organizer (name/email): ").strip() + tzid = self._prompt_timezone() + + return { + "summary": summary, + "description": description, + "start": start_dt, + "end": end_dt, + "duration": duration if duration else None, + "location": location, + "organizer": organizer, + "tzid": tzid, + } + + except KeyboardInterrupt: + prog = self.parser.prog if hasattr(self, "parser") else "program" + print(f"\n{prog}: cancelled by user") + sys.exit(1) - if not end: - duration = input("Enter duration (e.g. 1h, 30m): ").strip() - else: - end_dt = datetime.strptime(end, "%Y-%m-%d %H:%M") - delta = end_dt - start_dt - hours, remainder = divmod(delta.seconds, 3600) - minutes, _ = divmod(remainder, 60) - duration = f"PT{delta.days}D{hours}H{minutes}M" if delta.days else f"PT{hours}H{minutes}M" - - - location = input("Enter location: ").strip() - organizer = input("Enter organizer (name/email): ").strip() - - tzid = input("Enter timezone ID (e.g. Europe/Berlin) [default: UTC]: ").strip() - if not tzid: - tzid = "UTC" - - return { - "summary": summary, - "description": description, - "start": start, - "end": end if end else None, - "duration": duration if duration else None, - "location": location, - "organizer": organizer, - "tzid": tzid, - }