mirror of
https://github.com/Second-Hand-Friends/kleinanzeigen-bot.git
synced 2026-10-09 15:21:20 +02:00
main
100
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
2f7695c136 |
chore: log page layout hints to debug Astro redesign issues (#1330)
## ℹ️ Description Adds debugging output that shows whether and how far a user is affected by the redesigned (Astro) Kleinanzeigen pages. - Related issue: #1329 (category selection fails with `No HTML element found with ID 'cat_185'`); no behavior change, diagnostics only. - Motivation: reporters currently only see the timeout message. Diagnostic HTML dumps may contain PII, so users hesitate to share them. ## 📋 Changes Summary - New `WebScrapingMixin.page_layout_summary()` returns URL, `astro-island` count, logged-in marker presence, offered `cat_*` IDs, category picker presence, viewport width and `readyState`. It never raises. - `set_category`: DEBUG log of the layout before selection; WARNING with the layout when a `cat_<id>` element is missing. - `has_logged_in_marker`: DEBUG log of the layout when no marker is found. - `_extract_island_props`: DEBUG log when no Astro island with ad data exists. - Publish diagnostics JSON (`capture_on.publish`) now contains `page_layout`, so no HTML dump is needed to tell the layouts apart. - German translation for the new warning, docs note in `CONFIGURATION.md`, unit test for the helper. Checked the probe against a live logged-in session: start page has 31 islands and the marker, the classic category page has 0 islands and lists `cat_185`. ### ⚙️ Type of Change - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) Diagnostics/logging only, none of the above applies. ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run utest`; `pdm run test` additionally launches real browsers and was not run locally). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Improvements** * Failed-publish diagnostics now include a page layout summary, helping distinguish redesigned pages from classic ones without including the full HTML. * Additional layout details are recorded when login checks or category selection encounter problems. * Added clearer German translations for category selection errors. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
b9daab1121 |
refactor: keep list help in the literal help text blocks (#1327)
## ℹ️ Description Follow-up to #1321. The CLI help text is the one place that keeps a complete English and a complete German text block in the code, so `list` belongs into both blocks instead of using a gettext lookup with a temporary locale switch. Related issue: none. ## 📋 Changes Summary - Write the `list` help line literally into the English and German blocks of `help_text()` and drop the locale switch and the `help_text` entry in `translations.de.yaml`. - Replace the locale-preservation test with a simple check of the `list` line per language. - Document the exception for the CLI help text in `CONTRIBUTING.md`. No dependencies or configuration changes. ### ⚙️ Type of Change - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) Refactoring only, no user-visible change: the help output is identical. ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run utest` locally, the full suite runs in CI). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * CLI help now displays the complete English or German text for the `list` command, regardless of the currently active language setting. * **Documentation** * Updated translation guidance to clarify that CLI help text should include complete English and German wording. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
e4bca13df3 |
fix: ignore stray slashes in configured category paths (#1316)
## ℹ️ Description Publishing hangs at category selection when the configured category path contains a stray slash. - Link to the related issue(s): Fixes #1314 - Since #1278 the bot no longer opens `p-kategorie-aendern.html#?path={category}` but clicks one `cat_<segment>` ID per path level. A trailing or doubled slash (e.g. `161/176/`) splits into an empty segment, so the bot waits for `cat_`, which never exists. That matches the `web_find(ID, cat_)` timeouts in the issue's log. The old deeplink tolerated such slashes, which is why it only broke after #1278. ## 📋 Changes Summary - `set_category` drops empty path segments before the alias check and the per-level clicks, so `161/176/`, `/80//87` etc. select the intended category. The cleaned path is also what the category-suggestion fallback receives. - Extended the existing category selection test with trailing- and double-slash cases; both fail on the previous implementation. - No dependency, configuration or generated-artifact changes; no translation changes. Not verified live: I don't know which category the reporter configured. The empty `cat_` ID in the log can only come from an empty path segment, though. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Category paths with leading, trailing, or repeated slashes are now handled correctly when selecting a category. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
541c556530 |
ci: squash-merge dependency PRs automatically (#1317)
## ℹ️ Description The automatic merge of dependency PRs always fails, so they have to be merged by hand. - Link to the related issue(s): none; seen on #1315 (and #1308 was merged manually) - The `dependabot-pr-auto-merge` and `pdm-pr-auto-merge` jobs call `gh pr merge --auto --rebase`, but the repository only allows squash merges (`allow_rebase_merge: false`, `allow_squash_merge: true`, `allow_auto_merge: true`). The job fails with `GraphQL: Merge method rebase merging is not allowed on this repository (enablePullRequestAutoMerge)`. ## 📋 Changes Summary - Both auto-merge jobs now use `gh pr merge --auto --squash`, the only merge method the repository allows. - No dependency or configuration changes. Auto-merge still waits for the required checks and reviews of the `main` ruleset; this only fixes the merge method. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Automatic dependency pull request merges now use squash merging instead of rebase merging. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
0aa0f738e6 |
fix: read the delete CSRF token from the redesigned manage-ads page (#1313)
## ℹ️ Description Deleting ads fails on the redesigned (Astro) "Meine Anzeigen" page because the bot only reads the CSRF token from `<meta name="_csrf">`, which that page no longer renders. With `delete_old_ads: AFTER_PUBLISH` the timeout even aborts the whole publish run after the new ad went online, so the old ad stays and remaining ads are not processed. - Link to the related issue(s): Fixes #1312, reported in #1279 (comment by @DreckSoft) - The redesigned page still carries the token inside the JSON `data-initialprops` attribute of `#consentBanner` as `webContext.csrfToken`. On a live classic page (which renders both) I verified that this value is identical to the meta token, and that `_csrf_header` is `X-CSRF-TOKEN`, i.e. the header the delete request already sends. ## 📋 Changes Summary - `delete_flow.delete_ad` reads the token with one `web_execute`: `meta[name=_csrf]` first, then `webContext.csrfToken` from any `[data-initialprops]` element (malformed props are skipped). It no longer waits through 3 × `web_find` timeouts when the meta tag is absent. - Missing token still fails with the existing "Expected CSRF Token not found in HTML content!" message, before any delete request is sent; no translation changes. - New integration test runs `delete_ad` in a real browser against offline classic and redesigned markup (sanitized from the #1279 sample) and asserts the `x-csrf-token` header that is sent. Against the previous implementation 5 of the 6 cases fail; only the classic one passes. - Unit tests now mock `web_execute` instead of `web_find`; added a no-token case. Removed a CSRF mock in `test_publishing_form.py` that was never reached. - No dependency or configuration changes. Verification beyond tests: ran the shipped JS on the live manage-ads page with the configured browser: classic page → meta token; meta tag removed in the DOM → identical token from `initialprops`; both removed → `null`. My account currently gets the classic layout, so a real delete on the redesigned layout is still unconfirmed; feedback from an affected account (#1312, #1279) is welcome. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved ad deletion across classic and redesigned pages by checking both supported CSRF token sources. Deletion stops without sending a request if no valid token is available. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
5b9d94d1f6 |
ci: fail the build when code is not formatted (#1307)
## ℹ️ Description *Fail CI when the code is not formatted with `pdm run format`.* - Link to the related issue(s): none - CI ran ruff, mypy and basedpyright but never checked formatting, so `tests/unit/test_extract.py` was merged unformatted with #1282 and every later `pdm run format` rewrote it (fixed in #1306). AGENTS.md lists `pdm run format` as the first validation step; CI now enforces it. ## 📋 Changes Summary - New build step "Check code formatting": runs `pdm run format` and fails with an error annotation if `git diff --exit-code` reports changes. - Runs once, next to the other single-runner checks (`ubuntu-latest`, Python 3.15); the formatter output does not depend on the OS. - Verified locally: on `main` before #1306 the step fails (the 794-line diff in `tests/unit/test_extract.py`); on current `main` it passes. The generated `_version.py` that `pdm run format` also touches is git-ignored, so it does not trip the check. - No dependencies or configuration changes. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) CI-only change. ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). — workflow-only change; the new step was simulated locally against `main` before and after #1306. - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). — including `actionlint` for the workflow. - [x] I have updated documentation where necessary. — no documentation affected. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Added a formatting check to the build workflow; the check fails if formatting changes are needed. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
f94deb92d0 |
style: format tests/unit/test_extract.py (#1306)
## ℹ️ Description *Apply `pdm run format` to `tests/unit/test_extract.py`.* - Link to the related issue(s): none - The file was merged unformatted with #1282 (e.g. `path: Path`, `encoding="utf-8"` instead of the repo's `path:Path`, `encoding = "utf-8"`). Since CI has no format check, every later `pdm run format` rewrites it, so contributors either commit an unrelated 800-line diff or have to revert it by hand (as in #1298, #1299, #1304, #1305). ## 📋 Changes Summary - `pdm run format` output for `tests/unit/test_extract.py` only. - Whitespace-only: `git diff -w` is empty (794 lines touched, 0 changed when ignoring whitespace). - No dependencies or configuration changes. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) Formatting only (no behaviour change). ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). — 1768 passed, 5 skipped. - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. — no documentation affected. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. |
||
|
|
86ae143cd9 |
fix: open the ad overview on its first, unfiltered page (#1304)
## ℹ️ Description *Open the ad overview on its first, unfiltered page instead of the page and search restored from the browser tab.* - Link to the related issue(s): Fixes #1302 - The ad overview (`m-meine-anzeigen.html`) restores the UI-stored query parameters `pageNumber` and `keyword` from `sessionStorage` (`queryParams`) whenever its URL does not set them. In a tab that has paged before, opening the plain URL therefore starts on a later page. There the "Nächste" button is disabled, so the bot treats that page as the only one: - `download --ads=new|all` misses every ad on the earlier pages (#1302: 44 ads, 25 per page, the bot saw only the 19 ads of page 2), - `extend`/`reserve`/`activate` report ads on the earlier pages as missing, - `update` (reaching the overview through the site navigation, #1278) fails with "Could not reach edit form" for an ad on an earlier page once a previous edit in the same run paged forward. A stored search keyword filters the overview the same way. `sort` is not affected: the page adds a default `sort` to every URL lacking one. ## 📋 Changes Summary - New domain module `ad_overview.py`: the overview parameters the page restores and `first_page_url()`; `navigate_paginated_ad_overview` opens the overview with `pageNumber=1&keyword=`, keeping other query parameters (download and bulk actions). - New `WebScrapingMixin.reset_ad_overview_state()` drops only the stored `pageNumber` and `keyword` from `sessionStorage`; `open_ad_for_edit` calls it before the navigation click, keeping the click path from #1278 intact. A missing or unreadable entry is left untouched; a `TimeoutError` is reported as a warning and the navigation continues as before. - Tests: the URL pinning is covered for the default URL, existing parameters and a stale `pageNumber`/`keyword`. The bulk-action overview fake now behaves like the real page (starts on the last viewed page unless the URL sets `pageNumber`), which fails without the fix. `open_ad_for_edit` asserts the reset happens before the navigation clicks. A new integration test runs the reset against real `sessionStorage` in the shared integration-test browser (#1305) on an offline file page; it fails when the script stops deleting the keys. - No new dependencies or configuration changes. **Verified against the live site** (an account with 2 ads, `?pageSize=1` to get two pages; nothing was saved, `sessionStorage` restored afterwards): | Situation | Overview requests | Result | |---|---|---| | click "Nächste" | stores `pageNumber: 2` | – | | reopen plain URL (bot before fix) | `pageNum=2` | "Nächste" disabled, treated as single page | | reopen with `?pageNumber=1` (after fix) | `pageNum=1` | normal pagination | | stored keyword, `?pageNumber=1` only | `keyword=…` kept | 0 ads | | stored keyword, `?pageNumber=1&keyword=` | no keyword | all ads | | `open_ad_for_edit` with stored page 2, without reset | – | "Could not reach edit form" | | `open_ad_for_edit` with stored page 2, with reset | – | edit form of the ad on page 1 | **Open question for the reporter:** how the stale page got into a fresh bot run is not verified. `sessionStorage` only survives a restart when Chromium restores the last session; the reported config sets `--restore-last-session=false`, and Chromium may treat that switch as present (= enabled). The fix does not depend on where the stored state comes from. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). — 1768 passed, 5 skipped. - [x] I have formatted the code (`pdm run format`). — it leaves the changed files unchanged; its unrelated rewrite of `tests/unit/test_extract.py` (already unformatted on `main`) is not part of this PR. - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. — no user-facing documentation affected. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. |
||
|
|
52637ba421 |
test: share one browser across the browser integration tests (#1305)
## ℹ️ Description *Share one browser across the browser integration tests instead of starting one per test case.* - Link to the related issue(s): none - Every browser integration test started its own Chromium, and each parametrized case started another one: **10 browser starts per run**, 9 of them visible windows (`test_init`, 2× `test_logged_in_marker_…`, 6× `test_narrow_viewport_warning_…` run without `--headless`; only `test_visible_field_errors_…` was headless). Starting Chromium is the slowest and flakiest part of these tests. All of them only load offline HTML and emulate viewport widths through CDP, so one session per run is enough. ## 📋 Changes Summary - New `tests/integration/conftest.py`: - session-scoped `browser_session` fixture: starts the browser once with the bot's default launch configuration (plus `--no-sandbox` on Linux, as before) and retries `Failed to connect to browser` up to 5 times with a 10 s delay — the same budget as the former per-test `flaky` reruns; cleanup between attempts is best effort. - function-scoped `web` fixture: hands each test the shared session on a freshly loaded `about:blank` with the device metrics override cleared. - `test_narrow_viewport_warning_matches_mobile_layout_threshold` (6 cases) is removed: its threshold check compared `MIN_VIEWPORT_WIDTH` with a breakpoint hand-written into the same fixture, so it could not detect a change on the live site, and the warning logic is fully covered by unit tests (`tests/unit/test_web_scraping_mixin.py`). Its only browser-specific check — the measured width equals the emulated one — moved into `test_logged_in_marker_…`, which already emulates 390 and 1024 px. - `test_web_scraping_mixin_integration.py` and `test_publishing_validation.py` use the `web` fixture and run on the session event loop (`asyncio(loop_scope = "session")`); their assertions are unchanged. `test_init` now checks browser detection and the started session. - `test_publishing_validation.py` no longer uses its own headless, temporary-profile browser; it runs in the shared session like the others and still only writes offline HTML into `about:blank`. - No dependencies or configuration changes; CI still runs these tests with `--workers 0` (under `xvfb-run` on Linux). Result: **1 browser start instead of 10**, and 5 instead of 11 browser test cases; `pdm run itest` 5 passed in ~6 s locally. The tests also pass in reversed order, so they do not depend on state left by each other. With `pdm run test` (xdist) each worker that picks up integration tests starts at most one browser. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) Test-only change (no user-facing behaviour). ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). — 1762 passed, 5 skipped; `pdm run itest` 5 passed; with the shared session the tests also passed in reversed order. - [x] I have formatted the code (`pdm run format`). — it leaves the changed files unchanged; its unrelated rewrite of `tests/unit/test_extract.py` (already unformatted on `main`) is not part of this PR. - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. — no documentation affected. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. |
||
|
|
7ecd44dc1f |
feat: warn when the browser viewport is too narrow for the desktop layout (#1293)
## ℹ️ Description
- Link to the related issue(s): #1279 (Astro redesign tracking);
follow-up to #1283 /
|
||
|
|
7f5c59b9e0 |
chore: Update Python dependencies (#1291)
## ℹ️ Description Routine maintenance update of the locked Python dependencies. - Link to the related issue(s): _none — recurring dependency maintenance, same as #1275, #1269, #1266_ - Motivation and context: keeping `pdm.lock` in sync with current upstream releases so local runs, CI and the PyInstaller builds resolve the same, up-to-date packages instead of drifting behind. ## 📋 Changes Summary - `pdm.lock`: update `platformdirs` 4.11.11 → 4.11.12 (version pin plus the wheel and sdist SHA256 hashes). Notes: - `pyproject.toml` is untouched — `platformdirs` is a transitive dependency in the `default` and `dev` groups, so no declared version constraint changes. - No configuration changes and no new requirements for users. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) None of the above applies: this is non-breaking dependency maintenance (a patch-level bump of a transitive dependency) with no change to CLI behavior, config, or generated artifacts. ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`) — 1668 passed, 5 skipped, total coverage 93.25%. - [x] I have formatted the code (`pdm run format`) — no files changed. - [x] I have verified that linting passes (`pdm run lint`) — ruff, mypy (117 source files), pyright and actionlint all clean. - [x] I have updated documentation where necessary — not applicable, no user-facing or documented behavior changes. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. |
||
|
|
94544e4883 |
fix: follow click navigation when editing ad categories (#1278)
## ℹ️ Description Editing an ad can fail with HTTP 400/403 when the bot reloads the category-selection page directly. Follow the site's navigation to retain the edit context: homepage → Meins → Meine Anzeigen → edit → category selection → Weiter. Related issue: none; reported and reproduced during live browser diagnosis. The complete click path returned HTTP 200 with the configured category; the server's exact rejection mechanism is not established. ## 📋 Changes Summary - Open existing ads through their edit links in the paginated management overview. Restart this navigation on pre-submit retries. - Prefer the category-change anchor over an ambiguous category text match, then click each numeric or text category ID without loading a category deeplink. - Reject unresolved category aliases with a translated, non-retryable error before attempting category clicks. - Resolve offered category suggestions when a configured category link is missing; retain the original timeout if no picker is rendered. - Allow the existing overview pagination helper to operate on a page already reached through navigation. - Add regression coverage for numeric/text category paths, ads on later pages, missing ads (including page 11 coverage), and preservation of the current overview. No dependencies, configuration, or generated artifacts change. The edit-navigation timeout now has a German translation. New-ad entry remains unchanged; its category picker uses the same click selection. ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`: 1647 passed, 5 skipped). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary (no user-facing setup or command changes). Live validation: ran the modified bot's edit-opening and category-selection functions using the existing bot Chromium profile and launch parameters, stopping before saving. Independently verified with agent-browser that the returned form had `Haus & Garten > Weiteres Haus & Garten` and HTTP 200. Automated tests do not contact kleinanzeigen.de. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Improvements** * Editing an existing ad now reliably navigates through the “My Ads” overview to locate and open the correct listing. * Category selection during ad publishing stays within the current form session, helping preserve entered information. * Overview navigation can now continue from the current page without unnecessary reloads. * **Bug Fixes** * Invalid category aliases are detected before browser navigation, with clearer error messages when category selection or edit-form navigation fails. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
250a857771 |
fix: make login entry an explicit choice (#1276)
## ℹ️ Description Make the login entry an explicit user choice. The existing direct `/m-einloggen-sso.html` route remains the default (`login.entry_mode: SSO`). Users can opt in to homepage **Meins → Meine Anzeigen** navigation with `login.entry_mode: NAVIGATION`. The SSO route was introduced to avoid login-page JavaScript issues in headless browsers. Preserve that behavior for existing configurations; browser/headless mode never selects or changes the route automatically. Related issue: #1274 (closed by its author; this PR adds the requested alternative without claiming to resolve IP-range blocks). ## 📋 Changes Summary - Add `login.entry_mode` with supported values `SSO` (default) and `NAVIGATION`. - For NAVIGATION, dismiss the optional welcome popup and click Meins → Meine Anzeigen using selectors verified against the live DOM. - Preserve session pre-checks, navigation-timeout diagnostics, and the existing Auth0 credential flow for both routes. - Test both explicit modes with visible/headless browser arguments, popup handling, invalid configuration values, and timeouts on either route. - Document the option and regenerate the config schema and default YAML. No new dependencies or changed runtime messages. Validation: `pdm run format`, `pdm run lint`, `pdm run test`, and generated-artifact verification passed. Tests ran outside the sandbox because the pytest plugin requires a local socket. Manual browser verification reached the Auth0 identifier and password pages through the navigation route. Both submit buttons matched the existing bot selector. After password submission, Kleinanzeigen returned **IP-Bereich vorübergehend gesperrt**; successful post-login navigation and session detection remain unverified. Neither route guarantees avoidance of IP-range blocks. Manual inspection used agent-browser with Chrome for Testing; the effect of browser choice has not been isolated. ### ⚙️ Type of Change - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [x] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added configurable login entry modes: direct SSO or homepage navigation through the account menu. - SSO remains the default and works independently of headless browser settings. - Added support for automatically handling the welcome popup during homepage-based login. - **Documentation** - Documented the new login setting and added it to the default configuration. - **Tests** - Added coverage for both login routes, popup behavior, navigation failures, and configuration validation. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
b2806e226e |
fix: use PDM interpreter in generation and formatting scripts (#1277)
## ℹ️ Description `pdm run generate-artifacts` could fail while creating the default config when the shell's `python` differed from PDM's selected interpreter. For example, Python 3.13 on PATH loaded dependencies from `__pypackages__/3.12`, causing `ModuleNotFoundError: pydantic_core._pydantic_core`. Use PDM's interpreter consistently for config generation and Python post-formatting. This fix is independent of login-entry PR #1276. ## 📋 Changes Summary - Replace the shell-based config generator with a Python script that invokes the CLI through `sys.executable`. - Split `format:py` into a PDM composite so the Python post-formatter also uses PDM's interpreter. - Add an integration regression test that regenerates the exact config snapshot with an unusable Python executable on PATH. - Preserve supported Python versions, CLI generation behavior, and generated artifacts. No dependency or user-configuration changes; no documentation updates needed. Validation: `pdm run format`, `pdm run lint`, `pdm run test`, `pdm run generate-artifacts`, and generated-artifact verification passed. The generator was also verified locally with PDM selecting Python 3.12 while shell Python resolves to 3.13. ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary (no documentation changes required). By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Improved the configuration generation workflow by using the active Python environment directly. * Split Python formatting into separate automatic formatting and follow-up processing steps for more consistent results. * **Tests** * Added integration coverage to verify configuration generation works reliably even when conflicting Python executables are present on the system path. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
387d2eb153 |
refactor: modernize async timeout and deadline handling (#1273)
## ℹ️ Description Browser polling previously checked elapsed time only between polls, so a hanging browser call could exceed its timeout indefinitely. This refactor uses absolute operation deadlines and native asyncio timeout contexts while preserving configured retry and login phase budgets. Closes #1236. ## 📋 Changes Summary - Carry absolute deadlines through retry attempts and selector alternatives; bound page readiness, predicates, reattachment, and navigation. - Replace login and browser-process `wait_for` calls with timeout contexts, preserving phase durations, backoff, timing records, logs, and existing errors. - Propagate external cancellation without additional retries or login fallbacks, and clean up owned browser resources without starting fresh shutdown waits after cancellation. - Document the timeout inventory, caller-owned total budgets, and intentional navigation/polling changes in `docs/ASYNC_TIMEOUTS.md`; narrow the global `ASYNC109` suppression to existing browser adapters and corresponding test doubles. - Await browser target refresh directly, avoiding nodriver's hidden half-second pause and detached refresh tasks; document zero-budget expiry at the first asynchronous suspension. - Add behavior tests for hanging operations, parent deadlines, cancellation, selector fallback, startup cleanup, and shutdown, including real nodriver Tab regressions. No dependencies, configuration defaults, or generated artifacts change. Startup retains its existing lack of a default total timeout; callers can supply an enclosing deadline. Viewport adjustment remains outside the page-load budget. Validation: `pdm run format`, `pdm run lint` (Ruff, mypy, basedpyright, actionlint), and `pdm run test` all pass: **1,633 passed, 5 skipped**. Tests use fakes or local fixtures and do not contact kleinanzeigen.de. Independent review passed after fixing and retesting both identified nodriver deadline issues. ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved timeout handling so nested browser operations respect their overall time limits. * Improved cancellation behavior and cleanup during browser startup, navigation, and shutdown. * Preserved external cancellation and underlying navigation timeout errors without unnecessary retries. * Improved handling of malformed or incomplete HTTP responses. * **Documentation** * Added documentation for browser timeouts, cancellation behavior, retry policies, and operation deadlines. * Linked the new timeout guidance from contributor documentation. * **Refactor** * Updated login verification timeout handling while preserving existing behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
2a311576ed |
refactor: use asyncio.to_thread for blocking operations (#1272)
## ℹ️ Description Replace default-executor dispatch with `asyncio.to_thread()` for ordinary blocking work, simplifying calls and propagating the caller's context variables. Closes #1238. ## 📋 Changes Summary - Convert all 19 production `run_in_executor()` calls: 14 in extraction, one timing flush, two browser-profile operations, and two filesystem helpers. None require a custom executor or explicit Future handling. - Pass keyword arguments directly where possible. Keep compound glob and model-serialization operations inside worker threads. - Preserve sequential downloads, ordering, exception propagation, cancellation handling, rollback, cleanup, and log messages. - Extend save-failure coverage to timeouts and verify original contents survive; test worker context propagation and isolation. - No dependencies, configuration, translations, or generated artifacts need updating. ### ⚙️ Type of Change Internal behavior-preserving refactor; none of the feature/fix/breaking-change categories apply. - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary (no documentation changes needed). By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Improvements** * Improved asynchronous handling for file operations, downloads, cleanup, browser profile preparation, and timing collection. * Preserved existing behavior and error handling while maintaining task context across asynchronous file checks. * **Tests** * Expanded coverage for YAML-write failures involving operating system and timeout errors. * Added validation that asynchronous file existence checks preserve task context. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
98ad45b62b |
fix: skip null auto price reduction when downloading ads (#1271)
## ℹ️ Description Re-downloading an ad with `auto_price_reduction: null` currently emits a preservation warning because the downloader attempts to convert `None` into a dictionary. Treat this normal unset value like a missing key and silently skip it while preserving other valid local settings. Closes #1250. ## 📋 Changes Summary - Skip APR preservation when the existing value is absent or null. - Extend download tests for missing, null, empty-disabled, and enabled APR settings through direct file lookup and the filename fallback. - Verify that malformed non-null APR values still warn and other local settings remain preserved. - No dependency, configuration, schema, documentation, or translation changes are required. Validation: the two null regression cases failed before the fix. After the fix, `pdm run format`, `pdm run lint`, and `pdm run test` pass (1612 passed, 5 skipped). ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary (not required for this fix). By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Existing advertisements with an explicitly empty `auto_price_reduction` setting are now handled correctly. * Local settings preservation no longer attempts to reuse unavailable price-reduction values. * Clearer warnings are provided when an invalid price-reduction configuration cannot be preserved. * **Tests** * Expanded coverage for missing, empty, disabled, valid, and incomplete price-reduction settings. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
3d1a355c77 |
perf: traverse the ad overview once for bulk actions (#1270)
## ℹ️ Description Closes #1265. Bulk `extend`, `reserve`, and `activate` currently restart the manage-ads overview at page 1 for every eligible ad. They now share one traversal, processing all selected rows on each page and stopping when every requested entry has been handled or pagination ends. This reduces repeated overview loads for accounts with many ads. ## 📋 Changes Summary - Add a shared bulk-action coordinator that tracks pending IDs and resolves each action button on the current page. - Preserve per-entry progress/results, action delays, duplicate configuration entries, timeout handling, extension metadata persistence, and strict reservation-state verification. - Move German translations to the new logging locations and adapt existing flow tests. - Add 21 browser-independent regression cases covering all three commands, multiple rows/pages, early completion, missing IDs, click/open timeouts, duplicate entries, empty selections, and persisted file behavior. No dependencies, configuration changes, or additional requirements are introduced. No user documentation changes are needed for this internal performance improvement. Tests use simulated pages and never contact kleinanzeigen.de. Validation: `pdm run format`, `pdm run lint`, and `pdm run test` all pass; the full suite reports **1,605 passed, 5 skipped**. ### ⚙️ Type of Change - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) - [x] ⚡ Performance improvement (reduces repeated overview navigation without changing CLI usage) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary (no documentation changes needed). By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added unified bulk processing for extension, reservation, and activation actions across paginated ad listings. - Improved handling and reporting of ads whose action buttons cannot be found. - Added German translations for shared bulk-action messages. - **Bug Fixes** - Reduced repeated page traversal during bulk ad operations. - Improved reliability when action buttons time out or are unavailable. - **Tests** - Added and updated coverage for pagination, successful actions, timeouts, missing buttons, and ad updates. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
a1f000664f |
enh: continue downloading after individual ad failures (#1262)
## ℹ️ Description - Link to the related issue(s): Issue #1259 - Continue a download batch when navigation or extraction fails for one ad, so remaining ads are still attempted. ## 📋 Changes Summary - Isolate navigation and download failures per ad for all, new, and numeric-ID selectors. - Log failed ads with tracebacks and emit a unified success/failure summary. - Preserve task cancellation and add behavior-focused coverage for continuation after failures. - No dependencies, configuration changes, or additional requirements were introduced. ### ⚙️ Type of Change - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [x] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (pdm run test). - [x] I have formatted the code (pdm run format). - [x] I have verified that linting passes (pdm run lint). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Downloads now continue for remaining ads when an individual ad encounters a navigation or download failure. * Cancellation requests are preserved instead of being treated as ordinary download failures. * Download results now provide a consistent summary, including successful and failed items. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
7749b65f18 |
fix: remove unused shipping selectors (#1261)
## ℹ️ Description Removes obsolete shipping-dialog XPath selector constants that CodeQL reports as unused globals. - Link to the related issue(s): N/A - The CSS and text-based selector migration left these unused declarations and implementation-specific test assertions behind. ## 📋 Changes Summary - Remove three unused XPath selector constants from the publishing form. - Remove stale test imports and assertions for the retired XPath path. - No dependency or configuration changes. ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (pdm run test). - [x] I have formatted the code (pdm run format). - [x] I have verified that linting passes (pdm run lint). - [ ] I have updated documentation where necessary. (Not needed: no user-facing behavior changed.) By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. |
||
|
|
0705063fe9 |
fix: preserve decoded Astro island props (#1260)
## ℹ️ Description - Link to the related issue(s): Fixes #1255 - `astro-island` props returned by browser `getAttribute("props")` are already HTML-decoded. Applying `html.unescape()` first can corrupt entity-like content inside otherwise valid JSON strings and prevent the Astro fallbacks from receiving ad data. ## 📋 Changes Summary - Parse the browser-returned props value with `json.loads()` before attempting HTML unescaping. - Retain `html.unescape()` as a compatibility fallback for responses that still contain HTML entities. - Add a regression test covering an entity-like quoted phrase in a decoded description. ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved extraction of listing details containing entity-like text, such as `"`, preserving the original content. * Added safer handling for invalid or unexpected island properties, returning an empty result when necessary. * **Tests** * Added coverage to verify descriptions with entity-like content are parsed correctly. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
c98d6f3192 |
fix: show ad file path in validation errors (#1253)
## ℹ️ Description - Link to the related issue(s): Fixes #1252 - Ad-validation errors now identify the source YAML/JSON file, so users can locate invalid titles or descriptions immediately. ## 📋 Changes Summary - Pass each discovered ad file path through both validation stages. - Add regression tests for overlong titles, descriptions, and final-model validation errors. - No dependencies, configuration, or generated artifacts changed. ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. |
||
|
|
a3ce63afe0 |
fix: handle idless update confirmations (#1244)
## ℹ️ Description - Related issue: #1228 - Handles the redesigned ID-less success page when an existing listing is updated. ## 📋 Changes Summary - Recognize the existing ID-less success-page marker for updates as well as publishes. - Reuse the configured listing ID for a confirmed update; do not attempt publish-style new-ID recovery. - Preserve the strict published-ads recovery path for replacement publishes. - Add German translation coverage and a focused unit test. ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] Documentation changes are not needed for this internal recovery-path fix. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved publishing and updating reliability for redesigned confirmation pages that do not display an ad ID. * Updates now use the configured ad ID when available and report uncertainty when it is missing. * New listings recover their ad ID from published listings and report uncertain outcomes when recovery fails or is ambiguous. * Added German messaging for updates confirmed without a displayed ad ID. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
92da5f7c70 |
fix: support ptrace-restricted browser containers (#1242)
## ℹ️ Description - Link to the related issue(s): Fixes #1240 - Allow ptrace-restricted Docker and LXC users to omit Chromium's `--test-type` startup flag while preserving the existing default for other users. ## 📋 Changes Summary - Add `browser.suppress_unsupported_flag_warning`, defaulting to `true`. - Warn in recognized Linux containers without `CAP_SYS_PTRACE` when the flag remains enabled. - Document the container configuration, regenerate config artifacts, and cover default, opt-out, runtime propagation, and Linux-specific behavior. ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added a browser setting to control Chromium warning suppression, enabled by default. - Added support for disabling the setting in ptrace-restricted Docker or LXC containers to help browser startup succeed. - Added diagnostics and warnings for environments missing the required system capability. - **Documentation** - Documented the new setting, container limitations, and configuration guidance. - **Tests** - Added coverage for configuration validation, container detection, capability handling, and browser launch warnings. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
c966252da5 |
fix: use Python 3.12 for local act runs (#1241)
## ℹ️ Description - Follow-up to #1235. - Align local `act` runs with Python 3.12, the stable minimum version used for local development, release artifacts, and Docker builds. ## 📋 Changes Summary - Select the Ubuntu/Python 3.12 build-matrix entry in `.actrc`. - Keep Python 3.15 prerelease compatibility testing in the full GitHub Actions matrix. - Introduce no dependency or runtime changes. ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. Validation details: - 1507 tests passed, 4 skipped - 93.07% total coverage - `.actrc` selects an existing `ubuntu-latest` / Python 3.12 matrix entry - The `act` executable was not available for a local dry run By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. |
||
|
|
f4b4e0fdf6 |
enh: support Python 3.12 through 3.15 (#1235)
## ℹ️ Description - Closes #1226 - Raise the supported Python range from 3.10–3.14 to 3.12–3.15 before Python 3.10 reaches end of life. - Modernize the codebase with behavior-preserving Python 3.11 and 3.12 idioms while keeping CLI, configuration, persistence, and browser behavior stable. ## 📋 Changes Summary - Set `requires-python` and the PDM lock target to `>=3.12,<3.16`. - Test Python 3.12 and Python 3.15 prereleases across all supported CI platforms. - Build and publish native release artifacts and Docker images with stable Python 3.12; keep Python 3.15 as compatibility-only coverage until its final release. - Update CodeQL, dependency updates, local Act configuration, Ruff, mypy, BasedPyright, README, CONTRIBUTING, and AGENTS guidance. - Enable Ruff's `UP` rules and adopt applicable standard-library imports, `datetime.UTC`, built-in `TimeoutError`, PEP 695 type aliases and generic syntax. - Replace deprecated `shutil.rmtree(onerror=...)` usage with Python 3.12's `onexc` callback API and update its tests. - Regenerate `pdm.lock` for the full supported interpreter range and integrate the latest dependency updates from `main`. ### ⚙️ Type of Change - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [x] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. Validation details: - 1507 tests passed, 4 skipped - 93.07% total coverage - Generated schemas, default configuration, and README usage are up to date - Source CLI and PyInstaller binary smoke checks passed - Local PyInstaller build and binary smoke checks passed on Python 3.12.14; Python 3.12/3.15 platform coverage is delegated to the updated CI matrix By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added support for Python 3.12 through 3.15. * Improved compatibility with modern Python typing and datetime APIs. * **Bug Fixes** * Improved timeout handling and directory cleanup behavior. * Enhanced update-checking and web-scraping reliability. * **Documentation** * Updated installation and contribution requirements to Python 3.12–3.15. * **Tests** * Expanded coverage for update checks, timeout messages, and edge cases. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
7b31dddb49 |
fix: harden publishing against DOM variants (#1229)
## ℹ️ Description - Closes #1227 - Closes #1228 - Hardens publishing against Kleinanzeigen A/B variants observed in the shipping dialog and confirmation flow. - Prevents duplicate listings when a successful publish page no longer exposes an ad ID, while preserving the existing update flow. The shipping dialog can either open directly on package sizes or require "Andere Versandmethoden", and may retain a nested pane from earlier state. Separately, the redesigned success page may show "Geschafft!" and "Zu meinen Anzeigen" without an ID in the URL. Owned deleted ads can also expose a decorated page title when canonical manage-ads metadata is unavailable. ## 📋 Changes Summary - Detect direct package-size panes before using "Andere Versandmethoden". - Bound shipping-dialog back navigation to two steps and fail clearly for unsupported states. - Capture a strict pre-submit published-ad baseline for replace operations. - Recover an ID-less successful publish only when exactly one new exact-title ID appears, with bounded delayed retries. - Fail closed on incomplete or ambiguous recovery and retain the no-retry submit boundary. - Strip the verified `Gelöscht • ` decoration only for owned-overview page-title fallback; canonical API titles and manual downloads remain unchanged. - Add German translations and focused unit coverage for all new branches. - No configuration changes or new dependencies. ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Validation - `pdm run format` - `pdm run lint` - `pdm run test` — 1501 passed, 4 skipped - Live managed-browser republish: - exercised the "Andere Versandmethoden" shipping route - synchronized both configured carriers - persisted the new ID - deleted the exact old ID - verified the refreshed overview contained only the new listing - Local DOM verification helper was updated for diagnostics but remains ignored and is not part of this PR. ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved downloads from owned-ad overviews by removing deleted-status prefixes from saved titles. * Improved shipping setup navigation across nested dialogs and alternative shipping methods. * Recovered newly published ads when confirmation pages do not display an ad ID. * Added safeguards to prevent duplicate or ambiguous publication recovery. * **Tests** * Expanded coverage for owned-ad downloads, shipping navigation, and publication recovery scenarios. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
72538edaee |
fix: support redesigned shipping dialog actions (#1224)
## ℹ️ Description - Link to the related issue(s): N/A - Make the shipping-options flow resilient to Kleinanzeigen rendering “Andere Versandmethoden” as a button, link, span, or another clickable wrapper. - The previous XPath required a `<button>`, although the redesigned UI may use different element types. ## 📋 Changes Summary - Scope the action lookup to an open or visible shipping dialog. - Select the deepest text-bearing “Andere Versandmethoden” node so its click bubbles to the current clickable ancestor. - Reuse the selector during modify-mode back navigation. - Add regression coverage for tag-agnostic dialog interaction. - No dependencies or configuration changes. ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`: 1494 passed, 4 skipped). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary (not applicable; no user-facing configuration or workflow changes). By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved “Andere Versandmethoden” selection to be tag-agnostic and avoid duplicate/nested matches. * Added a back-and-retry flow when the desired shipping option isn’t available on the current dialog step. * Updated the final selection to click the deepest matching text element within the dialog. * **Tests** * Added regression tests covering tag-independent dialog actions and retry navigation behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
172aa61e6e |
fix: await browser session cleanup (#1223)
## ℹ️ Description - Link to the related issue(s): N/A - Fixes noisy asyncio teardown errors after the test suite by waiting for nodriver websocket tasks and the Chromium subprocess to finish before the event loop closes. - The root cause was `Browser.stop()` scheduling asynchronous connection cleanup without awaiting it; under fast pytest-xdist teardown, keepalive/listener tasks survived until logging capture had already closed. ## 📋 Changes Summary - Make browser-session cleanup await nodriver connection shutdown and Chromium process exit. - Retain best-effort synchronous cleanup for object destruction, where awaiting is impossible. - Convert the Chromium integration test to pytest-managed async execution and update affected mocks/unit tests. - Let pytest own test logging handlers so late teardown records do not leak into progress output. - Isolate terminal-color tests from ambient `NO_COLOR`/`FORCE_COLOR` settings. ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`: 1,489 passed, 4 skipped). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary (no documentation changes required). By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved browser-session shutdown to use async teardown, including reliable cleanup on normal exit and exceptions. * Enhanced browser-process termination handling with configurable timeouts, forced child-process cleanup, and safer exception handling during viewport sizing. * **Tests** * Updated unit and integration tests to await browser-session cleanup and align mocks with async behavior. * Expanded async test coverage for process-exit waiting, timeout/kill paths, and resilient teardown edge cases. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
a2d3fe3ed2 |
fix: decode cached download titles (#1218)
### Motivation - The cached JSON title from `published_ads_by_id` could contain HTML entities (e.g. `/`, `'`, `"`) and was returned stripped but not decoded, causing encoded text to be stored in YAML, used for filename rendering, and to inflate visible-length checks. - The goal is to decode only cached JSON titles before validation and filename rendering while preserving the existing page-title fallback and filename sanitization behavior. - closes #1215 and #1217 ### Description - Apply `html.unescape()` to the stripped cached title returned from `_resolve_download_title()` so cached titles are decoded before further processing. (`src/kleinanzeigen_bot/extract.py`). - Add focused unit tests to cover entity decoding and the length-validation regression: `test_resolve_download_title_decodes_published_metadata_entities` and `test_cached_title_entities_are_decoded_before_title_validation` (`tests/unit/test_extract.py`). - Keep the page-title fallback and all existing filename sanitization/validation logic unchanged, and only decode the cached JSON title path. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Cached advertisement titles now correctly decode HTML entities. * Decoded titles are validated and safely handled when generating file and directory names, preventing encoded entities or raw slashes from appearing in saved paths. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
a504622819 |
fix: narrow stale node protocol error handling (#1214)
## ℹ️ Description - Link to the related issue(s): Follow-up to #1209 - Restrict login detection’s `ProtocolException` recovery to the observed stale-DOM-node error so unrelated CDP failures propagate instead of starting unnecessary SSO automation. ## 📋 Changes Summary - Classify only the known stale-node CDP error by code and message. - Preserve timeout and known stale-node fallback behavior at all login detection boundaries. - Re-raise unrelated protocol errors and add focused regression coverage. - No dependency, configuration, or API changes. ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project’s standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. (No documentation change needed.) By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved login-state detection when temporary “stale node” browser errors occur. * Prevented these transient errors from incorrectly interrupting login checks. * Preserved error reporting for unrelated protocol errors. * **Tests** * Added coverage for stale-node recovery and unrelated protocol error handling. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
cf6662dd26 |
fix: require strict fetch for title cleanup (#1206)
## ℹ️ Description - Link to the related issue(s): Issue # - Fixes a remaining fail-closed gap in BEFORE_PUBLISH title cleanup for ID-less ads when the published-ad list cannot be fetched completely. ## 📋 Changes Summary - Require an additional strict published-ad fetch when BEFORE_PUBLISH title cleanup may match by title for ID-less ads. - Fail closed for ID-less publish candidates if strict published-ad fetch is incomplete, before submit/delete actions. - Keep ID-based candidates on the normal published-ad list so they can continue safely. - Add regression tests for strict-fetch usage and fail-closed behavior. - Add German translations for the new log messages. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. Validation performed locally: - `pdm run pytest tests/unit/test_publishing_workflow.py tests/unit/test_delete_flow.py` - `pdm run format` - `pdm run lint` - `pdm run test` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Enhanced publishing workflow to use more precise “published ad” data when title-based cleanup is enabled, improving match-and-replace behavior. * **Bug Fixes** * Publishing now fails safely when strict published-ad data is incomplete, avoiding retries and deletion actions when precision can’t be guaranteed. * For ads lacking a known identifier, the workflow intelligently selects the best available published-ad list or skips with a warning when strict data is unavailable. * **Tests** * Added unit test coverage for strict-vs-non-strict published-ad fetching scenarios and fail-closed behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
819d039b71 |
fix: persist created_on on first publish (#1204)
## ℹ️ Description - Link to the related issue(s): Issue # - Fixes first-publish persistence so newly published ads write `created_on` when missing. ## 📋 Changes Summary - Capture first-publish state before writing the new ad ID. - Persist one publication timestamp to both `updated_on` and missing first-publish `created_on`. - Add regression tests for first publish with an already-populated ad ID and update preservation of existing `created_on`. - No dependency, configuration, or generated artifact changes. ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved publish timestamp handling so first-time publishes and later updates record dates consistently. * Preserves the original creation date when it already exists, while keeping the last-updated time current. * **Tests** * Added coverage for timestamp behavior on first publish and subsequent updates. * Verified date values are stored in ISO-8601 format with timezone information. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
9cffbf6e8d |
fix: fail closed on persistence errors (#1203)
## ℹ️ Description - Link to the related issue(s): No linked issue; follows the confirmed P1 from `.slim/deepwork/p1-p2-validation.md`. - Prevent publish/update workflows from reporting success or running after-publish cleanup when local YAML persistence fails after a remote submit succeeds. ## 📋 Changes Summary - Add a non-retryable `PostPublishPersistenceError` carrying the remote ad ID. - Raise that error after logging post-submit local persistence failures. - Count persistence failures as failed publish/update items and skip post-submit confirmation / `AFTER_PUBLISH` cleanup. - Add tests for direct persistence failure, publish cleanup-skip behavior, and update non-retry/batch continuation. - Add German translations for the new warnings. ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved handling of post-publish save failures so they’re surfaced as a clear error instead of being silently logged. * Publishing and updating now stop retrying when local persistence fails after a successful remote action, while still logging details and capturing diagnostics. * Other retry behavior for existing publish issues remains unchanged. * **Tests** * Added and updated coverage for persistence failures, including error propagation, logging, and workflow behavior across multiple items. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
077c5db01b |
fix: prevent ambiguous title deletes (#1202)
## ℹ️ Description - Link to the related issue(s): Issue # - Prevent title-based deletion from deleting multiple same-title remote ads. - Make explicit ID deletion target only the configured ID, while ID-less title matching now fails closed on ambiguous matches. ## 📋 Changes Summary - Split delete selection so configured IDs are exact-ID only and title matching is only used for ID-less ads. - Require strict published-ad fetching when ID-less title matching may run, so ambiguity detection uses a complete list. - Skip ambiguous title matches before browser delete requests, ID mutation, or after-delete cleanup. - Added German translation for the new skip message. - Updated config/docs/generated schema wording for `delete_old_ads_by_title`. - Added unit coverage for ambiguous title fail-closed behavior, exact-ID behavior, strict fetch selection, and exact delete URLs. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. Validation: - `pdm run generate-schemas` - `pdm run generate-config` - `pdm run pytest tests/unit/test_delete_flow.py` - `pdm run format` - `pdm run lint` - `pdm run test` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved old-ad deletion behavior for items without an ID, including title-based matching only when needed. * Made title-based deletion fail closed: ambiguous title matches are now skipped. * Ensured exact-ID deletions target only the specified ID and don’t expand to same-title ads. * Skips title-based matching for a batch when published-ad retrieval can’t be completed, while continuing exact-ID deletions. * **Documentation** * Updated configuration documentation for title-based old-ad deletion to reflect the new matching and skip behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
25e2970ed0 |
feat: improve status APR report (#1201)
## ℹ️ Description - Moves APR preview information out of verify output and into status reporting. - Improves status output into readable per-ad blocks with full relative file paths and structured APR update/publish details. ## 📋 Changes Summary - Keep verify focused on validation while preserving its full ad-loading validation path. - Show APR preview details in status without requiring verbose mode. - Render status as path-first per-ad report lines with title, id, status, APR update/publish details, and unchanged summary. - Use structured APR detail data and translated human-readable reasons instead of raw reason tokens. - Remove the now-dead APR preview logger and stale translations. - Update CLI help, README/docs, smoke tests, and focused unit tests. ### ⚙️ Type of Change - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [x] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project standards. - [x] I have tested my changes and ensured that all tests pass (pdm run test). - [x] I have formatted the code (pdm run format). - [x] I have verified that linting passes (pdm run lint). - [x] I have updated documentation where necessary. Validation run: - pdm run format - pdm run lint - pdm run test — 1467 passed, 4 skipped By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * `status` now shows detailed APR preview information for ads in a clearer, per-ad layout. * Help text and documentation now point users to `status` for APR preview details. * **Bug Fixes** * `verify` no longer displays APR preview output, making its results focused on configuration and integrity checks. * Improved status output readability and APR detail handling for publish and update scenarios. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
28da3865c6 |
refactor: simplify humanizer behavior (#1200)
## ℹ️ Description - Related issue(s): none. - Simplifies the humanizer after PR #1199 by removing premature feature surface that was either speculative or default-off, while keeping the useful behavior: baseline pacing, typing jitter, and post-open viewport randomization. ## 📋 Changes Summary - Remove mouse-movement, idle-action, and long-pause humanizer configuration and implementation. - Keep plain click behavior plus baseline web_sleep pacing. - Keep typing jitter default-on with bounded per-character delays. - Keep post-open viewport resize default-on, preserving user-supplied --window-size behavior and no launch-time bot --window-size. - Update config defaults, generated schema/default config, German translations, and unit tests. - Delete the weak viewport integration test that asserted private state instead of user-observable behavior. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [x] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) Removed config keys: mouse_movement, idle_action_probability, long_pause_probability, long_pause_min_ms, long_pause_max_ms. ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project standards. - [x] I have tested my changes and ensured that all tests pass (pdm run test). - [x] I have formatted the code (pdm run format). - [x] I have verified that linting passes (pdm run lint). - [x] I have updated documentation where necessary. Validation: pdm run format && pdm run lint && pdm run test — 1468 passed, 4 skipped. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Simplified browser interactions to use direct clicks and per-character typing more consistently. * Updated viewport handling so browser size is applied after opening, using screen metrics when available. * Improved resizing behavior to skip invalid or unsupported cases without interrupting browsing. * Adjusted humanization timing defaults for smoother, lighter pacing. * **Refactor** * Narrowed the humanization settings to focus on pacing, typing jitter, and viewport behavior. * Removed unused idle and movement-related behavior from the browsing flow. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
df6e308ab2 |
fix: resize viewport after opening page (#1199)
## ℹ️ Description - Related issue(s): none. - Fixes the screen-aware viewport regression by removing the temporary pre-launch screen probe and resizing the already-open browser window after the first kleinanzeigen.de page load. ## 📋 Changes Summary - Remove the isolated probe browser path that could time out or appear on a different screen. - Open the main browser without bot-added `--window-size`, then resize once after the first eligible kleinanzeigen.de page opens. - Preserve user-supplied `--window-size` and skip remote/headless/no-display or disabled randomization cases. - Keep no-fallback behavior when screen metrics are invalid or no configured viewport fits. - Update viewport tests and German translations for moved log messages. ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. Validation run locally: `pdm run format && pdm run lint && pdm run test` — 1470 passed, 4 skipped. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Automatically resizes the browser window after a page loads, using screen-aware metrics from the current page. * Selects from configured viewport sizes that fit the available screen area, with bounded variation. * Adds runtime diagnostics for viewport resize (attempted/applied), including skip reasons and failure details. * **Bug Fixes** * Improves resilience when URL/metrics are missing, malformed, or don’t include valid dimensions. * Prevents resize for non-eligible pages and when a user-supplied window size is present; resize now occurs before human-like actions. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
4c150f64a1 |
enh: Add screen-aware viewport sizing (#1198)
## ℹ️ Description - Link to the related issue(s): PR #1193 follow-up - Adds screen-aware humanization viewport selection so randomized desktop sizes fit the available browser-reported screen area while preserving permissive config validation. ## 📋 Changes Summary - Add larger common desktop viewport defaults: `2560x1440`, `1920x1200`, `1728x1117`, and `1512x982`. - Probe browser-reported CSS-pixel screen metrics at launch time using `window.screen.availWidth` / `window.screen.availHeight`. - Filter configured viewport base sizes against available screen dimensions, apply bounded jitter, and preserve explicit `--window-size` overrides. - Omit automatic `--window-size` when no configured size fits, screen metrics are unavailable, the launch is headless, or no real display/window manager is available; explicit user `--window-size` remains preserved. - Cache successful probe metrics and bound the probe with the `chrome_remote_probe` timeout. - Update generated default config and German translations. - Add unit coverage and real-browser integration coverage for viewport probing/filtering, headless/no-display skips, probe timeout/cache behavior, and `create_browser_session()`. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [x] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Browser sessions now support screen-aware viewport selection automatically when viewport randomization is enabled. * Expanded the default set of candidate viewport sizes used for randomized sizing. * **Bug Fixes** * Viewport sizing now filters out candidates that don’t fit within the available screen area. * If a window size is already specified, it’s preserved. * **Tests** * Added/expanded slow integration tests for screen probing and viewport fitting. * Expanded unit tests for viewport filtering, jittering, fallback behavior, and probe reuse/timeout. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
a051712dc8 |
fix: handle portal combobox attributes (#1195)
## ℹ️ Description - Link to the related issue(s): Issue # - Fixes publishing for special-attribute button comboboxes whose option list opens via a fuller click sequence or renders outside the control parent element. ## 📋 Changes Summary - Dispatch mouseup and click in addition to the existing pointer/mouse down events when opening button comboboxes. - Add document-level listbox/menu fallback lookup for portal-rendered combobox popups. - Normalize option text whitespace before text fallback matching. - Add regression coverage for the combobox JS contract and no-options failure diagnostics. ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project standards. - [x] I have tested my changes and ensured that all tests pass (pdm run test). - [x] I have formatted the code (pdm run format). - [x] I have verified that linting passes (pdm run lint). - [x] I have updated documentation where necessary. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Summary by CodeRabbit * **Bug Fixes** * Improved dropdown/combobox selection reliability, including better support for portal-rendered menus and document-level listbox/menu fallbacks. * Made option matching more tolerant by normalizing whitespace and applying consistent case handling. * Reduced selection failures by using a more complete native interaction sequence when opening and choosing options. * Enhanced unit coverage to validate the injected selection script and clearer timeout error messaging. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
1bb8adc2cf |
feat: show filenames in status output (#1196)
## ℹ️ Description Show the full ad filename in `pdm run app status` output so status rows can be traced back to their source ad files. - Link to the related issue(s): none - Motivation: the status table currently shows ID, title, and status, but not the source filename, which makes it harder to identify which ad file a row came from. ## 📋 Changes Summary - Add a filename field to status rows, populated from the relative ad file path. - Render a `Filename` column in the status table. - Add the German translation for the new status table header. - Update status rendering unit tests for the new column. - No new dependencies or configuration changes. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [x] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Summary by CodeRabbit * **New Features** * Added a **Filename** column to the status table, displaying the relative ad file path for each ad. * **Tests** * Updated automated tests to reflect the new table layout, verify correct filename values, and adjust ANSI formatting checks to account for the added column. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
807633a6cc |
chore: remove CodeRabbit keyword ignores (#1194)
## ℹ️ Description - Link to the related issue(s): N/A - Remove CodeRabbit title keyword ignores so PRs with matching title words are no longer skipped automatically. ## 📋 Changes Summary - Removed `ignore_title_keywords` from `.coderabbit.yaml`. - No runtime dependencies, configuration requirements, or application behavior changes introduced. ### ⚙️ Type of Change - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) - [x] Chore / configuration maintenance ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [ ] I have tested my changes and ensured that all tests pass (`pdm run test`). Not run — CodeRabbit config-only change. - [ ] I have formatted the code (`pdm run format`). Not run — YAML line deletion only. - [ ] I have verified that linting passes (`pdm run lint`). Not run — CodeRabbit config-only change. - [x] I have updated documentation where necessary. No documentation updates needed. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Updated automated review settings so keyword-based exclusions are no longer used. * Review behavior now relies on existing draft and label checks, which may result in more consistent PR review coverage. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
4cc35cbd9f |
docs: clarify download shipping inference (#1192)
## ℹ️ Description - Link to the related issue(s): Issue # - Clarifies what `download` can infer for shipping options after the old cheapest-option limitation became inaccurate. ## 📋 Changes Summary - Replaces the outdated README limitation with the current download shipping inference behavior. - Documents pickup handling, `Versand möglich` without price, visible shipping prices, inferred `shipping_options`, `download.include_all_matching_shipping_options`, and `sell_directly` scope. - No dependency or configuration changes. ### ⚙️ Type of Change - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Updated the README “download” limitations to clarify that shipping details are inferred dynamically. * Added a detailed explanation of how pickup vs. “Versand möglich” listings are handled, how “shipping from” prices map to shipping costs and options, and how direct-buy eligibility is determined. * Documented the option to include all matching non-excluded shipping options during download. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
eda06334d1 |
docs: generate README usage section (#1191)
## ℹ️ Description - Link to the related issue(s): N/A - Keeps the README Usage command block in sync with the CLI help by generating it as part of the artifact pipeline. ## 📋 Changes Summary - Added a README Usage generator that renders normalized English CLI help between explicit README markers. - Added `generate-readme-commands` and wired it into `generate-artifacts`. - Extended generated artifact checks to detect README Usage drift without mutating files. - Added focused unit tests for marker replacement, locale/executable normalization, ANSI stripping, and command coverage. - No dependency changes introduced. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [x] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Kept the README “Usage” section automatically synchronized with the app’s CLI help. * Added a new `--preserve-local-settings` option to the CLI help output. * **Bug Fixes** * Improved and clarified CLI command/option descriptions (notably around `verify`, `extend`, and `update` behavior). * CI now fails early if the generated README “Usage” content is out of date. * **Documentation** * Regenerated the README “Usage” console block to reflect the latest help text and command details. * Updated agent guidance to match the expanded README generation behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
59185b8f6e |
docs: shorten pip-only install note (#1189)
## ℹ️ Description - Link to the related issue(s): N/A - Shortens the pip-only install note in the README so it is a side note rather than prominent guidance. ## 📋 Changes Summary - Condensed the pip-only note from a long block to two lines. - No dependencies, configuration changes, or additional requirements introduced. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [ ] I have tested my changes and ensured that all tests pass (`pdm run test`). Not run; documentation-only change. - [ ] I have formatted the code (`pdm run format`). Not run; documentation-only change. - [ ] I have verified that linting passes (`pdm run lint`). Not run; documentation-only change. - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. |
||
|
|
f2da0355d5 |
fix: classify Auth0 IP range block (#1188)
## ℹ️ Description - Link to the related issue(s): Issue #1120 - Classifies Kleinanzeigen IP-range block pages explicitly when Auth0 post-submit verification remains on the password URL. - This makes the failure actionable without changing login/captcha behavior or attempting to bypass the block. ## 📋 Changes Summary - Add `IP_RANGE_BLOCKED` to post-submit Auth0 state classification when the password-page DOM contains the Kleinanzeigen IP-range block heading. - Keep existing classification facts such as `STILL_ON_PASSWORD_PAGE`, so combined states remain visible. - Keep detection scoped to the Auth0 password page and best-effort. - Add focused unit tests for detection, gating, resilience, and coexistence with Auth0 inline errors. - No new dependencies, configuration changes, schema changes, or translation updates. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test tests/unit/test_login_flow.py tests/unit/test_translations.py`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved sign-in diagnostics to detect when login is stalled on the password step due to an IP-range restriction. * Added support for preserving existing login-state facts when the IP-block page probe fails, and for correctly combining IP-block signals with inline error states. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
ce0c5fa5b5 |
fix: handle DOM retry and button combobox selection (#1186)
## ℹ️ Description - Link to the related issue(s): Issue #1184 - Fixes two publish-flow failures reported in issue #1184: - persistent nodriver `ProtocolException(code=-32601)` could spin forever in `web_await()` while repeatedly re-attaching the CDP session; - special-attribute button comboboxes in the Handy & Telefon category needed open/read/select to happen atomically in one browser execution. ## 📋 Changes Summary - Bound `web_await()` CDP reattach retries by the configured timeout and add a short nonzero retry delay to avoid event-loop starvation. - Update special-attribute button-combobox selection to use one async `web_execute()` script that opens via pointer/mouse events, discovers options, matches API values, and clicks the selected option before the dropdown can close. - Add regression tests for bounded `-32601` retry behavior and atomic button-combobox selection. - Update the German translation for the enhanced combobox failure message. - Verified with the live `button-combobox` DOM probe. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. ## Validation - `pdm run format` - `pdm run lint` - `pdm run test` — 1370 passed, 4 skipped - `pdm run python data/verify_dom_assumptions.py run --yes --probe button-combobox --report data/.temp/dom-assumptions-issue-1184-button-combobox.json` — passed <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved dropdown/combobox option selection with stronger matching and more informative timeout/error reporting. * Tightened CDP re-attach retry logic to strictly follow the remaining timeout budget. * Added a startup runtime warning if the required nodriver CDP re-attach patch isn’t detected. * **Documentation / Chores** * Updated source installation guidance (pip-only users) to ensure the nodriver patch is applied. * Made the nodriver fix script marker-based and idempotent, including normalization of legacy patched installs. * **Tests** * Expanded unit tests for combobox selection, re-attach timeout/bounds behavior, CLI patch warning behavior, and the nodriver fix script. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
27b47f7561 |
fix: capture Auth0 post-submit diagnostics (#1183)
## ℹ️ Description - Link to the related issue(s): Issue #1120 - Capture diagnostics when Auth0 post-submit verification remains inconclusive, so future failures include a DOM/screenshot bundle plus classified metadata. ## 📋 Changes Summary - Reuse existing login-detection diagnostics for the final Auth0 post-password-submit timeout. - Add sanitized JSON metadata with `event`, `classification`, and `page_url`. - Keep diagnostics best-effort so capture failures do not mask the original classified timeout. - Add focused tests for enabled/disabled capture, privacy sanitization, failure preservation, and diagnostics argument forwarding. - No new configuration, schema, translation, captcha, or identifier-flow changes. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test tests/unit/test_login_flow.py tests/unit/test_translations.py`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. (Not needed.) By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved login timeout handling with clearer error messages and safer URL reporting. * Added fallback diagnostics during failed post-login verification, while preserving the original timeout if diagnostics capture fails. * Prevented sensitive URL parts from appearing in error reports. * **Tests** * Expanded coverage for login diagnostics forwarding and timeout behavior with diagnostics enabled and disabled. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
4acbc09fac |
fix: classify Auth0 post-submit uncertainty (#1181)
## ℹ️ Description - Link to the related issue(s): Issue #1120 - Adds focused diagnostics/classification for the post-password-submit Auth0 uncertainty path. This keeps the existing login/captcha/identifier flow stable while making the new failure mode easier to classify from logs. ## 📋 Changes Summary - Classifies final post-submit uncertainty as still on the Auth0 password page, visible Auth0 error text, verification/MFA-like state, or unknown redirect/session inconclusive state. - Logs sanitized diagnostic context and raises clearer classified messages while preserving the existing timeout prefix. - Adds focused unit tests for the new classifications and snippet sanitization. - Updates German translations for new translatable messages. - No new dependencies or configuration changes. ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project standards. - [x] I have tested my changes and ensured that all tests pass (pdm run test). - [x] I have formatted the code (pdm run format). - [x] I have verified that linting passes (pdm run lint). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved handling when transitioning after Auth0 password submission by using safer, sanitized diagnostic URLs. * Added clearer, classification-aware timeout messages when the next verification step can’t be identified. * Strengthened detection of post-Auth0 states, including inline Auth0 errors and MFA/verification prompts, with more graceful degradation on probing failures. * **Tests** * Expanded unit tests for post-submit state classification, URL sanitization, and improved timeout/error-message expectations, including resilience to probe/URL retrieval failures. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
1c34da9298 |
feat: show APR status indicators (#1180)
## ℹ️ Description - Link to the related issue(s): Issue # - Adds display-only APR indicators to the local status table so users can see repost/update APR state without running publish/update flows. ## 📋 Changes Summary - Adds optional `APR repost` and `APR update` columns to `kleinanzeigen-bot status` when APR is effectively enabled for at least one active ad. - Reuses existing `evaluate_auto_price_reduction()` logic for REPLACE and MODIFY modes; does not apply or mutate APR decisions. - Keeps APR output plain while preserving existing status color behavior. - Adds German translations and unit coverage for rendering, evaluator call modes, guardrails, and mutation safety. - No new dependencies or configuration changes. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [x] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`: 1344 passed, 4 skipped). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Status tables now show optional APR-related columns for repost and update pricing decisions when available. * APR results are displayed in a compact, easy-to-read format such as due, not due, error, or off. * **Bug Fixes** * Improved status table layout and spacing so translated status text fits more reliably. * Status summaries and row rendering now handle coloured and uncoloured cells more consistently. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
25a379fe67 |
feat: colorize status output (#1178)
## ℹ️ Description - Link to the related issue(s): Issue # - Adds optional color to the `kleinanzeigen-bot status` table using the existing Colorama dependency. - Keeps default status behavior local/read-only and gates ANSI output via terminal/env policy. ## 📋 Changes Summary - Adds `utils.color.should_use_color()` with `NO_COLOR` > `FORCE_COLOR` > TTY detection. - Colors only the status column while preserving plain ASCII layout and summary output. - Wires status rendering to the color gate in `_handle_status()`. - Removes legacy `colorama.init()` from `update_checker.py`; package init already enables Windows ANSI support. - Adds unit tests for color gating and colored status rendering. - No new dependencies or configuration changes. ### ⚙️ Type of Change - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [x] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`: 1332 passed, 4 skipped). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Status output can now be shown with optional terminal colors for improved readability. * Color display automatically follows your terminal and environment settings. * **Bug Fixes** * Status tables keep proper alignment even when colored text is enabled. * Unknown statuses remain uncolored, avoiding inconsistent display. * **Tests** * Added coverage for color handling and status rendering to improve reliability. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
50a4b570cf |
feat: add ad status command (#1177)
## ℹ️ Description - Link to the related issue(s): Issue # - Adds a CLI status overview inspired by useful lifecycle features from kleinanzeigen-bot-ui, while keeping this project CLI-only. - The new command helps users see local ad state at a glance without replacing the existing verify/APR preflight flow. ## 📋 Changes Summary - Add `kleinanzeigen-bot status` with an ASCII table and summary for local ad states: disabled, draft, changed, due, and published-local. - Add shared pure helpers for content-change and republication-due checks. - Add a small neutral `load_ad_configs()` loader reused by `load_ads()` and `status` without broad loader redesign. - Add German translations and focused unit/guardrail tests. - No schema/config model changes or generated artifacts. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [x] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. Validation: - `pdm run format` passed - `pdm run lint` passed - `pdm run test`: 1315 passed, 4 skipped; coverage 93.18% <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added a new `status` command to view the current state of configured ads. * Introduced a status summary that shows whether ads are disabled, drafts, changed, due, or published locally. * Added cleaner handling for ad loading and republication checks, improving consistency in displayed results. * **Bug Fixes** * Improved change detection for ads, including better handling when stored data is missing or empty. * Enhanced due-date checks so timing-based status is more reliable. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
d5d596d481 |
fix: target visible Auth0 submit button and broaden captcha detection (#1120) (#1176)
## ℹ️ Description Fixes #1120 — Auth0 login fails after email submit because the bot clicks a hidden submit button and cannot detect non-reCAPTCHA captcha providers. **Root causes:** 1. **Hidden submit button** — Auth0 renders two `button[type='submit']` elements. The hidden one (`class=ulp-hidden-form-submit-button`, `aria-hidden=true`) appears first in DOM. `querySelector()` was matching it instead of the visible primary button. 2. **Captcha detection too narrow** — Only matched reCAPTCHA v2 iframes. Kleinanzeigen.de uses Cloudflare Turnstile via Auth0 v2 (`data-captcha-provider='auth0_v2'`), which renders inline without an iframe. **Evidence:** @jochenberger provided HTML from the identifier page confirming both issues. User CAN manually click 'Weiter' and login succeeds. ## 📋 Changes Summary - Add `_click_auth0_submit()` helper using `[data-action-button-primary='true']` to target the visible button - Broaden captcha detection: iframe selector covers 6 providers, container selector uses `[data-captcha-provider]` + substring class matching - Simplify `handle_identifier_captcha_state()` with Turnstile token wait via JS property check - Use `_click_auth0_submit()` for both identifier and password submits - Add Auth0 provider provenance comments to selectors ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Bug Fixes** - Improved captcha/challenge detection to support both iframe-based providers and Auth0 container-based challenges. - Updated the Auth0 login flow to click the correct visible Auth0 primary submit button, avoiding hidden controls for identifier and password steps. - Centralized captcha detection timeout to make challenge handling more consistent. - **Tests** - Expanded and tightened unit tests for the Auth0 identifier-step captcha/submit behavior, including selector expectations and control-flow scenarios. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
8e70d0411d |
refactor: decompose WebScrapingMixin (static helpers, diagnostics, exception annotations) (#1174)
## ℹ️ Description Decompose `WebScrapingMixin` — incremental internal refactors to reduce class size and improve separation of concerns. ## 📋 Changes Summary ### Static method extraction - Extract 5 `@staticmethod` members from `WebScrapingMixin` to module-level private functions in `web_scraping_mixin.py` - Update internal call sites and test call sites (no compatibility aliases) ### Browser diagnostics extraction - Create `src/kleinanzeigen_bot/utils/browser_diagnostics.py` with module-level diagnostic functions - `WebScrapingMixin.diagnose_browser_issues()` → thin delegator (resolves `self` attrs, calls extracted logic) - Replace `self`-coupled logic with explicit parameter dependencies - Migrate translations to new module section in `translations.de.yaml` ### Exception annotations - Add `# noqa: BLE001` + justification comments to 4 bare `except Exception:` blocks (no behavior changes) ### ⚙️ Type of Change - [x] 🔧 Refactor (internal code improvements, no behavior changes) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`) — 1287 passed, 4 skipped - [x] I have formatted the code (`pdm run format`) - [x] I have verified that linting passes (`pdm run lint`) — ruff, mypy, pyright clean - [x] I have updated documentation where necessary. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added enhanced browser troubleshooting with remote-debugging connectivity checks, running-process inspection, and Chrome/Edge compatibility validation including recommended configuration updates. * **Refactor** * Reorganized browser/session diagnostics and remote-debugging argument handling into dedicated utilities; introduced a shared browser runtime configuration container. * **Chores** * Suppressed linter warnings for intentionally broad exception handling. * **Tests** * Updated unit and integration tests to match the new diagnostics flow and remote-debugging probing behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
b2dce90ef1 |
refactor: remove dead wrapper methods from KleinanzeigenBot (#1172)
## ℹ️ Description Remove four private wrapper methods on `KleinanzeigenBot` in `app.py` that wrap public module-level functions but have zero production call sites. This is a cleanup-only change with no behavioral impact. ## 📋 Changes Summary - **Remove** `_has_logged_in_marker` — delegates to `login_flow.has_logged_in_marker` - **Remove** `_check_publishing_result` — delegates to `publishing_workflow.check_publishing_result` - **Remove** `_delete_old_ad_if_needed` — delegates to `publishing_workflow.delete_old_ad_if_needed` - **Remove** `_capture_login_detection_diagnostics_if_enabled` — delegates to `login_flow.capture_login_detection_diagnostics_if_enabled` - **Remove** unused `Literal` import - **Retarget** 4 helper-detail tests that called the deleted wrapper directly to the real `login_flow.capture_login_detection_diagnostics_if_enabled` function ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Reorganized login detection diagnostics functionality for improved accessibility * Simplified login status verification logic within the authentication system <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
dedf4cb4f0 |
refactor: extract template name renderer from AdExtractor (#1171)
## ℹ️ Description Extract the priority-based template rendering algorithm from `_render_download_name_with_budget` into a module-level pure function `_render_name_with_budget`. The method becomes a thin wrapper that delegates rendering and handles truncation warnings. ## 📋 Changes Summary - Added `_render_name_with_budget(template, ad_id, title, max_length) -> tuple[str, bool, bool]` as a module-level pure function with no AdExtractor dependency - Rewrote `_render_download_name_with_budget` as a thin wrapper that calls the pure function and handles logging - Removed `_reserved_for_pending_placeholders` static method (logic inlined in the pure function) ### ⚙️ Type of Change - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Improved download name handling with enhanced truncation logic for improved filename generation. * Added warnings when download names are automatically shortened due to length constraints. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
1f142f8339 |
refactor: extract selector and filter helpers from load_ads (#1169)
## ℹ️ Description Extract three private helpers from `load_ads()` to remove the last remaining `# noqa: PLR0915` annotation in main source. `load_ads` goes from ~100 statements to ~35 — a clean orchestration function. ## 📋 Changes Summary - **`_parse_ad_selector`**: parse `ads_selector` string into numeric IDs list or frozenset of tokens - **`_should_include_ad`**: token-based ad filtering ("changed"/"new"/"due"/"all") — preserves exact ordering, side effects, and "changed"/price-reduction-for-update logic - **`_prepare_selected_ad_entry`**: description validation, category resolution, image resolution — called only after filtering to avoid validating skipped ads - Translation keys moved to match new caller function names (`_should_include_ad:`, `_prepare_selected_ad_entry:`) - Added regression test: inactive ad with unresolvable images is skipped without error ### ⚙️ Type of Change - [x] ✨ New feature (adds new functionality without breaking existing usage) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Reorganized ad loading process with improved selector parsing and filtering logic for better code maintainability. * Optimized validation workflow: inactive and non-selected ads now skip description and image validation, improving overall efficiency. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
388d0fb3c8 |
refactor: separate download ad persistence concerns (#1168)
## ℹ️ Description Separate downloaded-ad persistence concerns from `download_ad()` in `extract.py`. The original method mixed browser extraction, local-settings preservation, and a filesystem transaction — three independently meaningful and operationally sensitive concerns. ## 📋 Changes Summary - **Extracted `_preserve_local_settings_from_existing_ad()`** — preserves local-only settings (repost_count, republication_interval, auto_price_reduction, price_reduction_count) from an existing ad YAML into the new config. No-op unless `preserve_local_settings` is enabled. - **Extracted `_commit_staged_download()`** — owns the full filesystem transaction: YAML save, backup collision check, rename final→backup→staging→final, backup cleanup, and rollback on failure. - **Simplified `download_ad()`** — now a clean 3-step orchestrator: extract → preserve → commit. - **Restructured translation keys** in `translations.de.yaml` to follow the new caller function names. No behavior changes to preservation, rollback, YAML handling, or exception propagation. ### ⚙️ Type of Change - [ ] 🐞 Bug fix - [ ] ✨ New feature - [ ] 💥 Breaking change ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Enhanced ad download process with improved backup and rollback mechanisms for better reliability * Refined handling of local settings preservation during re-downloads to maintain data integrity <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
eeeae6ea5e |
refactor: extract shipping helpers from set_shipping (#1167)
## ℹ️ Description Refactor `set_shipping` in `publishing_form.py` by extracting four distinct concerns into focused private helpers. Simplifies a ~55-statement function into a ~20-statement orchestrator with a flat if-return chain. ## 📋 Changes Summary - Extract `_select_shipping_combobox_if_present` — PRO/commercial combobox handling - Extract `_set_pickup_shipping` — PICKUP radio + fieldset fallback - Extract `_set_configured_shipping_options` — shipping options dialog + MODIFY nav - Extract `_enable_platform_default_shipping` — enable shipping toggle - Keep legacy `shipping_costs` guard inline in `set_shipping` (per review) - Re-key translation entries under new caller-function names (duplicate "Failed to set shipping..." under both combobox and pickup helpers) - `set_shipping` slimmed from ~55 → ~20 ruff-counted statements ### ⚙️ Type of Change - [ ] 🐞 Bug fix - [ ] ✨ New feature - [ ] 💥 Breaking change ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Refactor * **Shipping configuration**: Refactored the shipping configuration logic to improve internal code structure and maintainability, enabling more reliable handling of shipping options across different scenarios. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
780743aee2 |
refactor: separate download_ads workflow modes (#1166)
## ℹ️ Description Extract four private async helpers from `download_ads()` to separate per-mode workflow logic. - Motivation: Reduce function complexity, enable tighter pylint thresholds ## 📋 Changes Summary - Extracted `_fetch_published_ads_by_id` — fetch and build published ads lookup dict - Extracted `_download_all_ads` — download all ads from overview page - Extracted `_download_new_ads` — download only unsaved ads (preserving URL dedup behavior) - Extracted `_download_ads_by_ids` — download specific ads by numeric ID (preserving distinct warning semantics) - Slimmed `download_ads()` to ~48-line orchestrator (was ~124 lines) - Restructured `translations.de.yaml` — messages moved to per-function sections - Ratcheted pylint thresholds: max-statements 90→76, max-branches 35→31 ### ⚙️ Type of Change - [ ] 🐞 Bug fix - [ ] ✨ New feature - [ ] 💥 Breaking change Internal refactor, no user-visible behavior change. ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`): 1286 passed, 4 skipped - [x] I have formatted the code (`pdm run format`) - [x] I have verified that linting passes (`pdm run lint`) - [x] I have updated documentation where necessary. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Strengthened code quality standards and refactored internal ad downloading logic for improved maintainability. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
eaa646874d |
refactor: replace get_message_template match with dict lookup (#1165)
## ℹ️ Description Replace the ~115-arm match/case in `__get_message_template` with a module-level `_MESSAGE_TEMPLATES` dict of raw English strings plus a 3-line lazy `_(template)` lookup function. - **Motivation**: Eliminate 5 complexity `noqa` annotations (C901, PLR0911, PLR0912, PLR0915, E701) by removing the real architectural complexity — a pure flat error-code → message mapping that has zero branching or logic. - **Approach**: A `dict[str, str]` of raw English strings (no `_()` calls at import time) with lazy translation inside `__get_message_template`. `"custom_error"` intentionally omitted — handled by `.get()` default. - **Translation**: Caller function name unchanged → translation keys under `__get_message_template` preserved. AST-based translation test extractor updated to recognize `_MESSAGE_TEMPLATES` dict values. ## 📋 Changes Summary - `src/kleinanzeigen_bot/utils/pydantics.py`: Replaced ~115 match arms with `_MESSAGE_TEMPLATES` dict + 3-line function; removed all 5 noqa annotations - `tests/unit/test_translations.py`: Added AST extraction for `_MESSAGE_TEMPLATES` dict values to maintain translation coverage checks ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Improved error message handling system to support better internationalization and translation workflows * **Tests** * Updated test suite to extract and verify translatable message strings <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
32c6d3985f |
refactor: split published ads pagination (#1164)
## ℹ️ Description Extract content-decoding and paging-navigation logic from `fetch_published_ads` into focused module-level helpers, reducing function complexity while preserving all behavior. ## 📋 Changes Summary - **`published_ads.py`**: Extracted `_parse_published_ads_page()` (content decode, JSON parse, payload validation, ad filtering) and `_determine_next_page()` (paging metadata resolution, last-page/empty-ads guards). Main `fetch_published_ads` is now a clean orchestration loop: request → response check → parse → extend → paginate. - **`translations.de.yaml`**: Split the single `fetch_published_ads:` translation section into three sections (`fetch_published_ads:`, `_parse_published_ads_page:`, `_determine_next_page:`) matching the new caller function names. Added missing translation for "No paging dict found on page %s". - **`pyproject.toml`**: Lowered `max-statements` from 115 to 90. - **`pydantics.py`**: Added `PLR0915` noqa for `__get_message_template` (already an approved exception for the generated pydantic error-code mapping). ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Improved published-ads fetching by separating response decoding and pagination handling into dedicated helpers, while preserving existing behavior. * Reworked strict-mode validation and stopping conditions for clearer control flow and more consistent error handling. * **Chores** * Updated linting limits to enforce stricter code quality. * Added targeted lint suppression for an overly complex section. * **Tests** * Expanded unit test coverage for published-ads content decoding and strict-mode failure cases across multiple malformed/edge responses. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
b5e2769f2d |
refactor: extract special attribute helpers from publishing form (#1161)
## ℹ️ Description Extract three module-level helpers from `set_special_attributes()` in `publishing_form.py` to reduce local variable count and improve readability. `set_special_attributes` had 27 locals — after extraction it has 10. - Behavior-preserving: no change to exception propagation, logging, or control flow. - `condition_s` probe stays in main to avoid translation-key churn. ## 📋 Changes Summary - Extract `_build_special_attribute_xpath()` — Pure XPath construction (fix comment: five → six patterns) - Extract `_resolve_special_attribute_element()` — Wraps `web_find_all` + candidate pick, propagates exceptions uncaught - Extract `_set_special_attribute_input()` — 6-branch input-type dispatch; hidden-input returns without logging, caller logs once - Rewire `set_special_attributes` to call the three helpers - Ratchet `pyproject.toml`: PLR0914 max-locals 27 → 20 - Update `translations.de.yaml`: move 4 debug messages + add `Failed to set attribute` under `_set_special_attribute_input` ### ⚙️ Type of Change - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) - [x] ♻️ Refactor (non-breaking restructuring of existing code) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). → 1268 passed, 4 skipped - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. → Translation file updated <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Summary by CodeRabbit * **Chores** * Tightened linting rules by lowering the allowed maximum number of local variables. * **Refactor** * Reworked special-attribute DOM handling to use clearer selection and value-setting paths for different field types, including improved fallback behavior. * **Tests** * Added async unit test coverage for `set_special_attributes`, including input fallback behavior and error cases for unsupported checkbox values and missing hidden input metadata. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
d542f1ea92 |
feat: use configured --remote-debugging-host for browser diagnostics probes (#1160)
## ℹ️ Description `diagnose_browser_issues()` previously hardcoded `127.0.0.1` for port-open and `/json/version` API probes. When Chrome's remote debugging is exposed on a different host (Docker, LAN, CI), the diagnostics miss the running browser entirely. This PR makes diagnostics host-aware by parsing `--remote-debugging-host` from `browser_config.arguments` and using the configured host instead of the hardcoded `127.0.0.1`. All diagnostics probes (port, API, Chrome version) now respect the configured host. ## 📋 Changes Summary - Added `_diagnostic_remote_debugging_endpoint()` — private diagnostics parser with first-wins semantics for both host and port, defaults to `127.0.0.1:0` - Added `_format_url_host()` — IPv6-safe URL bracketing helper - Threaded configured host into `net.is_port_open()`, `_remote_debugging_api_browser()`, and `_diagnose_chrome_version_issues()` - Emit `LOG.warning` before probing a non-loopback configured host (security/documentation guard) - Updated German translations for changed log message strings - Added tests: configured host `10.0.0.5` and `192.168.1.100`, host-after-port ordering, IPv6 URL formatting, Chrome-version host propagation - Default behavior (no `--remote-debugging-host` argument) unchanged — probes remain `127.0.0.1` ### ⚙️ Type of Change - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [x] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved remote browser debugging diagnostics to work with non-local hosts, including correct IPv6-safe URL formatting. * Added host-aware reachability checks and clearer warnings when the configured remote host may not be loopback. * Enhanced diagnostic messaging to report the configured host and port during remote debugging checks. * **Tests** * Expanded unit test coverage for configured remote-debugging hosts (including IPv6) and updated expectations for host-specific diagnostic outputs. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
d384f172b8 |
fix: remove individual shipping publishing (#1159)
## ℹ️ Description - Link to the related issue(s): Issue #1157 - Kleinanzeigen no longer offers individual/custom shipping. This updates publishing, validation, docs, schemas, translations, and tests so existing `shipping_costs` configs are handled gracefully instead of failing against removed DOM controls. ## 📋 Changes Summary - Keep `shipping_costs` for legacy configs/downloaded ads, but mark it deprecated in schema/docs and ignore it during publishing. - Remove publishing interaction with removed individual-shipping DOM controls. - Require predefined non-empty `shipping_options` for `sell_directly`. - Update docs, generated schemas/config artifacts, German translations, and unit tests. - Verified live DOM for `sell_directly: true` + `shipping_type: SHIPPING` + predefined `shipping_options` via local ignored script; no ad submission performed. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Updated shipping guides to deprecate custom individual shipping costs and make publishing depend on per-ad predefined `shipping_options` (DHL/Hermes; selectable options must come from a single size group). * Added migration guidance replacing `shipping_costs` with the correct `shipping_options`. * Clarified “Sell directly” requires `shipping_type: SHIPPING`, non-empty `shipping_options`, and `FIXED`/`NEGOTIABLE` pricing. * **Bug Fixes** * Publishing is blocked when `shipping_costs` is provided without `shipping_options`. * Removed unsupported individual-shipping handling and tightened “Sell directly” eligibility rules. * **Tests** * Expanded unit coverage for deprecation behavior, content handling, and direct-buy validation. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
5ab4015251 |
refactor: simplify browser diagnostics (#1158)
## ℹ️ Description - Link to the related issue(s): Issue # - Refactor browser diagnostics to reduce the complexity of the diagnostics orchestration while preserving the generated diagnostics report and browser workflow behavior. ## 📋 Changes Summary - Extract factual browser diagnostic checks into focused helpers for binary detection, remote debugging port parsing, remote API probing, target browser name detection, and process discovery. - Keep translated diagnostics logging as direct literal log calls in `diagnose_browser_issues`. - Add regression coverage for remote debugging host handling, invalid ports, first-port precedence, and port `0` pass-through behavior. - No dependencies, configuration changes, or additional requirements introduced. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) - [x] ♻️ Refactor (no user-facing behavior change) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Improved browser diagnostics by breaking down remote debugging checks into clearer steps, enhancing resilience when probing the browser and inspecting running processes, and refining success vs failure logging. * **Tests** * Expanded unit coverage to ensure remote debugging probing always targets `http://127.0.0.1:<port>`, validates `--remote-debugging-port` parsing (including invalid and multi-argument cases), and skips remote debugging when the port is `0` while continuing Chrome version diagnostics. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
0b4b9eb397 |
refactor: split browser session setup (#1156)
## ℹ️ Description - Link to the related issue(s): N/A - Split browser session setup into smaller, behavior-preserving helpers so browser startup orchestration is easier to review and maintain. ## 📋 Changes Summary - Extract remote debugging connection handling from browser session creation. - Extract launch argument, user-data-dir, Nodriver config, profile preparation, and extension setup helpers. - Add matching German translation entries for log messages moved into helper functions. - Leave lint thresholds unchanged because the diagnostics follow-up remains separate. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Summary by CodeRabbit * **Refactor** * Improved browser session setup by separating remote-debugging connections from fresh browser startup. * Hardened launch argument construction and user data directory resolution for more consistent configuration. * Improved browser startup failure cleanup to ensure resources are released reliably. * Kept troubleshooting output behavior, including better guidance for debugging scenarios. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
c8fb72ae9e |
refactor: split command orchestration handlers (#1155)
## ℹ️ Description - Link to the related issue(s): Issue # - Refactors the CLI command orchestration boundary so command dispatch remains visible while command execution lives in focused handlers. ## 📋 Changes Summary - Split command execution paths in `KleinanzeigenBot.run()` into named handlers for configuration, verification, update checks, content hashing, and ad workflows. - Preserved literal command dispatch cases and command-specific behavior for update checks, download validation, browser login, and cleanup. - Moved German translation keys to the new handler caller names for existing runtime messages. - Added focused tests for update-check behavior, download validation ordering, workspace state usage, and translation key placement. - Lowered the configured branch and cyclomatic complexity limits now that the command orchestration boundary is simpler. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Strengthened code quality standards by implementing stricter complexity thresholds in the development configuration. * **Refactor** * Reorganized command handler architecture to improve internal code structure and maintainability. * **Tests** * Significantly expanded test coverage to validate command execution, argument handling, and translation data integrity. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
75f34775e2 |
refactor: reduce return-count complexity (#1154)
## ℹ️ Description - Link to the related issue(s): Issue # - Reduces return-count complexity in the update checker while preserving existing update-check behavior. ## 📋 Changes Summary - Extracted GitHub release selection and commit-ish validation from `check_for_updates` into a private helper. - Moved German translation keys for logger calls that now originate from the helper. - Ratcheted Ruff/Pylint `max-returns` from 10 to 8. ### ⚙️ Type of Change - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * The update checker now correctly handles the latest update channel by excluding pre-release versions and recommending only stable releases. * **Chores** * Code quality configuration settings were adjusted. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
66cab91898 |
refactor: reduce return-count complexity (#1153)
## ℹ️ Description This refactor reduces return-count complexity for the next PLR0911 ratchet while preserving existing behavior. No related issue. ## 📋 Changes Summary - Extract German and English pluralization helpers while keeping translation and prefix handling in `pluralize()`. - Remove one early return from `check_for_updates()` by sharing the existing final state update/save path. - Ratchet Ruff `PLR0911` `max-returns` from 12 to 10. - Document the one-lower discovery result: `check_for_updates()` is the next limiter at 10 returns for `max-returns = 9`. - No dependencies, configuration requirements, documentation updates, or generated artifacts are introduced. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. No documentation changes were needed. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Reorganized pluralization logic and simplified update-checking control flow for improved code maintainability. * **Tests** * Expanded test coverage for pluralization with additional German and English language variations. * **Chores** * Updated code quality configuration standards. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
e8752ce10e |
refactor: reduce price reduction complexity (#1152)
## ℹ️ Description - Link to the related issue(s): Issue # - Extracts the first complexity hotspot in the ratcheting sequence by separating the final auto price-reduction application flow from `apply_auto_price_reduction`. - This keeps behavior unchanged while allowing the Ruff `max-returns` transitional limit to move from 13 to 12. ## 📋 Changes Summary - Extracted `_apply_price_reduction_decision` for the final price-reduction mutation/logging phase. - Moved German translations for the relocated `LOG.info` calls to the new helper function key. - Lowered `tool.ruff.lint.pylint.max-returns` from 13 to 12. - No dependency or runtime configuration changes introduced. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) Refactor-only change; none of the listed user-facing change types apply. ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Updated linting configuration thresholds for code quality standards. * **Refactor** * Improved internal code organization for better maintainability. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
801ed0e223 |
refactor: remove KleinanzeigenBot re-export from package root (#1150)
## ℹ️ Description - Link to the related issue(s): N/A - Removes the unsupported package-root `KleinanzeigenBot` re-export after tests were moved to their owning modules. - Updates remaining tests and `conftest.py` to import `KleinanzeigenBot` from `kleinanzeigen_bot.app` directly. - Re-enables Ruff's mccabe complexity checks and tightens high Pylint complexity thresholds left over from the old package-root monolith. ## 📋 Changes Summary - Removed `KleinanzeigenBot` from `src/kleinanzeigen_bot/__init__.py`. - Updated all remaining test imports to use `from kleinanzeigen_bot.app import KleinanzeigenBot`. - Enabled `C90`/mccabe complexity linting with an explicit `max-complexity`. - Lowered the broad Pylint limits for branches, locals, returns, statements, and public methods. - Kept the generated/static pydantic error-code mapping explicitly exempted from complexity checks. - No runtime behavior, CLI, config, translations, or ad YAML changes. - No new dependencies. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [x] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Reorganized internal module import structure for consistency across the codebase. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
3c17f3c8dd |
refactor: move cross-drive fallback test (#1149)
## ℹ️ Description - Link to the related issue(s): Issue # - Move the Windows cross-drive fallback coverage from the package-init test module into the publishing workflow test suite. - This is a behavior-neutral test organization cleanup. ## 📋 Changes Summary - Moved the cross-drive auto-price-reduction path fallback test into `TestAutoPriceReductionDispatch`. - Deleted the now-empty `tests/unit/test_init.py` and its unused local helpers. - No runtime code, CLI behavior, config, translations, or ad YAML changed. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * Reorganized test structure for Windows cross-drive path handling validation to improve maintainability. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
48e88fccd3 |
refactor: create app test file and move shell tests (#1148)
## ℹ️ Description - Link to the related issue(s): Issue # - Move app-shell unit tests into a dedicated test module matching `src/kleinanzeigen_bot/app.py`. ## 📋 Changes Summary - Added `tests/unit/test_app.py` for the app-shell test classes and shared fixture. - Kept the cross-drive path fallback coverage in `tests/unit/test_init.py`. - Updated the moved test module to import `KleinanzeigenBot` from `kleinanzeigen_bot.app`. - No runtime, CLI, config, translation, or ad YAML changes. ### ⚙️ Type of Change - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) - Test organization refactor only. ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * Added comprehensive unit tests covering command-line subcommands (including defaulting/fallback behavior for ad selector options) and unknown-command handling. * Added assertions for expected initialization behavior and invalid selector validation (including SystemExit code 2). * Refined the unit test modules to simplify imports and improve maintainability, while retaining key cross-drive publish fallback verification. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
d0d8e5461b |
refactor: move shipping form tests (#1147)
## ℹ️ Description - Link to the related issue(s): Issue # - Move the shipping option mapping test to the publishing form test module, where the browser-level shipping form behavior is owned. ## 📋 Changes Summary - Moved `test_shipping_options_mapping` from `tests/unit/test_init.py` to `tests/unit/test_publishing_form.py`. - Kept the existing assertions and patch targets intact. - Renamed the remaining `test_init.py` class to describe its cross-drive path fallback coverage. - No runtime behavior, CLI, config, translation, or ad YAML changes. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * Reorganized test coverage for publishing and shipping functionality * Added tests for Windows cross-drive path fallback behavior * Added tests for shipping options mapping verification <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
824ff70e43 |
refactor: move publishing result tests (#1146)
## ℹ️ Description - Link to the related issue(s): N/A - Moves a focused set of publish-ad orchestration/result tests out of the package initialization test module and into the publishing workflow test module. ## 📋 Changes Summary - Move pre-submit timeout retry coverage into `tests/unit/test_publishing_workflow.py`. - Move WANTED shipping delegation coverage into the publishing workflow tests. - Move auto price reduction dispatch coverage into the publishing workflow tests. - Remove now-unused local fixture/imports from `tests/unit/test_init.py`. - No runtime, CLI, config, translation, or ad YAML changes. ### ⚙️ Type of Change - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) - [x] Refactor / test organization only ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * Adjusted test coverage for internal functionality validation. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
01e764a477 |
refactor: move publish uncertainty tests (#1145)
## ℹ️ Description - Link to the related issue(s): Issue # - Moves publish-ad post-submit uncertainty tests into the publishing workflow test module so `test_init.py` keeps shrinking toward initializer-focused coverage. ## 📋 Changes Summary - Moved the post-submit uncertainty `publish_ad()` test slice into `tests/unit/test_publishing_workflow.py`. - Kept the pre-submit retryability test and unrelated initializer/CLI/login/shipping/ad-management tests in `tests/unit/test_init.py`. - Adjusted test imports only; no runtime behavior, configuration, translation, or YAML changes. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * Reorganized test coverage for publishing workflows, expanding validation of post-submit error handling and confirmation fallback mechanisms to ensure robust publication behavior under various scenarios. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
f54521b8e6 |
refactor: move publishing diagnostics tests (#1144)
## ℹ️ Description - Link to the related issue(s): N/A - Move the publish failure diagnostics tests out of the initializer-focused unit test module and into the publishing workflow unit test module. - This is a behavior-neutral test organization change. ## 📋 Changes Summary - Moved `TestKleinanzeigenBotDiagnostics` from `tests/unit/test_init.py` to `tests/unit/test_publishing_workflow.py`. - Kept existing assertions and publishing workflow patch targets unchanged. - Removed stale imports from `tests/unit/test_init.py`. - No runtime, CLI, config, translation, or ad YAML changes. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * Enhanced test coverage for diagnostics capture during publishing failures, including verification of log file handling and behavior when diagnostics are disabled. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
2332682d07 |
refactor: move publishing orchestration tests (#1143)
## ℹ️ Description - Link to the related issue(s): Issue #977 - Move another focused set of publishing/update orchestration tests out of `tests/unit/test_init.py` and into `tests/unit/test_publishing_workflow.py`. - This is a behavior-neutral test organization change; no runtime, CLI, config, translation, or ad YAML behavior changes are intended. ## 📋 Changes Summary - Moved display counter progression coverage into the publishing workflow test module. - Moved publish-ads orchestration coverage into a dedicated publishing workflow test class. - Cleaned up imports left behind in `tests/unit/test_init.py`. - Dependencies/configuration/additional requirements: none. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) Test-only refactor; none of the listed runtime change categories apply. ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. Not applicable; test-only relocation. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * Improved the ad publishing workflow test coverage by reorganizing publish/cleanup, retry behavior, and “no-retry” scenarios. * Added new async testing utilities (including a reusable mocked page) to better simulate browser interactions. * Expanded regression coverage for processing/counter progression across publishing and updating, including paused ads and “not found” cases. * Removed several redundant or replaced counter/retry/skip tests from the prior initialization test module. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
29aed68706 |
refactor: move publishing workflow tests (#1142)
## ℹ️ Description - Link to the related issue(s): Follow-up to #1141 - Move a publishing/update orchestration test slice into the publishing workflow test module. - Share duplicated test fixtures/helpers that are now used by the relocated publishing workflow tests and existing related tests. - This remains behavior-neutral test organization only. ## 📋 Changes Summary - Added `tests/unit/test_publishing_workflow.py` for publishing workflow orchestration tests. - Moved `TestKleinanzeigenBotUpdateAdsResilience` out of `tests/unit/test_init.py`. - Updated the relocated tests to import `KleinanzeigenBot` directly from `kleinanzeigen_bot.app`. - Moved the duplicated `base_ad_config` fixture into `tests/conftest.py`. - Extracted shared `build_update_ad` and `build_published_ads` test helpers into `tests/conftest.py`. - Removed duplicate fixture/helper definitions from affected unit test files. - No runtime behavior, CLI output, config parsing, translations, or ad YAML handling changes. ### ⚙️ Type of Change - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) - [x] Maintenance/refactor (tests only, no runtime behavior change) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Tests** * Added comprehensive tests for ad publishing resilience and orchestration, covering retry mechanisms, error handling, timeout scenarios, and failure propagation across different ad states * Reorganized and consolidated test utilities, shared fixtures, and builder helpers across test modules <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
ee581e383f |
refactor: clean up source hygiene (#1141)
## ℹ️ Description - Link to the related issue(s): Issue # - Clean up minor post-extraction source hygiene without changing runtime behavior. ## 📋 Changes Summary - Import `KleinanzeigenBot` from its concrete `app` module in the CLI. - Update stale source comments/docstrings that referenced the previous package structure. - No dependencies, configuration changes, CLI output changes, translation changes, or ad YAML handling changes. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Chores** * Refactored internal code organization by adjusting module imports and updating code documentation references to enhance maintainability and clarity. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
f5f3399a66 |
refactor: move app shell out of package init (#1140)
## ℹ️ Description Move the `KleinanzeigenBot` application class out of `__init__.py` into a dedicated `app.py` module. This continues the maintainability-focused refactoring of the package initializer that was started in prior PRs (login flow extraction, publishing workflow extraction, etc.). - Link to the related issue(s): N/A ## 📋 Changes Summary - **New `src/kleinanzeigen_bot/app.py`** (525 lines): contains the full `KleinanzeigenBot` class with all imports, constructor, `run()` command dispatch, `load_ads()`, and delegator methods - **`src/kleinanzeigen_bot/__init__.py`**: reduced from 545 lines to 27 lines — thin package initializer with `colorama` init, `LOG` setup, `KleinanzeigenBot` re-export from `app.py`, `main()` delegator, and `__name__` guard - **Translations**: split `__init__.py` section header in `translations.de.yaml`; class-owned translations moved to new `kleinanzeigen_bot/app.py:` section - **Tests**: updated patch targets from package-root paths to concrete module paths (`kleinanzeigen_bot.UpdateChecker` → `kleinanzeigen_bot.update_checker.UpdateChecker`) ### ⚙️ Type of Change - [ ] 🐞 Bug fix - [ ] ✨ New feature - [ ] 💥 Breaking change - [x] 🔧 Refactoring (no user-facing behavior changes) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Centralized runtime command handling in a new application entrypoint class while keeping the same CLI-style command set. * Slimmed the package initializer to re-export the main bot class and delegate CLI execution through `main(args)`. * **Bug Fixes** * Improved Windows console compatibility during startup. * **Tests** * Updated unit tests and mocks to reflect the new location of command-handling logic and related wiring. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
35bd393dc4 |
refactor: extract login/auth flow into login_flow.py (#1139)
## ℹ️ Description Extract all login, Auth0 form-fill, captcha, SMS/email verification, GDPR, login-state detection, and diagnostics-capture logic from `__init__.py` into a new `login_flow.py` module. ## 📋 Changes Summary - Create `login_flow.py` (~634 lines) with module-level async functions accepting explicit `web: WebScrapingMixin` + keyword arguments - Thin delegators in `__init__.py` bind `KleinanzeigenBot` instance attributes to module calls - Remove 12 dead delegator methods; tests call module functions directly - Move `LoginDetectionResult`/`LoginDetectionReason` types to `login_flow` - Move `TestKleinanzeigenBotAuthentication` to `tests/unit/test_login_flow.py`, update patch targets - Move login translations to `login_flow.py` section in `translations.de.yaml` - Fix diagnostics guard reset per login attempt - Remove `is_logged_in_web()`; pass username explicitly - Make cross-module functions public: `login_flow` internal helpers and `WebScrapingMixin` helpers (`dismiss_consent_banner`, `effective_timeout`, `extract_visible_text`) ### ⚙️ Type of Change - [x] ✨ New feature (adds new functionality without breaking existing usage) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **Refactor** * Reworked the authentication/login process to use a dedicated login flow, improving handling of multi-step sign-in and related verification prompts. * Standardized login-status detection and diagnostics behavior when login state can’t be determined. * Updated text-extraction and timeout behavior for DOM-based fallbacks, and aligned consent-banner dismissal to the public API. * **Tests** * Added extensive unit tests for the login flow and login-state detection. * Updated existing tests to reflect the refactored helpers and consent-banner method naming. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
ecd3ea35cf |
refactor: extract publishing workflow (#1137)
## ℹ️ Description - Link to the related issue(s): N/A - Extracts publish/update orchestration from the monolithic bot class into `publishing_workflow.py` as Step 21 of the monolith breakdown. ## 📋 Changes Summary - Added `src/kleinanzeigen_bot/publishing_workflow.py` for publish/update orchestration, retry/uncertainty handling, result checks, and delete-before/after-publish wiring. - Kept `KleinanzeigenBot` publish/update methods as narrow delegation seams with explicit dependencies. - Moved WANTED ad type selection into `publishing_form.fill_ad_form()` so form details stay in the form module. - Updated German translations and unit tests to patch concrete workflow module paths. - No dependency or configuration changes. ### ⚙️ Type of Change - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) - [x] Refactor (no user-facing behavior change) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved form rendering for WANTED ad type by ensuring the ad type is pre-selected before populating other form fields. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
eae9dc9fc1 |
refactor: extract publishing form orchestrator (#1136)
## ℹ️ Description Move the last form-filling remnant out of `__init__.py` into `publishing_form.py`, where all individual form section functions already live. - `_fill_ad_form()` only delegated to the already-extracted section functions (`set_category`, `set_special_attributes`, `set_shipping_form`, `set_pricing_fields`, `set_contact_fields`, `fill_image_section`). - Replaced with a public module-level `publishing_form.fill_ad_form()` that accepts explicit `web`, `root_url`, `ad_defaults`, `ad_file`, `ad_cfg`, and `mode` parameters. - `publish_ad()` now calls `_publishing_form.fill_ad_form(self, ...)` instead of `self._fill_ad_form(...)`. ## 📋 Changes Summary - Extracted `fill_ad_form()` into `publishing_form.py` as a public module-level async function - Removed `_fill_ad_form()` method from `KleinanzeigenBot` class - Updated call site in `publish_ad()` to pass explicit parameters - Updated test patch target in `test_publishing_persistence.py` and docstring in `test_init.py` ### ⚙️ Type of Change - [ ] 🐞 Bug fix - [ ] ✨ New feature - [ ] 💥 Breaking change ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Reorganized ad form-filling logic for improved maintainability and code structure. * **Tests** * Updated unit tests to reflect internal code reorganization. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
154c37b26e |
refactor: extract special-attributes/condition form section (#1135)
## ℹ️ Description Extracts special-attribute and condition form logic from `__init__.py` into `publishing_form.py` to continue module decomposition. ## 📋 Changes Summary - **`publishing_form.py`**: Added `set_special_attributes`, `_set_condition`, and helpers (`_pick_special_attribute_candidate`, `_special_attribute_candidate_priority`, `_describe_special_attribute_candidate`) adapted as module-level functions taking `web: WebScrapingMixin` - **`__init__.py`**: Removed the moved functions, cleaned up stale imports (`re`, `_ad_form_helpers`, `_select_button_combobox`, `ensure`, `Element`), updated `_fill_ad_form` to delegate via `_publishing_form.set_special_attributes()` - **`translations.de.yaml`**: Moved `_set_condition` and `set_special_attributes` sections from `__init__.py:` → `publishing_form.py:` block - **`test_init.py`**: Moved special-attribute and condition tests to `test_publishing_form.py`, updated orchestration patch targets - **`test_publishing_form.py`**: Added `TestSpecialAttributes`, `TestConditionSelector`, and `TestConditionFallbackToGenericHandler` classes with adapted imports and patches ### ⚙️ Type of Change - [x] Refactor — no behavior changes, internal module reorganization only ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. |
||
|
|
875b8b063a |
refactor: extract publishing shipping form section (#1134)
## ℹ️ Description - Extracts the publishing shipping form workflow from `KleinanzeigenBot` into `publishing_form.py`. - Keeps runtime behavior, selectors, waits, messages, and browser interactions unchanged while moving translation ownership. ## 📋 Changes Summary - Move WANTED shipping handling, shipping radio/dialog handling, shipping option toggling, and the private React-fiber button-combobox helper into `publishing_form.py`. - Update `__init__.py` to delegate shipping form work and keep only orchestration/seam responsibilities. - Move direct shipping behavior tests to `tests/unit/test_publishing_form.py`; keep a shipping orchestration seam test in `tests/unit/test_init.py`. - Move German translation entries for shipping messages to the `publishing_form.py` translation section. ### ⚙️ Type of Change - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Summary of changes * **Refactor** * Improved publishing ad shipping form handling by routing wanted vs non-wanted ads to the correct UI flow. * Enhanced Versand (shipping) combobox selection for wanted ads to ensure the right option is chosen. * Strengthened the shipping dialog flow for pickup vs shipping-with-options, including more reliable shipping price confirmation and retry behavior. * **Tests** * Expanded unit tests covering shipping dialog interactions, carrier/option selection, wanted-shipping combobox behavior, and timeout/error scenarios. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
e9ed698dce |
refactor: extract publishing pricing form section (#1133)
## ℹ️ Description - Link to the related issue(s): Issue # - Extracts the publishing pricing/direct-buy/description form section from the main bot class as the next monolith-breakdown step. ## 📋 Changes Summary - Added publishing_form.set_pricing_fields() for price type/amount, sell-directly/direct-buy radios, and description filling. - Replaced the inline _fill_ad_form() pricing block with the new publishing form section call. - Moved direct unit coverage for pricing/direct-buy/description behavior into test_publishing_form.py and kept orchestration seam tests in test_init.py. - Moved existing German translation ownership entries to the new function path without wording changes. - No dependencies, configuration changes, CLI changes, schema changes, or generated artifacts. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project standards. - [x] I have tested my changes and ensured that all tests pass (pdm run test). - [x] I have formatted the code (pdm run format). - [x] I have verified that linting passes (pdm run lint). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **Refactor** * Centralized pricing-related ad form filling (price type, price amount, ad description with affixes, and direct-buy/buy-now controls) into a shared publishing helper for more consistent behavior. * **Bug Fixes** * Improved handling of pricing/buy-now selection failures by surfacing clearer, localized timeout errors. * **Tests** * Added dedicated coverage for pricing field interactions, including dropdown skipping when not applicable, correct amount input behavior, and description generation usage. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
137a7691a7 |
refactor: extract publishing image form section (#1132)
## ℹ️ Description - Link to the related issue(s): N/A - Extracts the publishing image cleanup and upload section from the bot monolith into `publishing_form.py` as Step 16 of the monolith breakdown plan. ## 📋 Changes Summary - Move image cleanup/upload behavior into `fill_image_section()` and `upload_images()`. - Replace the monolith image block with a publishing form seam call. - Move direct image behavior tests from `test_init.py` to `test_publishing_form.py`. - Update German translation ownership paths without changing translated text. - No dependency, configuration, CLI, schema, or generated artifact changes. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) - [x] ♻️ Refactor (no intended behavior change) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Image upload handling has been reorganized and consolidated in the publishing module for improved code organization. The image processing workflow now includes enhanced timeout management and marker-based completion detection to ensure all images are reliably processed during ad publication. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
9d146c2b96 |
refactor: extract publishing contact form section (#1131)
## ℹ️ Description - Link to the related issue(s): Issue # - Refactors the publishing form code by moving the contact/location form section out of the package initializer into the publishing form module. ## 📋 Changes Summary - Move contact field handling, contact location handling, and city combobox helpers into publishing_form.py. - Keep the publishing form orchestration delegating through an explicit web/contact boundary. - Update unit tests to patch and call the new publishing form functions. - Move German translation ownership paths for the relocated messages without changing translated text. - No dependencies, configuration changes, or additional requirements introduced. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (pdm run test). - [x] I have formatted the code (pdm run format). - [x] I have verified that linting passes (pdm run lint). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Updated ad publishing to populate contact and location fields via dedicated public publishing-form helpers, with revised import wiring for ad model types. * Removed older internal city/contact handling logic and replaced it with clearer helper-driven flow. * **Bug Fixes** * Improved city/location hardening: safer city extraction, combobox-style selection with ambiguity checks, timeout-based fallbacks, and correct handling for read-only city inputs. * More resilient contact field population (zipcode/location, street, name, phone), with graceful handling when optional elements are missing. * **Tests** * Added/updated unit tests to cover city/contact hardening and category probe/picker selection behaviors, asserting helper calls rather than private methods. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
f02816cb06 |
refactor: extract publishing category form section (#1130)
## ℹ️ Description - Link to the related issue(s): N/A - Extracts the publishing category form section from the monolithic bot class into a focused publishing form module while preserving category selection and suggestion fallback behavior. ## 📋 Changes Summary - Move category selection and category suggestion fallback into `src/kleinanzeigen_bot/publishing_form.py`. - Update publish form orchestration to call the extracted category function through a narrow web/root_url boundary. - Update unit tests and German translation ownership for the new module path. - No dependencies, configuration changes, or additional requirements introduced. ### ⚙️ Type of Change - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Restructured category selection logic for improved maintainability and code organization. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
dd6a1955ef |
refactor: extract publishing form helpers (#1129)
## ℹ️ Description - Extract browser-independent publishing form helpers from the monolith into `ad_form_helpers.py`. - Prepares later publishing form extraction without changing browser behavior. ## 📋 Changes Summary - Move the Versand combobox selector constant to `ad_form_helpers.py`. - Move location matching logic to `ad_form_helpers.py`. - Update production call sites and helper ownership tests. - Keep form sections and browser-dependent logic in `__init__.py`. ### ⚙️ Type of Change - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Improved internal code organization by consolidating shared helpers for form-related utilities and location matching logic. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
fda56b109c |
refactor: prepare web helpers for publishing form extraction (#1128)
## ℹ️ Description - Link to the related issue(s): Issue #930 - Moves a shared consent-banner browser helper onto the generic web scraping mixin so later publishing form refactors can use it without depending on the main bot class. ## 📋 Changes Summary - Move `_dismiss_consent_banner()` from `KleinanzeigenBot` to `WebScrapingMixin` without changing selector, timeout, click, or sleep behavior. - Move the helper's focused unit tests from `test_init.py` to `test_web_scraping_mixin.py`. - No dependencies, configuration changes, or additional requirements introduced. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) None of the listed categories apply; this is an internal behavior-equivalent refactor. ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **Refactor** * Moved consent-banner dismissal logic into a shared web-scraping helper, and updated the bot flow to proceed directly after SMS verification. * **Tests** * Removed unit tests that covered the old bot-level consent-banner handling. * Added new async unit tests to verify the shared helper clicks the consent accept button when present and does nothing when absent. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
816cf3ed9e |
refactor: rename publishing persistence module (#1127)
## ℹ️ Description - Link to the related issue(s): Issue # - Rename the persistence-only publishing module so the module name matches its current responsibility. ## 📋 Changes Summary - Rename `publishing_flow.py` to `publishing_persistence.py`. - Update production imports/calls and test patch paths. - Move persistence tests to `test_publishing_persistence.py` and keep submission tests under `test_publishing_submission.py`. - Update the German translation section header for the renamed module. ### ⚙️ Type of Change - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Improved the way published ad changes are saved after submitting or updating, ensuring related fields (such as image updates and pricing adjustments) are correctly retained. * **Bug Fixes** * Publishing now continues even if the follow-up save step fails, preventing unnecessary interruptions. * **Tests** * Updated existing tests to match the revised persistence behavior. * Added new unit tests covering persistence outcomes, logging, rollback behavior, and image/price update handling. * Simplified the publishing submission test suite setup. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
5c22795728 |
fix: handle shipping select for pro accounts (#1126)
## ℹ️ Description - Link to the related issue(s): Issue #1125 - Fixes PRO/commercial account publishing where the Versand field is rendered as a custom `button[role="combobox"]` dropdown by the PostListingForm Astro island, not as a native `versand_s` `<select>` and not as the private-account radio-button UI. - Uses the confirmed PRO DOM model from the issue comments/screenshots: category-prefixed IDs such as `kunst.versand` / `uhren.versand`, placeholder `Bitte wählen`, and options `Versand möglich` (`ja`) / `Nur Abholung` (`nein`). ## 📋 Changes Summary - Detect the custom Versand combobox before falling back to the private radio/dialog shipping flow. - Locate the combobox by the confirmed category-prefixed id shape and by the selected-option label relationship (`aria-labelledby$="versand-selected-option"`) so the lookup is not tied to one category prefix. - Select `Versand möglich` for `shipping_type: SHIPPING` and `Nur Abholung` for `shipping_type: PICKUP` by visible option text via `web_select_button_combobox()`. - Apply the same safer Versand combobox selector to the existing WANTED-ad shipping combobox path. - Keep the private/non-commercial radio-button and shipping-options-dialog path as the fallback when the custom combobox is absent. - Add regression coverage for the PRO combobox path and relax existing shipping-flow assertions so they check behavior instead of exact probe ordering/timeout plumbing. - Add the German translation for the combobox error message. ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Improved the WANTED shipping flow to detect and use native “Versand” dropdown controls when available, selecting the correct shipping option directly. * **Bug Fixes** * Added clearer errors for unsupported shipping types and standardized timeout behavior when native selection fails; continues to fall back to the existing radio/dialog approach when the control is missing. * **Tests** * Expanded unit tests to cover the native Versand combobox route, including selector coverage and updated probe/call-order expectations. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
f94567a983 |
fix: use canonical title for owned ad downloads (#1123)
## ℹ️ Description - Link to the related issue(s): Issue #1119 - Fixes owned-ad downloads where the public/detail page title may include UI status decoration that makes the title exceed the semantic 65-character title limit. ## 📋 Changes Summary - Resolve download titles once via manage-ads metadata when available. - Reuse the resolved title for folder naming, file stems, and persisted ad config data. - Keep manual page title extraction as the fallback without stripping or truncation. - Add regression coverage for canonical metadata titles and fallback extraction. ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (pdm run test). - [x] I have formatted the code (pdm run format). - [x] I have verified that linting passes (pdm run lint). - [x] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Improvements** * Enhanced ad title resolution to prioritize cached published metadata when available, with fallback to page extraction for improved reliability. * Improved directory handling to consistently use the resolved ad title for naming and saved info templates. * **Bug Fixes** * Corrected title/metadata extraction flow to avoid redundant title reads and ensure creation dates are reliably sourced from the expected page elements. * **Tests** * Updated and added unit test coverage for title resolution, directory behaviors, and extraction call ordering. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
439c36e851 |
fix: click Auth0 Weiter after captcha (#1120) (#1122)
## ℹ️ Description Fixes issue #1120 by handling the Auth0 captcha branch after email submit. When captcha appears, the bot now probes for a visible/clickable "Weiter" button and clicks it before waiting for the password page. The normal no-captcha login flow remains unchanged. - Link to the related issue(s): Issue #1120 - Describe the motivation and context for this change. ## 📋 Changes Summary - Added a captcha-only Auth0 identifier handler that waits for captcha completion, probes for "Weiter" with `web_probe`, and clicks it if present. - Kept the existing no-captcha login path unchanged. - Updated German translations for the new log messages. - Adjusted unit tests for the new login helper. ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. No additional docs changes were needed beyond translations. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved login robustness to detect optional reCAPTCHA on the email/identifier step; users are notified when a captcha appears, can provide input, and the login resumes once advanced. * **Tests** * Updated unit tests to cover and control the captcha-handling behavior during the login flow, including the missing-password-step scenario. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
5d5c25d753 |
refactor: extract publishing submission flow (#1121)
## ℹ️ Description *Refactor the publishing submission/confirmation flow into a dedicated module while keeping behavior identical.* - Link to the related issue(s): N/A - Describe the motivation and context for this change: Reduce coupling in the publishing workflow and keep the persistence boundary separate. ## 📋 Changes Summary - Added `src/kleinanzeigen_bot/publishing_submission.py` for captcha, submit, confirmation, and ad-id recovery. - Removed the submission/confirmation helpers from `publishing_flow.py`, leaving persistence helpers there. - Updated the `publish_ad()` call site and tests to use the new concrete module path. - Moved the translated log-message entries for the extracted submission flow. ### ⚙️ Type of Change Select the type(s) of change(s) included in this pull request: - [ ] 🐞 Bug fix (non-breaking change which fixes an issue) - [ ] ✨ New feature (adds new functionality without breaking existing usage) - [ ] 💥 Breaking change (changes that might break existing user setups, scripts, or configurations) ## ✅ Checklist Before requesting a review, confirm the following: - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [ ] I have updated documentation where necessary. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Ad submission and confirmation logic moved into a dedicated submission module for clearer separation. * **Bug Fixes** * Improved publish confirmation: better captcha handling, post-submit dialogs (upsell/payment, imprint guidance, “no image”) and avoidance of stale-referrer fallbacks. * Now fails loudly and avoids persisting when ad confirmation is uncertain. * **Tests** * Unit tests updated to target the new submission flow and recovery/persistence behaviors. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
9172af0c69 |
enh: skip runtime bootstrap for update-check command (#1117)
## ℹ️ Description The `update-check` command was calling `_bootstrap_runtime()` which triggered config file creation (`create_default_config`), file logging setup, and browser config application. None of these are needed for a read-only GitHub release version check. This PR skips the full bootstrap and instead uses `UpdateChecker` with sensible defaults from `Config()` and a state path resolved from the already-available workspace. Closes #1090. ## 📋 Changes Summary ### 🚀 Enhancement - **`src/kleinanzeigen_bot/__init__.py`** — `update-check` case: removed `_bootstrap_runtime()` call, uses `self.config = Config()` with sensible defaults, state path from already-resolved `self.workspace`. ### ⚙️ Type of Change - [x] 🚀 New feature / Enhancement (non-breaking change which adds functionality) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. |
||
|
|
97256c1d70 |
fix: apply after_delete policy when title-mode delete returns all-404 with id=None (#1116)
## ℹ️ Description When `delete_old_ads_by_title=True` and `ad_cfg.id=None` and all remote DELETE requests return 404, the `after_delete` policy (DISABLE/RESET) was silently skipped because the orchestrator's `id_before`/`id_after` heuristic could not distinguish "not attempted" from "attempted but all 404." This PR replaces the heuristic with an explicit `DeleteResult` NamedTuple returned from `delete_ad()`, communicating whether HTTP DELETE requests were actually sent (`attempted`) separately from whether any returned 200 (`deleted`). Closes #1103. ## 📋 Changes Summary ### 🐞 Bug fix - **`delete_flow.py`** — New `DeleteResult(deleted, attempted)` NamedTuple replaces the `bool` return from `delete_ad()`. The orchestrator now uses `result.attempted` directly to decide whether to apply `after_delete` policy. - Removed the fragile `id_before`/`ad_cfg.id`-based heuristic entirely. ### 🧪 Tests - Updated all 9 existing `delete_ad()` tests for the new tuple return type - Updated 3 orchestrator tests (`delete_ads`) for the new `DeleteResult` API - Added regression test `test_cleanup_on_title_match_all_404_with_id_none` — `ad_cfg.id=None`, title-match, all responses 404, `after_delete=RESET` is applied ### ⚙️ Type of Change - [x] 🐞 Bug fix (non-breaking change which fixes an issue) ## ✅ Checklist - [x] I have reviewed my changes to ensure they meet the project's standards. - [x] I have tested my changes and ensured that all tests pass (`pdm run test`). - [x] I have formatted the code (`pdm run format`). - [x] I have verified that linting passes (`pdm run lint`). - [x] I have updated documentation where necessary. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved deletion tracking to distinguish attempted vs successful deletions, ensuring cleanup policies run correctly across edge cases. * **Tests** * Updated unit tests to reflect the new deletion outcomes and added a regression test to verify cleanup behavior when title-mode deletions all fail. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |