Commit Graph
20 Commits
Author SHA1 Message Date
Adam Daley 70577c36ba Fix client theme quality checks and Docker asset builds 2026-10-23 00:51:34 +01:00
Adam Daley 248148dc2e Modernise the client area and share default theme components 2026-10-23 00:34:55 +01:00
Adam Daley 161f1328b8 Replace legacy hooks with typed Symfony events (#4400)
* Add typed Symfony events alongside legacy hooks

* Move admin login activity to typed event listener

* Move client login activity to typed event listener

* Add typed events for cron currency and notifications

* Add typed extension lifecycle events for widget cache

* Avoid duplicate typed listener registration

* Add typed events for settings subscriptions and client deletion

* Migrate core cron hooks to typed Symfony listeners

* Migrate support ticket hooks to typed events

* Migrate client and profile lifecycle hooks to typed events

* Migrate authentication hooks to typed events

* Migrate staff checkout and order lifecycle events

* Migrate cart, order batch, invoice, and staff reset hooks

* Migrate extension, invoice, system, and service hooks

* Retire legacy hook runtime and finish reminder events

* Clean up retired hook data during upgrades

* Clarify reminder events and complete gateway cancellation

* Document current typed event development model

* Apply Rector suggestions for typed event changes
2026-09-24 01:19:05 +01:00
Adam Daley 2fbecd5b99 Harden null handling across core, adapters, and templates (#4384)
* Harden null handling across core, adapters, and templates

Guard the currency fraction-digit lookup when zlib is unavailable, map unknown GeoIP country codes to incomplete records, tolerate object app options and controllers without a register method, default missing ResellerClub and PayPal IPN fields, and hide server rows when a hosting order has no server.

* Guard non-string GeoIP country codes before enum lookup
2026-09-21 11:55:52 +01:00
Adam Daley 1432a7cf79 Simplify core library hot paths (#4365)
* Simplify core library hot paths

* Address review feedback
2026-09-19 18:18:22 +01:00
Adam Daley de116893b6 Harden URL, mail, and locale handling (#4359)
* Harden URL, mail, and locale handling

* Keep Sentry hardening mail test offline with unsupported DSN scheme

* Move Sentry regression tests into their module test files

* Drop Sentry issue IDs from regression test names

* Drop Sentry issue ID from Twig cache failure test name

* Drop Sentry issue IDs from test comments
2026-09-19 13:49:38 +01:00
Adam Daley bae0bffcfd Bundle default admin/client themes into a theme package (#4271) 2026-09-05 01:18:43 +01:00
Adam Daley bbe5f89317 Stop Twig cache-directory write failures from flooding Sentry (#4277)
* Stop Twig cache-directory write failures from flooding Sentry

Twig's FilesystemCache throws a raw \RuntimeException when it can't
create or write to the configured template cache directory (data/cache),
which happens whenever a host's file permissions are wrong. That
exception was completely uncaught, so every affected visitor got a raw
500 and every occurrence was reported to Sentry as a code bug even
though it's a host misconfiguration we can't fix from within the app -
this is the same class of noise fixed for the cache backend in #4275,
just from a different code path (~60k events across 4 duplicate-shaped
Sentry issues: FOSSBILLING-EBW/J8N/EWG/EWV).

Box_App::convertCacheWriteFailure() now catches it in both
Box_AppClient::render() and Box_AppAdmin::render(), converts it into a
FOSSBilling\Exception with a new Cache-category error code (5002), and
rethrows anything else unchanged. ErrorPage marks 5002 report:false, so
Sentry stops seeing it while the visitor still gets a proper error page.

* Handle all three Twig cache-write failure messages, not just one

CodeRabbit review on #4277: Twig\Cache\FilesystemCache::write() throws
three different \RuntimeException messages for the same underlying
problem (missing/unwritable data/cache directory) - 'Unable to create
the cache directory', 'Unable to write in the cache directory', and
'Failed to write cache file'. convertCacheWriteFailure() only matched
the first, so the other two still fell through as raw, Sentry-reported
fatals. Match all three, with a regression case for each.

* Don't imply file permissions are the only cause of a cache write failure

CodeRabbit review on #4276 (same code as here): 'Failed to write cache
file' can also come from a full disk, a hit quota, or a read-only
mount, not just a permissions problem - the error message told the
admin to check permissions when that might not be the actual cause.
Broadened the wording to also point at disk space.
2026-09-04 09:57:25 +01:00
Adam Daley b364588f30 Harden release cleanup and updater integrity (#4166) 2026-08-15 15:27:15 +01:00
Adam Daley 7f892a10c7 Replace Box_Database with Doctrine DBAL (#4139)
* Replace Box_Database usage with Doctrine DBAL

* Harden invoice lookups and DB session setup

* Clean up invoice renewal test mock

* Make DB session timeouts configurable
2026-08-11 02:37:46 +01:00
Adam Daley 56aed6bec5 Allow custom recurring billing periods (#4102)
* ✨ Allow custom recurring billing periods

Products were limited to a fixed set of 7 hardcoded recurring billing
periods (1W/1M/3M/6M/1Y/2Y/3Y), stored as fixed columns on
product_payment. Admins can now configure any number of arbitrary
periods per product (e.g. 45 days, 18 months, 5 years) within
Box_Period's existing valid ranges, while the original 7 periods
remain as pre-filled defaults and one-click quick-add presets.

- Replace product_payment's fixed w/m/q/b/a/bia/tria columns with a
  new product_payment_period table (one row per configured period),
  migrated via UpdatePatcher::patch98().
- Rework the admin product pricing UI to add/remove billing periods
  by quantity + unit (day/week/month/year), in addition to the
  existing presets.
- Fix Box_Period's constructor, which only ever accepted a
  single-digit quantity (e.g. "9Y" but not "24M" or "45D") despite
  its own unit bounds implying otherwise.
- Fix period labels silently disappearing in the client checkout,
  admin order form, and admin subscription edit screens for any
  period outside Box_Period's 9 presets, by having the API return a
  precomputed title per period instead of relying on a second lookup.
- Fix the Stripe adapter dropping the period quantity entirely when
  creating recurring prices (e.g. quarterly/biannual products were
  silently billed monthly), and reject periods that exceed Stripe's
  own interval_count caps instead of mis-billing them.

Closes #4098

* Address review feedback on custom billing periods

- Make patch98's period migration INSERT idempotent with ON DUPLICATE
  KEY UPDATE, so a rerun after a partial failure doesn't hit the
  (product_payment_id, code) unique constraint.
- Order ProductPayment::$periods by sortOrder so the admin's edit
  order is preserved on reload, matching the pattern already used by
  ServiceDownloadable's ordered collection.
- Wrap the Box_Period parsing failure in
  getEnabledProductPaymentPeriod() so a malformed/missing period
  raises FOSSBilling\InformationException instead of a raw exception,
  matching applyPricingToProductPayment()'s handling.
- Fix the Stripe adapter reusing a wrong-cadence price: Stripe's price
  list filter only supports 'interval', not 'interval_count', so the
  existing-price match now also compares interval_count explicitly.
- Stop the admin pricing form from resurrecting default periods an
  admin had deliberately removed - defaults are now only used when a
  product has no configured periods at all.
- Drop the redundant product_payment_id_idx index, since the unique
  key on (product_payment_id, code) already covers lookups on
  product_payment_id via its leftmost prefix.

* Fix quantity validation and i18n in the add-period JS

- Use Number() + Number.isInteger() instead of parseInt() to validate
  the custom period quantity, so a fractional value like "5.7" is
  rejected instead of silently truncated to 5.
- Replace the English-only '(s)' suffix hack for pluralizing the unit
  label with translated data-singular/data-plural attributes on each
  unit option, selected based on quantity.
2026-08-06 21:39:00 +01:00
Adam Daley 59fae43df5 Fix client sessions, form fields, and error pages (#4011)
* Fix client sessions, form fields, and error pages

* Redirect authenticated clients away from login
2026-07-17 20:03:05 +01:00
Adam Daley 17ee2d7f29 Fix Twig currency locale formatting (#3998) 2026-07-17 14:28:42 +01:00
0eb6610f5a Apply PHP Code Styling & Quality Changes (#3940)
* Apply PHP Code Styling & Quality Changes

* Fix fingerprint PHPStan error

---------

Co-authored-by: FOSSBilling Bot <fossbilling-bot>
Co-authored-by: Adam Daley <admdly@users.noreply.github.com>
2026-07-09 05:44:18 +01:00
Adam Daley 85cd7aac2a Modernize HTTP response flow (#3928)
* Modernize HTTP response flow

* Fix route matcher test spelling
2026-07-07 05:15:39 +01:00
Adam Daley 800a7456d8 Stop mapping timers before debugbar collection (#3907)
* Stop mapping timers before debugbar collection

* Fix DebugBar timing PHPStan type

* Refactor timing measure stop checks in Box_App
2026-07-06 19:55:33 +01:00
Adam Daley 102e97bd61 Modernize HTTP routing and response handling (#3892)
* Modernize Box app HTTP routing

* Use response factory for module redirects

* Clean up IPN response handling
2026-07-05 00:54:07 +01:00
Adam Daley 1efffee98b Handle Twig render failures as 500 errors (#3874)
* Handle Twig render failures as 500 errors

* Fix nested Twig loader error handling

* Fix AppClient missing page test stub
2026-07-02 11:48:08 +01:00
83949ce8f0 Apply PHP Code Styling & Quality Changes (#3705)
Co-authored-by: FOSSBilling Bot <fossbilling-bot>
Co-authored-by: Adam Daley <admdly@users.noreply.github.com>
2026-06-03 11:31:36 +01:00
Adam Daley dd3dcbfd52 Enhance type safety, authentication checks, and testing framework (#3701)
* Improve type safety, auth checks and PHPStan fixes (#3250)

* Improve type safety, auth checks and PHPStan fixes

* Remove @phpstan-ignore annotations

* Improve type safety, auth checks and PHPStan fixes

* Remove @phpstan-ignore annotations

* Remove redundant @phpstan-ignore comment

* Improve code robustness and reliability (#3248)

* Harden code against null/undefined values

* Update dependency lockfiles

* Sanitize ticket input and use IDs in email list

* Restructure tests and add test utilities

* Move E2E tests to `Library\E2E` namespace

* Update `php-build` action ref in workflows

* Switch tests to Pest and add test scaffolding

* Refactor E2E tests to Pest-style tests

m

Skip E2E tests when env not configured

* Refactor Unit tests and update test config

Add test datasets and refine test helpers

* Add DEBUG guard, fix API JSON decode, update tests

* Refactor tests: add types and Mockery expectations

* Adjust tests, phpstan config, and composer script

* Instantiate test APIs locally, remove beforeEach

* Refactor runtime checks, types & logging

* Apply PHP Code Styling Changes

m

* Add PHPStan ignores, test renames & small fixes

* Enable Pest tests in CI workflow

* Remove legacy tests; add new unit tests/config

* Avoid undefined index in fingerprint comparison

* Ignore properties absent in both fingerprints

* Remove public_ticket_create API method

* Add Fingerprint unit tests

* Remove em dash from fingerprint test name

* Switch to Pest; assorted bug fixes & refactors

* Prefer getDi() and guard DEBUG define

* Refactor tests: DBAL, Antispam rename, helpers

* Refactor email tests to use Doctrine entities

* Update tests, use DBAL mocks & improve Formbuilder admin

* Validate plan_id and update unit tests

* Replace error_log with DI logger and update tests

* Expect db->store in Invoice Service test

* Use DI logger instead of error_log; fix tests

* Fix typo in Hook Service test

* Fix Staff test spelling fixture

* Complete Pest test migration

* Fix Product test spelling fixtures

* Fix Product test spelling fixtures

* Run live tests with Pest and load helpers

* Migrate tests to ApiClient; remove legacy APIHelper

* Fix Email test spelling

* Remove unused PHPUnit bridge

* Organize Cypress end-to-end tests

* Document Pest test directory root

* Remove noisy Pest comments
2026-06-02 07:43:01 +01:00