her-sync 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. her_sync-0.3.0/.gitignore +20 -0
  2. her_sync-0.3.0/PKG-INFO +115 -0
  3. her_sync-0.3.0/README.md +86 -0
  4. her_sync-0.3.0/calendar_filters.yaml +7 -0
  5. her_sync-0.3.0/deploy/DISTRIBUTION.md +56 -0
  6. her_sync-0.3.0/deploy/calendar.example.yml +10 -0
  7. her_sync-0.3.0/deploy/config.example.yml +2 -0
  8. her_sync-0.3.0/deploy/crm.example.yml +9 -0
  9. her_sync-0.3.0/deploy/her@.service +11 -0
  10. her_sync-0.3.0/deploy/mail.example.yml +9 -0
  11. her_sync-0.3.0/deploy/profile.example.yml +8 -0
  12. her_sync-0.3.0/deploy/systemd-install.sh +12 -0
  13. her_sync-0.3.0/email_filters.yaml +26 -0
  14. her_sync-0.3.0/pyproject.toml +38 -0
  15. her_sync-0.3.0/scripts/her-release +9 -0
  16. her_sync-0.3.0/scripts/release_cli.py +329 -0
  17. her_sync-0.3.0/skills/receipt-extraction/SKILL.md +67 -0
  18. her_sync-0.3.0/src/her_sync/__init__.py +3 -0
  19. her_sync-0.3.0/src/her_sync/__main__.py +3 -0
  20. her_sync-0.3.0/src/her_sync/apply/__init__.py +8 -0
  21. her_sync-0.3.0/src/her_sync/apply/cost_centers.py +84 -0
  22. her_sync-0.3.0/src/her_sync/apply/invoices.py +77 -0
  23. her_sync-0.3.0/src/her_sync/bde/__init__.py +11 -0
  24. her_sync-0.3.0/src/her_sync/bde/cashflows.py +150 -0
  25. her_sync-0.3.0/src/her_sync/bde/cost_centers.py +22 -0
  26. her_sync-0.3.0/src/her_sync/bde/invoices.py +199 -0
  27. her_sync-0.3.0/src/her_sync/bde/session.py +124 -0
  28. her_sync-0.3.0/src/her_sync/cli.py +407 -0
  29. her_sync-0.3.0/src/her_sync/cli_helpers.py +10 -0
  30. her_sync-0.3.0/src/her_sync/collectors/__init__.py +10 -0
  31. her_sync-0.3.0/src/her_sync/collectors/cashflows.py +166 -0
  32. her_sync-0.3.0/src/her_sync/collectors/invoices.py +70 -0
  33. her_sync-0.3.0/src/her_sync/collectors/receipts.py +30 -0
  34. her_sync-0.3.0/src/her_sync/config.py +153 -0
  35. her_sync-0.3.0/src/her_sync/daemon.py +102 -0
  36. her_sync-0.3.0/src/her_sync/io/paths.py +69 -0
  37. her_sync-0.3.0/src/her_sync/io/xlsx.py +51 -0
  38. her_sync-0.3.0/src/her_sync/migrate.py +252 -0
  39. her_sync-0.3.0/src/her_sync/plugins/__init__.py +1 -0
  40. her_sync-0.3.0/src/her_sync/plugins/bde.py +180 -0
  41. her_sync-0.3.0/src/her_sync/plugins/caldav.py +124 -0
  42. her_sync-0.3.0/src/her_sync/plugins/email.py +59 -0
  43. her_sync-0.3.0/src/her_sync/profile.py +275 -0
  44. her_sync-0.3.0/src/her_sync/secrets.py +92 -0
  45. her_sync-0.3.0/src/her_sync/sync/__init__.py +3 -0
  46. her_sync-0.3.0/src/her_sync/sync/caldav_client.py +199 -0
  47. her_sync-0.3.0/src/her_sync/sync/calendar.py +287 -0
  48. her_sync-0.3.0/src/her_sync/sync/calendar_filters.py +53 -0
  49. her_sync-0.3.0/src/her_sync/sync/calendar_priority.py +59 -0
  50. her_sync-0.3.0/src/her_sync/sync/email.py +498 -0
  51. her_sync-0.3.0/src/her_sync/sync/email_filters.py +77 -0
  52. her_sync-0.3.0/src/her_sync/sync/email_watcher.py +151 -0
  53. her_sync-0.3.0/src/her_sync/sync/gloda_index.py +63 -0
  54. her_sync-0.3.0/src/her_sync/sync/mbox_reader.py +163 -0
  55. her_sync-0.3.0/src/her_sync/sync/msf_index.py +279 -0
  56. her_sync-0.3.0/src/her_sync/sync/sync_lock.py +28 -0
  57. her_sync-0.3.0/src/her_sync/tools/browser_record.py +76 -0
  58. her_sync-0.3.0/tests/test_caldav_client.py +56 -0
  59. her_sync-0.3.0/tests/test_email_sync.py +91 -0
  60. her_sync-0.3.0/tests/test_mbox_reader.py +39 -0
  61. her_sync-0.3.0/tests/test_migrate.py +28 -0
  62. her_sync-0.3.0/tests/test_msf_index.py +60 -0
  63. her_sync-0.3.0/tests/test_paths.py +36 -0
  64. her_sync-0.3.0/tests/test_profile.py +50 -0
  65. her_sync-0.3.0/tests/test_pypi_token.py +45 -0
@@ -0,0 +1,20 @@
1
+ .env
2
+ .venv/
3
+ __pycache__/
4
+ *.pyc
5
+ .pytest_cache/
6
+ .ruff_cache/
7
+ *.egg-info/
8
+ dist/
9
+ build/
10
+ share/
11
+
12
+ # Share-Verzeichnis enthält sensible Daten
13
+ share/data/
14
+ share/inbox/
15
+ share/outbox/
16
+ share/complete/
17
+
18
+ # Browser-Session für manuelles Login
19
+ .sessions/
20
+ playwright-state/
@@ -0,0 +1,115 @@
1
+ Metadata-Version: 2.5
2
+ Name: her-sync
3
+ Version: 0.3.0
4
+ Summary: Linux-native Sync-Tool für Agent-Share-Filesysteme (BDE, Email, CalDAV)
5
+ Requires-Python: >=3.11
6
+ Requires-Dist: beautifulsoup4>=4.12
7
+ Requires-Dist: caldav>=1.3
8
+ Requires-Dist: httpx>=0.27
9
+ Requires-Dist: icalendar>=6.0
10
+ Requires-Dist: keyring>=25.0
11
+ Requires-Dist: lxml>=5.0
12
+ Requires-Dist: openpyxl>=3.1
13
+ Requires-Dist: pydantic>=2.0
14
+ Requires-Dist: pyyaml>=6.0
15
+ Requires-Dist: rich>=13.0
16
+ Requires-Dist: typer[all]>=0.12
17
+ Provides-Extra: dev
18
+ Requires-Dist: build>=1.0; extra == 'dev'
19
+ Requires-Dist: playwright>=1.40; extra == 'dev'
20
+ Requires-Dist: pytest>=8.0; extra == 'dev'
21
+ Requires-Dist: ruff>=0.4; extra == 'dev'
22
+ Requires-Dist: twine>=5.0; extra == 'dev'
23
+ Provides-Extra: release
24
+ Requires-Dist: build>=1.0; extra == 'release'
25
+ Requires-Dist: twine>=5.0; extra == 'release'
26
+ Provides-Extra: watch
27
+ Requires-Dist: watchdog>=4.0; extra == 'watch'
28
+ Description-Content-Type: text/markdown
29
+
30
+ # her-sync
31
+
32
+ Linux-native Sync-Tool für Agent-Share-Filesysteme (BDE, Email, CalDAV).
33
+ CLI-Befehl: **`her`**
34
+
35
+ ## Installation
36
+
37
+ ```bash
38
+ pipx install "her-sync[watch]"
39
+ ```
40
+
41
+ Aus Git:
42
+
43
+ ```bash
44
+ pipx install --force "git+https://gitea.example.com/you/her-sync@main#egg=her-sync[watch]"
45
+ ```
46
+
47
+ Entwicklung: `pip install -e ".[watch,dev]"`
48
+
49
+ ## Konfiguration
50
+
51
+ `~/.her/`
52
+
53
+ ```
54
+ ~/.her/
55
+ ├── config.yml
56
+ ├── profiles/bde-work/
57
+ │ ├── profile.yml # share + watch
58
+ │ ├── crm.yml # bde: { ... }
59
+ │ ├── mail.yml # email: { ... }
60
+ │ ├── calendar.yml # caldav: { ... }
61
+ │ └── local.yml # optional: Overrides (alphabetisch später = gewinnt)
62
+ ├── state/bde-work/
63
+ └── share-bde/ # optional — Share kann auch woanders liegen
64
+ ```
65
+
66
+ Alle `.yml`-Dateien im Profilordner werden **alphabetisch** geladen und deep-gemergt.
67
+ Welches Plugin aktiv ist, ergibt sich **nur aus dem YAML-Key** (`bde:`, `email:`, `caldav:`) —
68
+ der Dateiname spielt keine Rolle. Fehlender Key = Plugin deaktiviert.
69
+
70
+ ```yaml
71
+ # local.yml — optional, überschreibt Teile aus calendar.yml o.ä.
72
+ caldav:
73
+ months_past: 6
74
+ ```
75
+
76
+ ```bash
77
+ her profile init bde-work
78
+ her profile migrate-env --env-file .env --name bde-work
79
+ her secrets set bde-work/bde-password
80
+ her --profile bde-work status
81
+ ```
82
+
83
+ ## CLI
84
+
85
+ ```bash
86
+ her profile list|show|init|migrate-env|validate
87
+ her secrets set|delete|test
88
+ her daemon run|start|stop|status
89
+ her status
90
+
91
+ her bde collect cashflows
92
+ her bde collect cashflow-history --force
93
+ her bde apply cost-centers --dry-run
94
+
95
+ her email sync
96
+ her caldav ls
97
+ her caldav sync
98
+ ```
99
+
100
+ ## Daemon
101
+
102
+ ```bash
103
+ her daemon run --profile bde-work
104
+ ./deploy/systemd-install.sh bde-work
105
+ systemctl --user start her@bde-work
106
+ ```
107
+
108
+ ## Release (Repo-Checkout)
109
+
110
+ ```bash
111
+ her secrets set release/her-pypi-token # einmalig lokal
112
+ ./scripts/her-release release --bump patch --pypi
113
+ ```
114
+
115
+ Details: [deploy/DISTRIBUTION.md](deploy/DISTRIBUTION.md)
@@ -0,0 +1,86 @@
1
+ # her-sync
2
+
3
+ Linux-native Sync-Tool für Agent-Share-Filesysteme (BDE, Email, CalDAV).
4
+ CLI-Befehl: **`her`**
5
+
6
+ ## Installation
7
+
8
+ ```bash
9
+ pipx install "her-sync[watch]"
10
+ ```
11
+
12
+ Aus Git:
13
+
14
+ ```bash
15
+ pipx install --force "git+https://gitea.example.com/you/her-sync@main#egg=her-sync[watch]"
16
+ ```
17
+
18
+ Entwicklung: `pip install -e ".[watch,dev]"`
19
+
20
+ ## Konfiguration
21
+
22
+ `~/.her/`
23
+
24
+ ```
25
+ ~/.her/
26
+ ├── config.yml
27
+ ├── profiles/bde-work/
28
+ │ ├── profile.yml # share + watch
29
+ │ ├── crm.yml # bde: { ... }
30
+ │ ├── mail.yml # email: { ... }
31
+ │ ├── calendar.yml # caldav: { ... }
32
+ │ └── local.yml # optional: Overrides (alphabetisch später = gewinnt)
33
+ ├── state/bde-work/
34
+ └── share-bde/ # optional — Share kann auch woanders liegen
35
+ ```
36
+
37
+ Alle `.yml`-Dateien im Profilordner werden **alphabetisch** geladen und deep-gemergt.
38
+ Welches Plugin aktiv ist, ergibt sich **nur aus dem YAML-Key** (`bde:`, `email:`, `caldav:`) —
39
+ der Dateiname spielt keine Rolle. Fehlender Key = Plugin deaktiviert.
40
+
41
+ ```yaml
42
+ # local.yml — optional, überschreibt Teile aus calendar.yml o.ä.
43
+ caldav:
44
+ months_past: 6
45
+ ```
46
+
47
+ ```bash
48
+ her profile init bde-work
49
+ her profile migrate-env --env-file .env --name bde-work
50
+ her secrets set bde-work/bde-password
51
+ her --profile bde-work status
52
+ ```
53
+
54
+ ## CLI
55
+
56
+ ```bash
57
+ her profile list|show|init|migrate-env|validate
58
+ her secrets set|delete|test
59
+ her daemon run|start|stop|status
60
+ her status
61
+
62
+ her bde collect cashflows
63
+ her bde collect cashflow-history --force
64
+ her bde apply cost-centers --dry-run
65
+
66
+ her email sync
67
+ her caldav ls
68
+ her caldav sync
69
+ ```
70
+
71
+ ## Daemon
72
+
73
+ ```bash
74
+ her daemon run --profile bde-work
75
+ ./deploy/systemd-install.sh bde-work
76
+ systemctl --user start her@bde-work
77
+ ```
78
+
79
+ ## Release (Repo-Checkout)
80
+
81
+ ```bash
82
+ her secrets set release/her-pypi-token # einmalig lokal
83
+ ./scripts/her-release release --bump patch --pypi
84
+ ```
85
+
86
+ Details: [deploy/DISTRIBUTION.md](deploy/DISTRIBUTION.md)
@@ -0,0 +1,7 @@
1
+ # Nextcloud CalDAV — welche Kalender exportiert werden
2
+ # Leer lassen oder alle Einträge entfernen = alle Kalender des Users
3
+ #
4
+ # Namen entsprechen dem Anzeigenamen oder dem URL-Segment (z. B. personal)
5
+
6
+ calendars:
7
+ - name: personal
@@ -0,0 +1,56 @@
1
+ # Distribution
2
+
3
+ Paket: **her-sync** auf PyPI
4
+ CLI: **`her`**
5
+
6
+ ```bash
7
+ pipx install her-sync
8
+ # oder mit Watch-Extra:
9
+ pipx install "her-sync[watch]"
10
+
11
+ # Aus Git:
12
+ pipx install --force "git+https://gitea.example.com/you/her-sync@v0.3.0#egg=her-sync[watch]"
13
+
14
+ # Lokaler Checkout:
15
+ pipx install --force ".[watch]"
16
+ ```
17
+
18
+ ## Release
19
+
20
+ ```bash
21
+ pip install -e ".[dev]" # build + twine für Publish
22
+
23
+ # Lokal: Tag + pipx
24
+ ./scripts/her-release release --bump patch
25
+
26
+ # Mit PyPI-Upload (Keyring):
27
+ her secrets set release/her-pypi-token
28
+ ./scripts/her-release release --bump patch --pypi
29
+
30
+ # Nur Upload (ohne Git-Tag):
31
+ ./scripts/her-release publish
32
+ ```
33
+
34
+ ### PyPI-Token
35
+
36
+ | Quelle | Wann |
37
+ |---|---|
38
+ | `HER_PYPI_TOKEN` | CI — bevorzugt |
39
+ | `TWINE_PASSWORD` | CI-Fallback (twine-kompatibel) |
40
+ | Keyring `release/her-pypi-token` | Lokal (Default) |
41
+ | `HER_PYPI_KEYRING` / `--pypi-keyring` | Anderer Keyring-Ref |
42
+
43
+ ```bash
44
+ # Lokal einmalig
45
+ her secrets set release/her-pypi-token
46
+
47
+ # CI (Gitea/GitHub Actions)
48
+ export HER_PYPI_TOKEN=pypi-AgEI...
49
+ ./scripts/her-release release --bump patch --pypi --no-pipx
50
+ ```
51
+
52
+ Keyring-Service bleibt `her-sync` — Release-Refs unter `release/…`, getrennt von Profil-Secrets (`bde-work/…`).
53
+
54
+ ## Config
55
+
56
+ `~/.her/` — Keyring-Service: `her-sync`
@@ -0,0 +1,10 @@
1
+ caldav:
2
+ enabled: true
3
+ url: https://nc.example.com/remote.php/dav/calendars/USER/
4
+ user: USER
5
+ email: USER@example.com
6
+ password: {keyring: bde-work/caldav-password}
7
+ months_past: 12
8
+ months_future: 12
9
+ calendars:
10
+ - name: personal
@@ -0,0 +1,2 @@
1
+ # ~/.her/config.yml
2
+ default_profile: bde-work
@@ -0,0 +1,9 @@
1
+ bde:
2
+ enabled: true
3
+ base_url: http://crm.local:3000
4
+ company_id: 1
5
+ basic_auth_user: api
6
+ basic_auth_pass: {keyring: bde-work/bde-basic-pass}
7
+ login: api
8
+ password: {keyring: bde-work/bde-password}
9
+ receipts_source: ~/Documents/Belege/incoming
@@ -0,0 +1,11 @@
1
+ [Unit]
2
+ Description=Agent-Sync watcher (%i)
3
+ After=network-online.target
4
+
5
+ [Service]
6
+ ExecStart=%h/.local/bin/her daemon run --profile %i
7
+ Restart=on-failure
8
+ RestartSec=5
9
+
10
+ [Install]
11
+ WantedBy=default.target
@@ -0,0 +1,9 @@
1
+ email:
2
+ enabled: true
3
+ mode: mbox
4
+ betterbird_profile: ~/.var/app/eu.betterbird.Betterbird/.thunderbird/PROFILE.default-default
5
+ filters:
6
+ - name: unread-inbox
7
+ folders:
8
+ - ImapMail/imap.gmail.com/INBOX
9
+ unread_only: true
@@ -0,0 +1,8 @@
1
+ # ~/.her/profiles/bde-work/profile.yml
2
+ share: ~/.her/share-bde
3
+
4
+ watch:
5
+ debounce_seconds: 10
6
+ on_email_change:
7
+ - email
8
+ - caldav
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ PROFILE="${1:-bde-work}"
4
+ UNIT_DIR="${HOME}/.config/systemd/user"
5
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
6
+
7
+ mkdir -p "$UNIT_DIR"
8
+ cp "${SCRIPT_DIR}/her@.service" "${UNIT_DIR}/"
9
+ systemctl --user daemon-reload
10
+ systemctl --user enable "her@${PROFILE}.service"
11
+ echo "Installiert: her@${PROFILE}"
12
+ echo "Start: systemctl --user start her@${PROFILE}"
@@ -0,0 +1,26 @@
1
+ # E-Mail Export-Filter (Betterbird mbox, relativ zu BETTERBIRD_PROFILE)
2
+ # Export nach: share/data/inbox/emails/<name>/<YYYYMMDD_HHMMSS>_<hash>/ (UTC)
3
+ #
4
+ # Pro Filter:
5
+ # folders — mbox-Ordner (mehrere möglich)
6
+ # unread_only — nur ungelesene Mails (X-Mozilla-Status)
7
+ # tags — Betterbird-Tags (X-Mozilla-Keys), mindestens einer muss passen
8
+ # months_past — 0 = kein Datumsfilter; >0 = nur Mails der letzten N Monate
9
+ # trust_gloda_read — bei unread_only: Gloda-Read-Status nutzen wenn MSF noch
10
+ # „ungelesen“ zeigt (Betterbird schreibt .msf verzögert)
11
+ #
12
+ # Beim nächsten Sync werden Exporte gelöscht, die nicht mehr passen.
13
+
14
+ filters:
15
+ - name: unread-inbox
16
+ folders:
17
+ - ImapMail/imap.gmail.com/INBOX
18
+ unread_only: true
19
+
20
+ # - name: rechnungen
21
+ # folders:
22
+ # - ImapMail/imap.gmail.com/[Gmail].sbd/Geschäftlich.sbd/Rechnungen
23
+ # - ImapMail/imap.gmail.com/[Gmail].sbd/Geschäftlich.sbd/Steuer
24
+ # months_past: 3
25
+ # tags:
26
+ # - Steuer
@@ -0,0 +1,38 @@
1
+ [project]
2
+ name = "her-sync"
3
+ version = "0.3.0"
4
+ description = "Linux-native Sync-Tool für Agent-Share-Filesysteme (BDE, Email, CalDAV)"
5
+ readme = "README.md"
6
+ requires-python = ">=3.11"
7
+ dependencies = [
8
+ "typer[all]>=0.12",
9
+ "httpx>=0.27",
10
+ "beautifulsoup4>=4.12",
11
+ "lxml>=5.0",
12
+ "openpyxl>=3.1",
13
+ "pydantic>=2.0",
14
+ "rich>=13.0",
15
+ "caldav>=1.3",
16
+ "icalendar>=6.0",
17
+ "pyyaml>=6.0",
18
+ "keyring>=25.0",
19
+ ]
20
+
21
+ [project.optional-dependencies]
22
+ watch = ["watchdog>=4.0"]
23
+ dev = ["pytest>=8.0", "ruff>=0.4", "playwright>=1.40", "build>=1.0", "twine>=5.0"]
24
+ release = ["build>=1.0", "twine>=5.0"]
25
+
26
+ [project.scripts]
27
+ her = "her_sync.cli:app"
28
+
29
+ [build-system]
30
+ requires = ["hatchling"]
31
+ build-backend = "hatchling.build"
32
+
33
+ [tool.hatch.build.targets.wheel]
34
+ packages = ["src/her_sync"]
35
+
36
+ [tool.ruff]
37
+ line-length = 100
38
+ target-version = "py311"
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
4
+ cd "$ROOT"
5
+ PYTHON="${ROOT}/.venv/bin/python"
6
+ if [[ ! -x "$PYTHON" ]]; then
7
+ PYTHON="$(command -v python3)"
8
+ fi
9
+ exec "$PYTHON" "${ROOT}/scripts/release_cli.py" "$@"