Skip to content

Tags: ChurchCRM/CRM

Tags

7.3.3

Toggle 7.3.3's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Fix: default DB port to 3306 when blank and log a warning (#8894)

## Summary
Some installs have `$dbPort` left blank in `Config.php`. Previously this
caused a fatal validation error. This PR makes the loader fall back to
the MySQL default (3306) and log a warning so operators can see it
happened.

## Changes
- Default `$dbPort` to `'3306'` when the value is `null` or empty string
before validation runs
- Emit a `CONFIG_WARN` log entry when the port is assumed so operators
can find and fix it
- Remove `$dbPort` from the \"required variables\" check (it now always
has a value by the time validation runs)
- Consolidate the duplicate `writeErrorLog()` into a single
`writeLog(string \$level, string \$message)` helper

## Why
Blank DB port is a common configuration oversight on shared hosting and
older installs where the port was simply omitted from `Config.php`. A
hard failure is worse than a safe default.

## Files Changed
- `src/ChurchCRM/Config/ConfigLoader.php` — port defaulting logic +
unified log helper

## Testing
- PHP syntax validation: ✅ 744 files pass
- Biome lint: ✅ no errors
- Manually verified: blank `$dbPort` → falls through to `'3306'`,
warning written to `churchcrm-YYYY-MM-DD-config-error.log`

## Related Issues
Fixes installs silently broken by missing `$dbPort` in `Config.php`

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

7.3.1

Toggle 7.3.1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Improve GitHub release upload robustness (#8769)

## What Changed
Enhanced the GitHub release upload workflow to be more robust by:
- Removing the "v" prefix from release tags for consistency
- Adding validation to ensure the zip file exists before attempting
upload
- Improving release detection by querying the GitHub API directly
instead of relying on `gh release view`
- Using explicit file variable instead of glob pattern to prevent
potential issues with multiple matches

## Type
- [ ] ✨ Feature
- [x] 🐛 Bug fix
- [ ] ♻️ Refactor
- [x] 🏗️ Build/Infrastructure
- [ ] 🔒 Security

## Testing
The changes are to the CI/CD workflow and will be validated by the
GitHub Actions pipeline on the next release. The improvements add error
handling that will catch issues earlier (missing zip files) and use more
reliable API queries for release detection.

## Pre-Merge
- [x] Tested locally
- [x] No new warnings
- [x] Build passes
- [x] Backward compatible (or migration documented)

https://claude.ai/code/session_012dwe1XbZJBsTgR774UaZjd

---------

Co-authored-by: Claude <noreply@anthropic.com>

7.3.0

Toggle 7.3.0's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
🌍 POEditor Locale Update - 2026-04-25 (#8818)

## 🌍 Automatic Locale Update

This PR contains updated translations downloaded from POEditor and
missing term reports for all locales.

**Details:**
- 📅 **Date**: 2026-04-25
- 🏷️ **Version**: 7.3.0
- 🚀 **Trigger**: Manual run

**What's included:**
- Updated translation files from POEditor
- Generated locale JSON files
- 📊 Missing terms for all locales (in `locale/terms/missing/`)
- Locale audit results

**Missing Terms Reports:**
For each incomplete locale, batch files under
`locale/terms/missing/{locale}/` contain all untranslated terms
downloaded directly from POEditor. These can be used with
`/locale-translate` or uploaded directly to POEditor.

This PR was automatically created by the POEditor workflow.

---

**Manual Run Options:**
- 🔍 Full download and audit

Co-authored-by: DawoudIO <554959+DawoudIO@users.noreply.github.com>

7.2.2

Toggle 7.2.2's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
🌍 POEditor Locale Update - 2026-04-23 (#8782)

## 🌍 Automatic Locale Update

This PR contains updated translations downloaded from POEditor and
missing term reports for all locales.

**Details:**
- 📅 **Date**: 2026-04-23
- 🏷️ **Version**: 7.2.2
- 🚀 **Trigger**: Manual run

**What's included:**
- Updated translation files from POEditor
- Generated locale JSON files
- 📊 Missing terms for all locales (in `locale/terms/missing/`)
- Locale audit results

**Missing Terms Reports:**
For each incomplete locale, batch files under
`locale/terms/missing/{locale}/` contain all untranslated terms
downloaded directly from POEditor. These can be used with
`/locale-translate` or uploaded directly to POEditor.

This PR was automatically created by the POEditor workflow.

---

**Manual Run Options:**
- 🔍 Full download and audit

Co-authored-by: DawoudIO <554959+DawoudIO@users.noreply.github.com>

7.2.1

Toggle 7.2.1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
chore(deps): bump dompurify from 3.3.3 to 3.4.0 (#8686)

7.2.0

Toggle 7.2.0's commit message

Verified

This commit was signed with the committer’s verified signature.
claude Claude
ci: simplify Create Release workflow inputs

Drop the run_id input — it was confusing (users don't know where to
find a run ID) and the workflow always picking the latest successful
master build is the right default. If you need to release an older
build, bump the relevant commit back onto master first.

Also drop the actions/checkout step: gh CLI works via API with
GH_TOKEN and we don't touch any repo files, so the checkout was dead
weight. GH_REPO is set from github.repository so gh knows which repo
to query.

7.2.0-rc2

Toggle 7.2.0-rc2's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Fix API SQL injections, null guards, and security bugs (#8601)

## Summary

- Fix 7 SQL injection vulnerabilities in `FinancialService.php` by
converting to Perpl ORM queries
- Add null guards on ORM `findPk()`/`findOne()` results that could crash
on invalid IDs
- Fix user enumeration in login endpoint (same 401 for all failures)
- Fix operator precedence bug, boolean coercion, `(int)` casts, and
birthday parse guard
- Delete unused `system-locale.php` API route (zero callers)
- Add Cypress tests covering the security fixes

## Security Fixes

### Critical: SQL Injection in FinancialService.php (7 locations)
All used raw `FunctionsUtils::runQuery()` with string concatenation:
- `getMemberByScanString()` — raw SQL →
`FamilyQuery::filterByScanCheck()` ORM
- `setDeposit()` — raw DELETE → `PledgeQuery` ORM
- `getDepositTotal()` — raw SUM → `PledgeQuery` with `withColumn()`
- `locateFamilyCheck()` — raw COUNT → `PledgeQuery::count()`
- `processCurrencyDenominations()` — `mysqli_real_escape_string` +
`(int)` casts (no ORM model)
- `getPledgeorPayment()` — raw SELECT → `PledgeQuery` ORM, also removes
`extract()`
- `getCurrencyTypeOnDeposit()` — `(int)` casts on both parameters (no
ORM model)

### High: Null Guards
- `FinancialService::deletePayment()` — null check before `delete()`
- `FinancialService::getPayments()` — null check on `getPerson()`
- `people-groups.php` — null guards on membership and role lookups (3
locations)

### Medium: Bug Fixes
- `people-families.php:88` — operator precedence: `!empty(a ||
!empty(b))` → `!empty(a) || !empty(b)`
- `people-groups.php` — `(int)` casts on `roleID`/`groupID`/`userID`
from request input
- `people-groups.php` — `setActive()`/`setIncludeInEmailExport()` string
`'false'` → `filter_var()` boolean
- Middleware (`Person`/`Family`/`Group`/`Property`) — `(int)` cast on
`findPk()` IDs
- `public-register.php` — guard `DateTime::createFromFormat` returning
`false`
- `public-user.php` — prevent user enumeration (same 401 for "not found"
and "wrong password")

### Cleanup
- Delete unused `system-locale.php` — zero frontend/backend/test callers
- Keep `/api/issues` accessible to all authenticated users (used by
Report Issue on every page)

## Test plan
- [ ] Verify deposit operations (create, update, close) still work
- [ ] Test payment creation with CHECK and CASH methods
- [ ] Test scanned check lookup (`/families/byCheckNumber`)
- [ ] Verify login returns 401 for invalid users (not 404)
- [ ] Test group role update/rename operations
- [ ] Test group active/email-export toggle with `'true'`/`'false'`
- [ ] Verify "Report an Issue" works for non-admin users
- [ ] Run full Cypress E2E suite

https://claude.ai/code/session_01XtgSNmxPz4scbhfXtQ8fFf

---------

Co-authored-by: Claude <noreply@anthropic.com>

7.2.0-rc1

Toggle 7.2.0-rc1's commit message
locale: mandate branch + commit + push + upload per locale

- Add MANDATORY data loss prevention rules to prevent agent timeouts losing work
- Require commit + push after EVERY locale (never accumulate uncommitted translations)
- Add per-locale POEditor upload as part of translation workflow (step 3f)
- Commit refreshed batch files only if upload succeeded (step 3g)
- Skip refreshed file commit if upload fails — continue to next locale gracefully
- Create locale-translate-agent-prompt.md: storable, clear script for GitHub agents
- Update all skill files (locale-ai-translation.md, locale-cloud-safe-translation.md,
  locale-workflow-simplified.md, locale-release.md, locale-translate.md)

Fixes: Hours of lost translation work from agent timeouts and uncommitted files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

7.1.2

Toggle 7.1.2's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
🌍 POEditor Locale Update - 2026-04-07 (#8545)

## 🌍 Automatic Locale Update

This PR contains updated translations downloaded from POEditor and
missing term reports for all locales.

**Details:**
- 📅 **Date**: 2026-04-07
- 🏷️ **Version**: 7.1.2
- 🚀 **Trigger**: Manual run

**What's included:**
- Updated translation files from POEditor
- Generated locale JSON files
- 📊 Missing terms for all locales (in `locale/terms/missing/`)
- Locale audit results

**Missing Terms Reports:**
For each incomplete locale, batch files under
`locale/terms/missing/{locale}/` contain all untranslated terms
downloaded directly from POEditor. These can be used with
`/locale-translate` or uploaded directly to POEditor.

This PR was automatically created by the POEditor workflow.

---

**Manual Run Options:**
- 🔍 Full download and audit

Co-authored-by: DawoudIO <554959+DawoudIO@users.noreply.github.com>

7.1.1

Toggle 7.1.1's commit message

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
fix: replace inline onclick with data-* attributes in custom field ed…

…itors (#8520)

## Summary

- Inline `onclick` attributes on Delete buttons in the three custom
field editors (Group, Family, Person) are blocked when CSP is enforced
(`script-src` does not include `unsafe-inline`)
- Replaces `onclick="confirmDeleteField(...)"` with `data-field-name`,
`data-field-id` (and `data-prop-id` for Group) attributes on the button
- Adds a delegated `$(document).on('click', '.js-delete-field')`
listener inside the **existing** `<script nonce="...">` block — no new
script tags
- Removes the now-unnecessary `$fieldNameJs`/`$fieldIdJs` PHP
intermediary variables

## Why

ChurchCRM's `Content-Security-Policy` `script-src` directive does not
include `unsafe-inline`. When `bEnforceCSP` is enabled, all inline event
handlers are silently blocked. Discovered during review of #8509 (which
patched only the HTML-attribute quoting in `GroupPropsFormEditor.php`).

This fix makes Delete work under both report-only **and** enforced CSP,
and is consistent with the pattern documented in
`security-best-practices.md` → _No Inline Event Handlers_.

## Files Changed

| File | Change |
|------|--------|
| `src/GroupPropsFormEditor.php` | `onclick` →
`data-field-name/prop-id/field-id` + delegated listener |
| `src/FamilyCustomFieldsEditor.php` | `onclick` →
`data-field-name/field-id` + delegated listener |
| `src/PersonCustomFieldsEditor.php` | `onclick` →
`data-field-name/field-id` + delegated listener |
| `cypress/e2e/ui/admin/person-custom-fields.spec.js` | Regression tests
for Person + Family delete buttons |
| `cypress/e2e/ui/groups/standard.group.properties.spec.js` | Regression
test for Group props form delete button |

## Testing

Cypress regression tests added that verify for all three editors:
1. Delete button has `data-field-name`/`data-field-id` attributes and
**no** `onclick`
2. Clicking the button opens the bootbox confirm dialog (event
delegation fires)
3. Cancel leaves the field intact
4. Confirm deletes the field and shows a success notification

Manual steps:
1. Open Admin → Custom Fields (Person, Family, Group)
2. Click the ⋮ menu on any field → **Delete** — confirm dialog should
appear and delete should succeed
3. Enable `bEnforceCSP` in System Settings → repeat above — Delete must
still work (no CSP console errors)

## Related Issues

- Fixes #8508
- Supersedes #8509 (the `htmlspecialchars(json_encode(...))` workaround
is no longer needed since the `onclick` attribute is removed entirely)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>