HomeJournal 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

FeatureStatusE2EDescription
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=impsContactAdmin::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=deleteUsrContactAdmin::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.