Moving a running time entry to another member could give that member's
user a second running time entry. Stopping the time entry and changing
the member in the same request is still allowed.
The running time entry check in the store endpoint was scoped to the
member, so a user could start a time entry in each of their
organizations. The active time entry endpoint and the database
consistency check expect only one running time entry per user.
Partial updates of time entries only validated end against start if both
were part of the payload. Start and end are now also validated against the
persisted value if only one of them is sent (fixes#1189).
The importers now fail if the end of a time entry is before the start and
the database consistency check reports such time entries.
Re-adds the copy of the import data that was removed in 70646a0d. Every import stores its raw data in import/{date}-{organizationId}-{uuid} on the private disk.
Production runs as long-lived Octane workers in FrankenPHP worker mode, so state leaking between requests
(static properties, singletons, ...) is a real risk that php artisan serve cannot reproduce. Base the scanner image
on the production FrankenPHP image, add start-octane.sh (single worker, production Caddyfile) and describe this
class of issue in the threat model.
Bundle Gotenberg (Chromium only) so the PDF export tests pass offline and PDF rendering can be exercised.
Remove redundant @var annotations from API resources and defer the user
access in the email unique rule of UserUpdateRequest, so rules() can be
evaluated by Scramble without route model binding. Add a test that fails
on any Scramble diagnostic and tests for the email unique rule.
Scramble 0.13 moved the collected resource type of resource collections
to a different template slot, which broke the custom paginated resource
collection extension and the API docs export. Scramble now infers
paginated responses natively, so the extension, the marker interface and
the @return annotations that overrode the inference are removed.
Scramble 0.13 also documents closure routes, so the API fallback routes
are moved to a controller that is excluded from the docs.
Add a test that exports the API docs.
Models that belong to an organization via a parent model (for example
project members via their project) implement AuditableThroughParent and
return the parent relation. The owner organization of their audits is
taken from the loaded parent if it matches the foreign key, otherwise it
is queried. The declaration is also used to backfill the owner of
existing audits.
Models implementing AuditableWithoutOwner intentionally have no audit
owner, either because they belong to neither an organization nor a user,
or because they and their audits have to be kept when the owner is
deleted (for example billing records). Adds helpers and a scope on the
audit model to find audits that are missing an owner although they
should have one.
- Rename the audit actor columns user_type/user_id to actor_type/actor_id
- Add owner_organization_id and owner_user_id to the audits table as
foreign keys with cascade on delete, so that the audits of an
organization or user are deleted together with it. The indexes and
foreign keys are created without blocking writes on the large table.
- Fill the owner columns for new audits via CustomAuditable. Organizations
and users no longer record their own deletion audit, since it would
reference the already deleted owner.
Faker's image() downloads the image from via.placeholder.com, which no
longer exists. Since the domain resolves again but does not respond,
the download (without timeout) hangs and the PHPUnit runs time out.
The profile photo is now generated locally with GD, which also stores a
real image instead of the temporary file path returned by image().
The Laravel 13 config update made sslmode read DB_SSLMODE, which the
self-hosting examples set to require, breaking instances whose database
does not support SSL. Use DB_SSL_MODE instead so existing values are
ignored again, and fall back to DATABASE_URL when DB_URL is not set.