xref: /plugin/lastseen/README.md (revision 1b84a8a38b9a9da5f86410b2d4d76b5401df1ac5)
134b8413fStracker-user# User Last Seen plugin for DokuWiki
234b8413fStracker-user
351e72b81Stracker-userRecords when each registered user was last active on the wiki, and shows it in an Admin-panel page. Useful for spotting dormant or stale accounts.
434b8413fStracker-user
5*1b84a8a3Stracker-user![User Last Seen admin table with sortable columns and pagination](images/lastseen-screen.png)
6*1b84a8a3Stracker-user
734b8413fStracker-user## What it does
834b8413fStracker-user
934b8413fStracker-user- Every authenticated request updates that user's "last seen" timestamp. This is **last activity**, not just last login — a page view made with a persistent ("remember me") cookie counts, because the tracker hooks `DOKUWIKI_STARTED`, which fires after authentication resolves regardless of how the user authenticated.
100c66c82eStracker-user- An Admin page (**User Last Seen**) lists every registered user with up to five columns: **Username · Display name · Email · Groups · Last seen**. The Email and Groups columns can each be hidden from the configuration. It appears in the "Additional plugins" section of the Admin panel (below the version info), not in the built-in "Administration" block where the User Manager lives — DokuWiki hard-codes which plugins get top-block placement, and third-party plugins always go into the lower section.
1134b8413fStracker-user- "Last seen" shows both an absolute timestamp and a relative time ("3 days ago"). Users never seen since the plugin was installed show "never".
1234b8413fStracker-user- Column headers are clickable to sort — sort by "Last seen" ascending to float dormant accounts to the top.
130c66c82eStracker-user- A per-column **text filter** row (Username, Display name, Email, Groups) narrows the table. Matching is a plain case-insensitive substring — type `ad` to find `admin`. It is a server-side GET form, no JavaScript, modelled on the built-in User Manager's search row.
140c66c82eStracker-user- The table is **paginated** with numbered page links (`‹ 1 … 4 5 6 … 20 ›`); the page size is configurable, and sorting/filtering survive paging because everything travels in the URL.
1534b8413fStracker-user
1634b8413fStracker-user## Why an Admin page and not a column in the User Manager
1734b8413fStracker-user
1851e72b81Stracker-userThe bundled User Manager fires no events for table rendering — its table is built with hardcoded `echo` statements and a fixed five-column layout. Adding a column would require forking the bundled `usermanager` plugin, which DokuWiki *core* upgrades overwrite (unlike third-party plugins). A separate Admin page uses only public APIs (`retrieveUsers()`, the admin-plugin interface), survives upgrades untouched, and can do things a cramped column can't — sortable, relative times, "never" highlighting. DokuWiki's admin UI hard-codes six built-in plugins (`usermanager`, `acl`, `extension`, `config`, `logviewer`, `styling`) in the top "Administration" block; all third-party admin plugins appear in a separate "Additional plugins" section below.
1934b8413fStracker-user
2034b8413fStracker-user## Architecture
2134b8413fStracker-user
2234b8413fStracker-user| Component | Role |
2334b8413fStracker-user| --- | --- |
2434b8413fStracker-user| `action.php` | Hooks `DOKUWIKI_STARTED`. If `REMOTE_USER` is set, records the user as seen (throttled). |
2534b8413fStracker-user| `helper.php` | Owns the storage file and format. `record()` is internally throttled; `getAll()` / `getTimestamp()` for reads. |
2634b8413fStracker-user| `admin.php` | The **User Last Seen** Admin page. Enumerates users via the auth backend, renders the sortable table. |
2734b8413fStracker-user
2834b8413fStracker-user**Storage.** A single serialized `username → unix-timestamp` map at `{metadir}/_lastseen.dat`. The meta directory is used (not cache) so the data survives cache clears and DokuWiki upgrades. Writes are atomic (`io_saveFile()`) under a lock (`io_lock()`).
2934b8413fStracker-user
3034b8413fStracker-user**Throttling.** Recording on every page view would be wasteful. `record()` only rewrites a user's timestamp if the stored one is older than `update_interval` (default 600s / 10 min). Heavy browsing produces at most one write per interval per user. "Last seen" is therefore accurate to within the interval, which is plenty for spotting dormant accounts.
3134b8413fStracker-user
3234b8413fStracker-user## Configuration
3334b8413fStracker-user
3434b8413fStracker-userAdmin → Configuration Settings:
3534b8413fStracker-user
3634b8413fStracker-user| Setting | Default | Effect |
3734b8413fStracker-user| --- | --- | --- |
3834b8413fStracker-user| `update_interval` | `600` | Throttle: minimum seconds between last-seen writes per user. Lower = more precise, more disk I/O. Minimum 60. |
3934b8413fStracker-user| `show_never` | `1` (on) | List users never seen since install. Turn off to show only users with recorded activity. |
400c66c82eStracker-user| `show_mail` | `1` (on) | Show the Email column. |
410c66c82eStracker-user| `show_grps` | `1` (on) | Show the Groups column. |
420c66c82eStracker-user| `entries_per_page` | `20` | Rows per page in the table. Set to `0` to show all users on one page (no pagination). |
4334b8413fStracker-user
4434b8413fStracker-user## Access
4534b8413fStracker-user
4634b8413fStracker-userThe Admin page is **admin-only** (`forAdminOnly()` returns true) — last-seen data is mildly sensitive. To also allow managers (users in `$conf['manager']`), change `forAdminOnly()` in `admin.php` to return `false`.
4734b8413fStracker-user
4834b8413fStracker-user## Requirements and caveats
4934b8413fStracker-user
5034b8413fStracker-user- **Auth backend.** Built and tested against `authplain` (the default file-based backend). The Admin page enumerates users via `retrieveUsers()`. If the active backend can't list users (some LDAP/AD configurations), the page detects this via `$auth->canDo('getUsers')` and shows a notice instead of an incomplete roster.
5134b8413fStracker-user- **Historical data.** Tracking begins at install — users are "never" until their first authenticated request afterward.
5234b8413fStracker-user- **Deleted users.** If a user is removed from the wiki, their entry lingers in the storage file as harmless orphan data; the Admin page won't display it (it only shows users returned by `retrieveUsers()`). The file can be deleted to reset all data — it's rebuilt automatically.
5334b8413fStracker-user- **Privacy.** This is mild activity tracking. Admin-only visibility is the intended boundary; for a staff wiki this is a normal administrative function.
5434b8413fStracker-user
5534b8413fStracker-user## Install
5634b8413fStracker-user
5734b8413fStracker-userDrop the folder into `lib/plugins/lastseen/`, or use Admin → Extension Manager → Manual Install to upload the zip. No "update suppression" date trick is needed — this is a local plugin with no upstream in the dokuwiki.org repository, so the Extension Manager never offers an update for it.
5834b8413fStracker-user
5934b8413fStracker-user## Tested against
6034b8413fStracker-user
61e85c7321Stracker-userDokuWiki `2025-05-14b "Librarian"` under `error_reporting=E_ALL`.
6234b8413fStracker-user
6334b8413fStracker-user## License
6434b8413fStracker-user
6534b8413fStracker-userGPL 2.
66