nixos-module: work around upstream language-list caching bug
Migration 2025_08_31_224356_additional_languages_af_ca_id.php runs
during `migrate`, before db:seed's LanguageSeeder has populated the
other 42 rows of the languages table, and does
Cache::forever('languages', Language::all()) - permanently caching
just the 3 languages (Afrikaans, Catalan, Indonesian) it sees at that
moment. StaticServiceProvider checks this cache key before ever
querying the DB again, so every fresh install's language dropdown
(e.g. the "Welcome to Invoice Ninja" company setup wizard) was stuck
showing only those 3 entries, in their own native-language spelling
(ctrans() translates each name using the active locale).
Adds an unconditional `invoiceninja-manage cache:forget languages` to
invoiceninja-data-setup.service, and a regression test asserting
/api/v1/statics returns more than 40 languages. Verified directly:
before the fix, a fresh account's statics call returned exactly 3
languages; after, it returns all 45.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -97,7 +97,13 @@ expect Nix to report the correct hash on a failed build (or use `nix-prefetch`/`
|
|||||||
clears bootstrap/opcode cache, rebuilds `.env`, rsyncs static storage into `dataDir`, symlinks the runtime
|
clears bootstrap/opcode cache, rebuilds `.env`, rsyncs static storage into `dataDir`, symlinks the runtime
|
||||||
`app.php`, and guards one-time actions (`migrate`, `db:seed`, admin account creation) behind marker files
|
`app.php`, and guards one-time actions (`migrate`, `db:seed`, admin account creation) behind marker files
|
||||||
(`.initial-migration`, `.db-seeded`, `.admin-created`) in `dataDir`. `phpfpm-invoiceninja.service` and
|
(`.initial-migration`, `.db-seeded`, `.admin-created`) in `dataDir`. `phpfpm-invoiceninja.service` and
|
||||||
`invoiceninja-queue-worker.service` both depend on it.
|
`invoiceninja-queue-worker.service` both depend on it. It also unconditionally runs
|
||||||
|
`invoiceninja-manage cache:forget languages` on every activation, working around an upstream bug: migration
|
||||||
|
`2025_08_31_224356_additional_languages_af_ca_id.php` runs during `migrate` (before `db:seed`'s
|
||||||
|
`LanguageSeeder` has populated the other 42 rows) and does `Cache::forever('languages', Language::all())`,
|
||||||
|
permanently caching just the 3 languages it sees at that moment — without this, the language dropdown in
|
||||||
|
the app stays stuck at 3 entries forever, since `StaticServiceProvider` checks that cache key before ever
|
||||||
|
querying the DB again.
|
||||||
- `invoiceninja-scheduler.timer`/`.service` run `artisan schedule:run` every minute — this is what drives
|
- `invoiceninja-scheduler.timer`/`.service` run `artisan schedule:run` every minute — this is what drives
|
||||||
Invoice Ninja's own internal cron-scheduled jobs (recurring invoices, scheduled reports, etc.); without it the
|
Invoice Ninja's own internal cron-scheduled jobs (recurring invoices, scheduled reports, etc.); without it the
|
||||||
app's dashboard reports "cron jobs are not enabled". Laravel's scheduler is just a dispatcher, so this one
|
app's dashboard reports "cron jobs are not enabled". Laravel's scheduler is just a dispatcher, so this one
|
||||||
|
|||||||
@@ -696,6 +696,14 @@ in
|
|||||||
# Necessary for languages, currencies, countries, etc.
|
# Necessary for languages, currencies, countries, etc.
|
||||||
[[ ! -f ${cfg.dataDir}/.db-seeded ]] && invoiceninja-manage db:seed --force && touch ${cfg.dataDir}/.db-seeded
|
[[ ! -f ${cfg.dataDir}/.db-seeded ]] && invoiceninja-manage db:seed --force && touch ${cfg.dataDir}/.db-seeded
|
||||||
|
|
||||||
|
# Work around an upstream bug: migration 2025_08_31_224356_additional_languages_af_ca_id.php
|
||||||
|
# runs during `migrate` (before db:seed's LanguageSeeder has populated the other 42 rows) and
|
||||||
|
# does `Cache::forever('languages', Language::all())`, permanently caching just the 3 languages
|
||||||
|
# it sees at that moment. Without this, the language list stays stuck at those 3 forever,
|
||||||
|
# since StaticServiceProvider checks this cache key before ever querying the DB again.
|
||||||
|
# Unconditional (not marker-gated) so it also self-heals installs that hit this before the fix.
|
||||||
|
invoiceninja-manage cache:forget languages
|
||||||
|
|
||||||
# Create Invoice Ninja admin account
|
# Create Invoice Ninja admin account
|
||||||
[[ (! -f ${cfg.dataDir}/.admin-created) && (${
|
[[ (! -f ${cfg.dataDir}/.admin-created) && (${
|
||||||
if cfg.adminAccount.enable then "true" else "false"
|
if cfg.adminAccount.enable then "true" else "false"
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ pkgs.testers.nixosTest {
|
|||||||
};
|
};
|
||||||
|
|
||||||
testScript = ''
|
testScript = ''
|
||||||
|
import json
|
||||||
|
|
||||||
def check_invoiceninja(machine, proxy_unit):
|
def check_invoiceninja(machine, proxy_unit):
|
||||||
machine.wait_for_unit("mysql.service")
|
machine.wait_for_unit("mysql.service")
|
||||||
machine.wait_for_unit("redis-invoiceninja.service")
|
machine.wait_for_unit("redis-invoiceninja.service")
|
||||||
@@ -65,6 +67,19 @@ pkgs.testers.nixosTest {
|
|||||||
)
|
)
|
||||||
assert "${adminEmail}" in login_response, f"login did not succeed: {login_response}"
|
assert "${adminEmail}" in login_response, f"login did not succeed: {login_response}"
|
||||||
|
|
||||||
|
with subtest("full language list is available, not just the af/ca/id migration's 3"):
|
||||||
|
# Regression check: migration 2025_08_31_224356_additional_languages_af_ca_id.php runs
|
||||||
|
# during `migrate`, before db:seed's LanguageSeeder has populated the other 42 rows, and
|
||||||
|
# does Cache::forever('languages', Language::all()) - permanently caching just the 3
|
||||||
|
# languages it sees at that moment. invoiceninja-data-setup works around this with
|
||||||
|
# `invoiceninja-manage cache:forget languages`; this confirms the workaround is in place.
|
||||||
|
token = json.loads(login_response)["data"][0]["token"]["token"]
|
||||||
|
statics = machine.succeed(
|
||||||
|
f"curl -sf http://localhost/api/v1/statics -H 'X-API-TOKEN: {token}'"
|
||||||
|
)
|
||||||
|
language_count = len(json.loads(statics)["languages"])
|
||||||
|
assert language_count > 40, f"expected ~45 languages, got {language_count}"
|
||||||
|
|
||||||
|
|
||||||
nginx.start()
|
nginx.start()
|
||||||
caddy.start()
|
caddy.start()
|
||||||
|
|||||||
Reference in New Issue
Block a user