main.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. import os
  2. from pathlib import Path
  3. import typer
  4. from archive_logs import run as run_archive_logs
  5. from clients import run
  6. from files import run as run_files
  7. from info import run as run_info
  8. from move_files import default_desktop, refresh_and_move
  9. from session_details import run as run_session_details
  10. from summary import run as run_summary
  11. from watch import run as run_watch
  12. app = typer.Typer(help="PC-Visit Filetracker")
  13. DATA_DIRECTORY = Path("data")
  14. def default_session_history() -> Path:
  15. user_profile = Path(os.environ.get("USERPROFILE", str(Path.home())))
  16. return user_profile / "AppData" / "Roaming" / "pcvisit Data" / "Session History"
  17. @app.callback(invoke_without_command=True)
  18. def app_callback(context: typer.Context) -> None:
  19. """Verwalten der PC-Visit-Filetracker-Befehle."""
  20. if context.invoked_subcommand is None:
  21. typer.echo(context.get_help())
  22. @app.command("clients")
  23. def clients_command(
  24. directory: Path | None = typer.Argument(None, help="Verzeichnis mit XML-Dateien"),
  25. output: Path = typer.Option(DATA_DIRECTORY / "clients.csv", "--output", "-o", help="Zielpfad der CSV-Datei"),
  26. ) -> None:
  27. """Importiert Client-Daten aus Session-XML-Dateien."""
  28. directory = directory or default_session_history()
  29. try:
  30. result = run(directory, output)
  31. except ValueError as error:
  32. raise typer.BadParameter(str(error), param_hint="directory") from error
  33. typer.echo(f"{result.xml_count} XML-Dateien gelesen, {result.row_count} Einträge nach {output} geschrieben.")
  34. @app.command("files")
  35. def files_command(
  36. directory: Path | None = typer.Argument(None, help="Verzeichnis mit XML-Dateien"),
  37. output: Path = typer.Option(DATA_DIRECTORY / "files.csv", "--output", "-o", help="Zielpfad der CSV-Datei"),
  38. ignore_timestamp: bool = typer.Option(
  39. False,
  40. "--ignore-timestamp",
  41. help="Ignoriert den Abgleich des Erstellungsdatums mit der Session.",
  42. ),
  43. ) -> None:
  44. """Importiert vorhandene Dateien aus ReceivedFile-Elementen."""
  45. directory = directory or default_session_history()
  46. try:
  47. result = run_files(directory, output, ignore_timestamp=ignore_timestamp)
  48. except ValueError as error:
  49. raise typer.BadParameter(str(error), param_hint="directory") from error
  50. typer.echo(
  51. f"{result.xml_count} XML-Dateien gelesen, {result.row_count} vorhandene Dateien nach {output} geschrieben."
  52. )
  53. @app.command("move-files")
  54. def move_files_command(
  55. directory: Path | None = typer.Argument(None, help="Verzeichnis mit XML-Dateien"),
  56. files_csv: Path = typer.Option(
  57. DATA_DIRECTORY / "files.csv", "--files-csv", help="CSV-Datei mit den gefundenen Dateien"
  58. ),
  59. clients_csv: Path = typer.Option(DATA_DIRECTORY / "clients.csv", "--clients-csv", help="CSV-Datei mit den Kunden"),
  60. desktop: Path | None = typer.Option(None, "--desktop", help="Desktop-Verzeichnis als Zielbasis"),
  61. ignore_timestamp: bool = typer.Option(
  62. False,
  63. "--ignore-timestamp",
  64. help="Ignoriert den Abgleich des Erstellungsdatums mit der Session.",
  65. ),
  66. ) -> None:
  67. """Verschiebt gefundene Dateien in Desktop/PC-Visit/Kunde."""
  68. directory = directory or default_session_history()
  69. try:
  70. result = refresh_and_move(
  71. directory,
  72. files_csv,
  73. clients_csv,
  74. desktop or default_desktop(),
  75. ignore_timestamp,
  76. )
  77. except ValueError as error:
  78. raise typer.BadParameter(str(error)) from error
  79. typer.echo(
  80. f"{result.moved_count} Dateien verschoben, {result.skipped_count} übersprungen, "
  81. f"{result.missing_client_count} ohne Kunde."
  82. )
  83. @app.command("archive-logs")
  84. def archive_logs_command(
  85. directory: Path | None = typer.Argument(None, help="Verzeichnis mit XML-Dateien"),
  86. ) -> None:
  87. """Archiviert Session-XML-Dateien nach Jahr."""
  88. directory = directory or default_session_history()
  89. try:
  90. result = run_archive_logs(directory)
  91. except ValueError as error:
  92. raise typer.BadParameter(str(error), param_hint="directory") from error
  93. typer.echo(
  94. f"{result.checked_count} XML-Dateien geprüft, {result.archived_count} archiviert, "
  95. f"{result.skipped_count} übersprungen."
  96. )
  97. @app.command("summary")
  98. def summary_command(
  99. input_path: Path = typer.Option(
  100. DATA_DIRECTORY / "session_details.csv",
  101. "--input",
  102. "-i",
  103. help="Eingabe-CSV aus session-details",
  104. ),
  105. output: Path = typer.Option(DATA_DIRECTORY / "summary.csv", "--output", "-o", help="Zielpfad der CSV-Datei"),
  106. days: int = typer.Option(14, "--days", help="Anzahl der letzten Kalendertage für die Konsolenausgabe"),
  107. ) -> None:
  108. """Erstellt eine Zusammenfassung aus session_details.csv."""
  109. try:
  110. result = run_summary(input_path, output, days)
  111. except ValueError as error:
  112. raise typer.BadParameter(str(error), param_hint="input_path") from error
  113. typer.echo(
  114. f"{result.activity_count} Aktivitäten gelesen, {result.summary_count} Zusammenfassungen nach {output} geschrieben."
  115. )
  116. if result.recent_summary:
  117. typer.echo(result.recent_summary)
  118. @app.command("info")
  119. def info_command(
  120. directory: Path | None = typer.Argument(None, help="Verzeichnis mit XML-Dateien"),
  121. days: int = typer.Option(14, "--days", help="Anzahl der letzten Kalendertage für die Konsolenausgabe"),
  122. ) -> None:
  123. """Führt clients, archive-logs, session-details und summary aus."""
  124. directory = directory or default_session_history()
  125. try:
  126. result = run_info(
  127. directory,
  128. DATA_DIRECTORY / "clients.csv",
  129. DATA_DIRECTORY / "session_details.csv",
  130. DATA_DIRECTORY / "summary.csv",
  131. days,
  132. )
  133. except ValueError as error:
  134. raise typer.BadParameter(str(error), param_hint="directory") from error
  135. typer.echo(f"clients: {result.clients_result.row_count} Einträge")
  136. typer.echo(
  137. f"archive-logs: {result.archive_result.archived_count} archiviert, "
  138. f"{result.archive_result.skipped_count} übersprungen"
  139. )
  140. typer.echo(f"session-details: {result.session_details_result.activity_count} UserActivity-Einträge")
  141. typer.echo(f"summary: {result.summary_result.summary_count} Zusammenfassungen")
  142. if result.summary_result.recent_summary:
  143. typer.echo(result.summary_result.recent_summary)
  144. @app.command("session-details")
  145. def session_details_command(
  146. directory: Path | None = typer.Argument(None, help="Verzeichnis mit XML-Dateien"),
  147. output: Path = typer.Option(
  148. DATA_DIRECTORY / "session_details.csv",
  149. "--output",
  150. "-o",
  151. help="Zielpfad der CSV-Datei",
  152. ),
  153. ) -> None:
  154. """Sammelt UserActivity-Details aus Session-XML-Dateien."""
  155. directory = directory or default_session_history()
  156. try:
  157. result = run_session_details(directory, output)
  158. except ValueError as error:
  159. raise typer.BadParameter(str(error), param_hint="directory") from error
  160. typer.echo(
  161. f"{result.xml_count} XML-Dateien geprüft, {result.activity_count} UserActivity-Einträge nach {output} geschrieben."
  162. )
  163. @app.command("watch")
  164. def watch_command(
  165. directory: Path | None = typer.Argument(None, help="Verzeichnis mit XML-Dateien"),
  166. files_csv: Path = typer.Option(
  167. DATA_DIRECTORY / "files.csv", "--files-csv", help="CSV-Datei mit den gefundenen Dateien"
  168. ),
  169. clients_csv: Path = typer.Option(DATA_DIRECTORY / "clients.csv", "--clients-csv", help="CSV-Datei mit den Kunden"),
  170. desktop: Path | None = typer.Option(None, "--desktop", help="Desktop-Verzeichnis als Zielbasis"),
  171. ignore_timestamp: bool = typer.Option(
  172. False,
  173. "--ignore-timestamp",
  174. help="Ignoriert den Abgleich des Erstellungsdatums mit der Session.",
  175. ),
  176. ) -> None:
  177. """Überwacht XML-Dateien und führt bei Änderungen move-files aus."""
  178. directory = directory or default_session_history()
  179. try:
  180. run_watch(directory, files_csv, clients_csv, desktop or default_desktop(), ignore_timestamp)
  181. except ValueError as error:
  182. raise typer.BadParameter(str(error), param_hint="directory") from error
  183. if __name__ == "__main__":
  184. app()