Home › Journal Admin › Users
Users
Journal-scoped staff/user directory management — search & filter, role assignment, reviewer/editor subject assignment, duplicate-account merging, password reset, Excel import/export, and single & campaign email to users (legacy sidebar group "Manage List"). Legacy entry: manager.php (role 6, various _action values), dispatched into class/cn.adm.class.php's ContactAdmin and its subclasses RoleManager (class/contact.role.class.php), ContactImport (class/import.cn.class.php) and JournalCampaign (class/campaign.class.php), rendered by view/cn.adm.view.php / view/contact.role.view.php / view/import.cn.view.php / view/campaign.view.php.
| Page | Status | E2E | Enhanced | Legacy Ref | Route | Roles |
|---|---|---|---|---|---|---|
| Users List | Full | Yes | filters | manager.php?_action=userList | /manager?_action=userList | Journal Admin (role 6 — see gating note); also Editor-in-Chief — see EIC note |
| Users List — Excel Export | Full | Yes | loading-states | manager.php?_action=userList&excel=1 | /manager?_action=userList&excel=1&kw=... | Journal Admin (role 6 — see gating note); also Editor-in-Chief — see EIC note |
| Email to a User | Pending | — | — | journal/email.ed.php?cn=... | /journal/email.ed?cn=... | Journal Admin (loose gate — see note) |
| Reset Password | Full | — | reset-link | manager.php?_action=resetpass&cn=... | /manager?_action=resetpass&cn=... | Journal Admin (roles 4/6/16 — see gating note); also Editor-in-Chief — see EIC note |
| Manage Roles | Full | Yes | tabbed | manager.php?_action=role | /manager?_action=role | Journal Admin (role 6; also role 16 via mng_assist — see note) |
| Assign Subjects to Reviewers, Editors & Section Editors | Full | Yes | tabbed | manager.php?_action=reviewer | /manager?_action=reviewer | Journal Admin (role 6; also role 16 via mng_assist — see note) |
| Campaign Email to Users | Basic | — | — | manager.php?_action=campaign | /manager?_action=campaign | Journal Admin (role 6; also role 16 via mng_assist and Editor-in-Chief — see notes) |
| Import Users from Excel | Pending | — | — | manager.php?_action=import_cn | /manager?_action=import_cn | Journal Admin (role 6; also role 16 via mng_assist — see note) |
| Merge Duplicate Users | Pending | — | — | manager.php?_action=merge_dup | /manager?_action=merge_dup | Journal Admin (role 6; also role 16 via mng_assist — see note) |
Features
| Feature | Status | E2E | Description |
|---|---|---|---|
| Admin can browse a paginated, journal-scoped directory of the journal's users | Full | Yes | List stays within the current journal, shows only real user records, defaults to last-name sort, and shows a results count. |
| Admin can live-search users by keyword, scoped to a field group (full name, email, affiliation, country) | Full | Yes | Legacy multi-word AND matching semantics are served by the API; searching clears any active initial filter, matching legacy override behavior. |
| Admin can narrow the list by last-name initial using a locale-aware A–Z strip | Full | Yes | Legacy generated the initials alphabet from the UI language (e.g. Arabic letters under ar locale); the port passes locale into the strip. |
| Admin can filter users by role, registration status (registered/unregistered), and reviewer-agreed | Full | Yes | Filter drawer shows an active-filter count badge; clearing filters is available from both the drawer and the empty state. |
| Admin can sort the user list by last name, first name, country, or newest | Full | Yes | Default sort is last name, matching legacy. |
| Admin can open a quick-view sidebar for a user without leaving the list | New | Yes | Lets the admin inspect a contact inline (with an Edit shortcut) while keeping the filtered list context; auto-closes when search/filters change. |
| Admin sees an explicit empty state with clear-search / clear-filters actions when a search matches nothing | New | Yes | Actionable recovery from a dead-end search rather than a bare message. |
| Admin can edit a user's profile from the list (Edit row action → user detail page) | Full | Yes | The detail page also hosts the Manage Roles and Assign Subjects tabs; deep profile-edit rules are cataloged under the Account/edit-profile sibling spec. |
| Admin can register an unregistered user from the user detail page | New | Yes | Gives admins an explicit way to promote cn_status 1 (unregistered) contacts, which legacy only did as a side effect of other flows. |
| Admin can export the current filtered/sorted user list to an Excel file | Full | Yes | Legacy export produced one row per user with subjects concatenated, custom fields, second-language columns, and text-formatted phone/fax cells; the port honors the on-screen filter state instead of a raw ?excel=1 URL. |
| Admin can email an individual user from the list (composer with prefilled sender/recipient, CC/BCC, one attachment, rich-text body) | Pending | — | Legacy journal/email.ed.php composer with client+server validation, placeholder substitution ({date}, {journalLink}, {journalTitle}), per-journal SMTP config with env fallback, and an appended per-recipient unsubscribe link; no apps/web counterpart. |
| Admin can force-reset a user's password from the list | Full | — | Deliberate redesign: reset-link model instead of legacy generate-plaintext-password + on-screen credentials panel. |
| User is notified by email when an admin resets their password | Full | — | Legacy emailed the new plaintext password (plus alternate email as extra recipient) with a localized template; the web flow surfaces a reset link to the admin instead, but the underlying apps/api mutation still emails the target contact via a resetByAdmin template. |
| Admin can assign and remove journal roles for a user | Full | Yes | Legacy save semantics: journal-scoped replace of assignable roles, never touching roles 0/6/10; empty selection legally strips all assignable roles. |
| At most one Editor-in-Chief per journal is enforced when the unique-EIC setting is on | Pending | — | Legacy checks ju_journal_setting unique_edt=1 and refuses a second role-4 contact (with known partial-save/messaging quirks); not verifiable from apps/web — backend parity flagged. |
| Admin is informed that assigning Production Manager moves certain manuscript actions from the EIC to the PM | Pending | — | Legacy Manage Roles screen shows an informational message about the Production Manager workflow effect; no equivalent notice found in ManageRolesTab.tsx. |
| Admin can assign subject expertise to reviewers, editors, and section editors via a parent/child subject hierarchy | Full | Yes | Legacy limited eligible contacts to roles 3/9/14 (Reviewer/Editor/Section Editor); parents and children are independently assignable. |
| Reviewer-chosen favorite subjects are preserved when an admin reassigns subjects | Pending | — | Legacy protects ju_contact_subject rows with fav_spc=2 (reviewer-selected favorites) from the manager's delete-and-replace save; whether the new API preserves this is not verifiable from apps/web — flagged. |
| Admin can send a campaign (bulk) email to a filtered set of journal users | Basic | — | Legacy JournalCampaign covers recipient search (status, role, country, position/degree, speciality, date/issue limits), a two-list receiver builder, personalization tokens ({receiverName}, {firstName}, {cnEditLink}, {reviewerPage}...), per-recipient unsubscribe footers, unsubscribe-list suppression, elastic credit gating, and paced one-message-per-recipient delivery. |
| Admin can persist an extra 'alert emails' recipient list alongside campaign sends | Pending | — | Legacy campaign page edits ju_journal_setting alert_emails (comma-separated free-form addresses) inline; there is no dedicated maintenance page for this setting. |
| Admin can bulk-import users from an Excel workbook via an upload → column-mapping → preview → save wizard | Pending | — | Legacy ContactImport maps row-1 headers to contact fields (with locale-exact auto-matching), requires first/last name + email, resolves title/position/degree/country from labels, previews New vs Already Exists, and de-duplicates by current-journal email. |
| Import options: assign reviewer role, update existing users, and send registration emails with generated credentials | Pending | — | Legacy sub-behaviors: reviewer role and Specialty 1-3 subject links are additive even for untouched registered users; unregistered existing users are always overwritten and re-passworded; registration email (reviewer variant when reviewer role checked) goes only to new/unregistered contacts. |
| Admin can merge duplicate user accounts into one primary account | Pending | — | Legacy searches by first+last name (prefix+suffix matching), requires an active primary, protects admin accounts from being merged, reassigns roles/articles/manuscripts/reviews/tracking to the primary, then permanently deletes the duplicates. |
| Admin can impersonate a user and later return to their own account | Full | Yes | Legacy blocks impersonating any contact holding admin role 6 (in any journal) and restores the original admin on logout; row-action-only per the inventory's row-identification rule. |
| Admin can delete a user from the journal, blocked when the user is a manuscript owner/editor, an active reviewer, or a journal admin | Full | Yes | Legacy blocking rules (with manuscript-ID messages), self-delete protection, and the cross-journal role-row deletion side effect live server-side; UI-level parity is in place. |
| User-management actions are recorded in contact action history when the journal's audit setting is on | Pending | — | Legacy writes ju_contact_actions rows (types 7 delete, 9 role change, 10 password reset, 14 subject assign, 15 import, 16 merge) when save_cn_action=1; no apps/web evidence of an equivalent audit surface — backend parity flagged. |
| Admin can block/disable a user account (legacy blockUserForm) | Dropped | — | Dead in the legacy app itself; nothing to port. |
The real tenant-scoped entry point is root
manager.php, not mainm/adm.php / mainn/adm.php.Those two files (and
main/adm.php) also expose _action=register (a users list) and _action=roles (a role-assignment form) with near-identical markup, but they instantiate class/adm.role.class.php's AdmRoleManager under the platform Super Admin session ($_SESSION['juAdmUser__'], via class/adm.class.php's JournalAdmin) and every query is scoped to ju_contacts.journal_code = 0 — a platform-wide "Editorial Office" staff list, not this journal's own users. That variant does not fit this segment's "one journal's staff" remit and is not claimed here; it is an open gap for a Super Admin sibling module.Page-level gate is looser than the per-action save/query gate.
manager.php's own top-of-file check only requires a ju_contact_role row with _role = 6 in any journal (no _journal filter) before rendering any row above. Users List, Reset Password, and Manage Roles' save step then separately call ContactAdmin::checkAdminSt(), which is scoped to the current journal and accepts roles 4, 6, or 16 — so a role-6 admin from a different journal can open these screens here, but the underlying save/query still requires role 4/6/16 specifically in this journal. Import Users from Excel and Merge Duplicate Users have no such secondary check at all and rely solely on the page-level gate. The AJAX dispatcher (request/manager.ajax.php, used by Manage Roles/Assign Subjects/Campaign/Merge) applies its own top gate of roles 4/6/16, again with no journal filter.Email to a User has the loosest gate of any row here.
Per
apps/legacy/spec/admin/user-management/admin-email-to-user.md, journal/email.ed.php's own authorization check accepts any authenticated contact with at least one ju_contact_role row — no specific role value is enforced at that endpoint itself (only the Users List link that opens it is gated by manager.php's role-6 check). Recipient lookup still scopes to the current journal.Import Users from Excel's role-16 path is a different route, not this one.
Per
import-users-from-excel.md, role 16 (Editorial Office) can also reach this wizard, but only via the separate mng_assist.php entry point (Publishing Workflow › management-assistant), since manager.php's own page gate is role 6 only. The same spec notes the rendered forms still submit back to manager, so a role-16-only user who starts the wizard from mng_assist fails partway through — an existing legacy inconsistency, not a design choice, and not something this row's Legacy Ref/Route claims.Manage Roles, Assign Subjects, Campaign Email to Users, and Merge Duplicate Users are also fully reachable via
mng_assist.php (role 16, Editorial Office).Unlike Import Users from Excel's broken role-16 variant above,
mng_assist.php's role, reviewer, campaign, and merge_dup case blocks (apps/legacy/js/mng_assist.php lines 273–299) are live, uncommented dispatches into the identical RoleManager / JournalCampaign / ContactImport classes used here — unlike its userList and resetpass case blocks (lines 357–377), which are commented out and dead. These four have no render/save split: their save step runs through request/manager.ajax.php, which independently gates on _role IN (4, 6, 16), so all four work completely whether opened from manager.php or mng_assist.php. See Publishing Workflow › Management Assistant, which separately catalogs these same four screens as its own rows and cross-links back to this page.Editor-in-Chief (
editor.php) also exposes several of these screens (EIC note).Per
admin-user-list.md's own note, "Editors may have access to a similar user list when the ju_journal_setting value for setting_field = 'eic_custom_opt' includes user_list" — live at editor?_action=userList (apps/legacy/js/editor.php lines 405–423; UI link at view/index.editor.view.php line 585) and, for the Excel variant, at editor?excel=1 (same file, lines 48–58, intercepted before the row-based gate and routed to the identical ContactAdmin::getContactList). Campaign Email to Users is likewise reachable at editor?_action=campaign when eic_custom_opt includes campaign (lines 395–404; UI link at index.editor.view.php line 582). Users List and Campaign Email to Users are separately cataloged as their own rows under Publishing Workflow › Editor-in-Chief (gated role 4); the Excel Export variant via editor.php is not separately cataloged there and is noted only here. Reset Password is also reachable at editor?_action=resetpass — unconditionally, with no eic_custom_opt flag: editor.php lines 69–71 gate role 4 (roles 1/4/9/14 only for track/print/imps), and its case block at lines 429–433 dispatches to the identical ContactAdmin::resetUserPassword; the per-row action link in view/cn.adm.view.php is built from ContactAdmin::mngActionFile, which editor.php sets to "editor" at line 416, so the icon really does point at editor?_action=resetpass when the list is rendered from there. This Reset Password path is separately cataloged as its own row, "Reset User Password (confirmation panel)", under Publishing Workflow › Editor-in-Chief.Impersonate and Delete are row actions, not separate rows.
Impersonate (
manager.php?_action=imps → ContactAdmin::impersonateAsUser) immediately switches the session and redirects to the impersonated user's own contacts?_action=profile (Journal segment) with no admin-side render of its own. Delete (AJAX task=deleteUsr → ContactAdmin::deleteContact, called from the Users List row) swaps a status string into the existing list panel with no navigation. Per this inventory's row-identification rule, pure redirect/AJAX handlers with no distinct rendered screen are not counted as rows, so both are documented here only as behavior of the Users List row's action column (per impersonate-user.md / delete-user.md), not claimed as pages. The same impersonate handler is also reachable at editor?_action=imps for roles 1/4/9/14 (editor.php lines 69–71, 424–428, with an independent UI link on the corresponding-author row in view/manu.view.php line 1624) — same redirect-only behavior, so likewise not claimed as a row there either.Two adjacent items are intentionally not claimed here.
manager.php?_action=reg_form (Registration Form field configuration) sits in the same legacy sidebar group as this table's rows, but it configures the journal's own registration form rather than staff/user management, so it is left to the Account sibling module. Separately, class/cn.adm.class.php defines a blockUserForm/blockUserSave block-user screen (ju_contacts.cn_disabled), but no manager.php action, AJAX task, or link anywhere in the app calls it — it appears to be dead/unreachable code and is not claimed as a row.