@@ -544,5 +544,107 @@ def list_lists(url, username, password, nextcloud_mode, debug):
544544 raise click .Abort ()
545545
546546
547+ @cli .command (name = "dump-all-tasks" )
548+ @click .option ("--url" , help = "CalDAV server URL (or set CALDAV_URL env var)" )
549+ @click .option ("--username" , help = "CalDAV username (or set CALDAV_USERNAME env var)" )
550+ @click .option ("--password" , help = "CalDAV password (or set CALDAV_PASSWORD env var)" )
551+ @click .option (
552+ "--nextcloud-mode/--no-nextcloud-mode" ,
553+ default = True ,
554+ help = "Adjust URL for Nextcloud specific path [default: enabled]" ,
555+ )
556+ @click .option (
557+ "--debug/--no-debug" ,
558+ default = False ,
559+ help = "Enable debug mode with interactive console [default: disabled]" ,
560+ )
561+ @click .option (
562+ "--list-uid" ,
563+ default = None ,
564+ envvar = "CALDAV_TASKS_API_DEFAULT_LIST_UID" ,
565+ help = "UID of the task list to dump all tasks from. Defaults to CALDAV_TASKS_API_DEFAULT_LIST_UID env var if set." ,
566+ )
567+ def dump_all_tasks (url , username , password , nextcloud_mode , debug , list_uid ):
568+ """Dump all tasks from a specified list in VTODO format."""
569+ logger .debug (
570+ f"CLI dump-all-tasks initiated with url: { '***' if url else 'from env' } , "
571+ f"user: { username or 'from env' } , nc_mode: { nextcloud_mode } , "
572+ f"debug: { debug } , list_uid: { list_uid } "
573+ )
574+
575+ if not list_uid :
576+ click .echo (
577+ "Error: Task list UID must be provided via --list-uid argument or CALDAV_TASKS_API_DEFAULT_LIST_UID environment variable." ,
578+ err = True ,
579+ )
580+ raise click .Abort ()
581+
582+ try :
583+ # This command is inherently read-only.
584+ # Filter to only the specified list to optimize loading
585+ api = get_api (
586+ url ,
587+ username ,
588+ password ,
589+ nextcloud_mode ,
590+ debug ,
591+ target_lists = [list_uid ],
592+ read_only = True ,
593+ )
594+
595+ logger .info ("Loading remote tasks..." )
596+ api .load_remote_data ()
597+
598+ # Find the specified task list
599+ target_task_list = None
600+ for task_list in api .task_lists :
601+ if task_list .uid == list_uid :
602+ target_task_list = task_list
603+ break
604+
605+ if not target_task_list :
606+ click .echo (f"Error: Task list with UID '{ list_uid } ' not found." , err = True )
607+ raise click .Abort ()
608+
609+ click .echo (
610+ f"# Dumping all tasks from list: '{ target_task_list .name } ' (UID: { list_uid } )"
611+ )
612+ click .echo (f"# Total tasks: { len (target_task_list .tasks )} " )
613+ click .echo ("" )
614+
615+ if not target_task_list .tasks :
616+ click .echo ("# No tasks found in this list." )
617+ return
618+
619+ # Print each task's VTODO format
620+ for i , task in enumerate (target_task_list .tasks , 1 ):
621+ click .echo (f"# Task { i } /{ len (target_task_list .tasks )} : { task .text } " )
622+ click .echo (f"# UID: { task .uid } " )
623+ click .echo ("" )
624+ vtodo_string = task .to_ical ()
625+ click .echo (vtodo_string )
626+ click .echo ("" ) # Extra blank line between tasks
627+
628+ if debug :
629+ click .echo (
630+ "Debug mode: Starting interactive console. API and task list available as 'api', 'target_task_list'."
631+ )
632+ _globals = globals ().copy ()
633+ _locals = locals ().copy ()
634+ _globals .update (_locals )
635+ code .interact (local = _globals )
636+
637+ except click .UsageError as ue :
638+ click .echo (f"Configuration error: { ue } " , err = True )
639+ raise click .Abort ()
640+ except ConnectionError as ce :
641+ click .echo (f"Connection failed: { ce } " , err = True )
642+ raise click .Abort ()
643+ except Exception as e :
644+ logger .exception (f"An unexpected error occurred: { e } " )
645+ click .echo (f"Error: { e } " , err = True )
646+ raise click .Abort ()
647+
648+
547649if __name__ == "__main__" :
548650 cli ()
0 commit comments