Contact & Auth
Public support inquiry form plus the journal's reader account system — sign-in, registration, and password recovery/change. Legacy entry: journal/contact.us.php (support form, using class/config.class.php's JU_Config directly — no Contact_Manager involvement) and contacts.php (dispatched into class/contacts.class.php's Contact_Manager) — neither has an auth gate to enter.
| Page | Status | E2E | Enhanced | Legacy Ref | Route | Roles |
|---|---|---|---|---|---|---|
| Contact Us | Full | Yes | validation | journal/contact.us.php | /journal/contact.us | Public |
| Login | Full | — | inline-2fa | contacts.php | /contacts | Public |
| Register (Sign Up) | Full | Yes | validation | contacts.php?_action=signup | /contacts?_action=signup | Public (registration can be disabled by journal setting disable_reg) |
| Forgot Password | Full | — | recaptcha | contacts.php?_action=login&frg=1 | /contacts?_action=login&frg=1 | Public |
| Two-Factor Verification | Full | — | inline | contacts.php?_action=twofactor | /contacts?_action=twofactor | Public (mid-login only — requires a pending login attempt with a temporary session) |
| Reset Password (Email Link) | Full | — | validation | contacts.php?_action=rp | /contacts?t=<encrypted: _action=rp&e={email}&c={confirm_code}> | Public (via the one-time emailed link only; blocked for non-browser user agents) |
| Unsubscribe (Email Alerts) | Pending | — | — | contacts.php?unsubscribe=<encrypted token> | /contacts?unsubscribe=<encrypted: em={email}> | Public — reachable only via the one-time encrypted link mailed to the recipient; no session check at all |
| Change Password | Full | Yes | validation | contacts.php?_action=chpass | /contacts?_action=chpass | Public — requires an active reader (or logged-in admin) session |
Features
| Feature | Status | E2E | Description |
|---|---|---|---|
| Visitor can send a support inquiry (name, email, phone, subject, query type, message) that is emailed to the journal | Full | Yes | The legacy eight-value query-type select is preserved; success shows a toast instead of a reloaded confirmation page. |
| Journal admin can turn the public contact form off (no_contact_form) while still showing the configured contact note text | Full | — | When disabled, only the journal-configured note is shown; the form is suppressed. |
| Contact form submissions are bot-protected | Full | — | reCAPTCHA v3 only; the legacy image-CAPTCHA fallback path is not reproduced (see Dropped feature). |
| Fallback image CAPTCHA (math/word challenge) when reCAPTCHA is unavailable, and CAPTCHA escalation after 3 failed login/reset attempts | Dropped | — | Legacy escalated to a visible challenge after 3 failed attempts or when Google was unreachable; the port relies on reCAPTCHA v3 scoring on every submit. |
| Reader can sign in with username or email and password | Full | — | Public header e2e (TC-JR-HP-008) still asserts the legacy login href, so no spec exercises the native page yet. |
| Reader with 2FA enrolled must enter a TOTP code to complete sign-in | Full | — | Verification is inline in the login flow with auto-focus OTP input and a Back option; success updates the session and routes to /profile. |
| Successful login updates the reader's last-login timestamp and IP | Full | — | Server-side side effect of login, verified by API integration spec rather than e2e. |
| Login attempts (success and failure) are recorded in contact action history and the audit log | Pending | — | Legacy saveCnActionHistory + saveAuditLog fire on both wrong-login and success (contacts.class.php:740-745, 790-793); no equivalent action-history/audit write was found cited for the new login path — flagged for verification. |
| Visitor can register a reader account (contact_code=0) and receives a registration email | Full | Yes | Duplicate username/email rejection and the registration email are server-side parts of the same capability. |
| Journal setting disable_reg can switch public registration off | Basic | — | Legacy hides/blocks signup when disable_reg is set; the ported register page needs a parity check for this gate. |
| Admin dashboard 'Register a New Author' shortcut (eic_custom_opt contains reg_au) reuses the public signup | Pending | — | Per apps/legacy/spec/auth/contact-registration.md it is the identical /contacts?_action=signup route, not a separate form; no apps/web admin-dashboard shortcut to the native /register page was cited. |
| Reader can request a password-reset link by email | Full | — | Legacy returned wrongEmail for unknown addresses; the new form shows explicit submit/success states. |
| Reader completes password reset from the emailed one-time link by setting a new password of their choice | Full | — | Includes an invalid/expired-token state that routes back to /forgot-password for a fresh link. |
| System emails the reader a newly generated password after a reset-link visit | Dropped | — | Superseded rather than lost: the reset link now leads to a set-your-own-password form. |
| Reset link is blocked for non-browser user agents (crawler protection so mail scanners don't burn the one-time link) | Pending | — | Legacy resetPasswordForm bails out via crawler.detect.php isCrawler (contacts.class.php:926-929); no equivalent user-agent gate was found cited for the new-password route. |
| Logged-in reader (or admin) can change their password after confirming the current one | Full | Yes | Same page also serves the super-admin context by branching on pathname. |
| Email recipient can unsubscribe from alert emails via a token-encrypted link (no login required) | Pending | — | Legacy Contact_Manager::unsubscibeAlertEmails decrypts em={email} from the link, shows a confirm form with CSRF token, and appends the address to the journal's unsubscibe_em setting; grep of apps/web found no unsubscribe route — the footer newsletter SUBSCRIBE form is a different capability. |
| Newsletter subscribe form in the public journal footer | New | — | Opt-in counterpart designed from scratch for the new public footer; does not replace the missing token-gated unsubscribe. |
Contact Us has an older, simpler fallback in the
mainm/mainn theme dirs.Those two front-end directories don't call
journal/contact.us.php at all — their .htaccess rewrites the same pretty URL (contact.us) to an inline branch inside their own index.php (?contact) that only echoes the contact_us journal-setting note text, with no form, no CSRF, and no CAPTCHA. The row above documents the current, spec-matching implementation (journal/contact.us.php, per apps/legacy/spec/journal/contact-us.md); the mainm/mainn variant is flagged here rather than split into a second row since it's a strictly reduced legacy fallback of the same conceptual page, not a materially distinct screen. Worth a second look in Phase C if any live journal still runs on the mainm/mainn docroot.Reader "My Account" actions on the same
contacts.php dispatcher are intentionally excluded here.Once a reader is signed in,
contacts.php also serves profile view/edit (_action=edit / profile, shared with the admin-side edit-profile form), saved manuscripts (_action=records), and 2FA enrollment (_action=enable2fa) — each gated behind an active $_SESSION[SESSION_NAME_ID] (Contact_Manager::showContactInfo / ::myRecords / ::enableTwoFactor all redirect to login or bail out without one). These are post-login account-management screens, not "sign-in/sign-up/registration/password flows," and none of the Journal segment's other modules (Home, Journal Info, Issues & Articles, Browse, Search, Static Pages) obviously claims a reader-account area either — flagging this as an open gap for Phase C/D triage (possibly a future "Reader Account" module) rather than force-fitting them into Contact & Auth. Email-preference unsubscribe (unsubscribe) is not part of this excluded group despite riding the same dispatcher: Contact_Manager::unsubscibeAlertEmails() carries no session check at all, so it gets its own public/token-gated row above instead (peer to Reset Password (Email Link), not to this post-login set). Two more _action values on the same dispatcher, search and favsubs, are also absent from both this excluded list and the table above, but for a third reason: both are empty no-op cases in the content-dispatch switch (case 'search': break; / case 'favsubs': break;) — no Contact_Manager method is called, no view is rendered, and inc/js/contacts.js has no client-side handling for either — i.e. dead/stub code, not an implemented reader-account screen, as of the current codebase."Register a New Author" is the same route as Register, not a separate row.
Per
apps/legacy/spec/auth/contact-registration.md, the admin dashboard's "Register a New Author" shortcut (shown when journal setting eic_custom_opt contains reg_au) links to the identical public contacts?_action=signup URL and handler — there is no separate admin-only form or code path.