const test = require('node:test') const assert = require('node:assert/strict') const fs = require('node:fs') const path = require('node:path') const root = path.resolve(__dirname, '..', '..') const read = (file) => fs.readFileSync(path.join(root, file), 'utf8') const userController = read('src/Admin/UserController.php') const reportOps = read('src/Admin/UserControllerReportOperations.php') const restrictionOps = read('src/Admin/UserControllerRestrictionOperations.php') const restriction = read('src/User/Restriction.php') const reportCenter = read('src/Messages/ReportCenter.php') const usersMenus = read('src/Admin/Native/UsersMenus.php') const mailNotifications = read('src/Settings/MailNotifications.php') const home = read('src/User/Home.php') const commentItem = read('inc/helpers/comments/item.php') const usersBan = read('assets/admin/src/pages/users/UsersBan.vue') const functions = read('functions.php') const uninstall = read('uninstall.php') test('report REST surface is canonical: submit + users/reports only', () => { assert.match(userController, /'\/report\/submit'/) assert.match(userController, /'\/users\/reports'/) assert.match(userController, /'\/users\/reports\/\(\?P\\d\+\)'/) assert.match(userController, /'\/users\/reports\/\(\?P\\d\+\)\/process'/) for (const dead of ["'/report/list'", "'/report/update-status'", "'/report/counts'"]) { assert.ok(!userController.includes(dead), `alias route should be removed: ${dead}`) } assert.ok(!reportOps.includes('public function update_report_status'), 'dead update_report_status method') assert.ok(!reportOps.includes('public function get_report_counts'), 'dead get_report_counts method') }) test('report center has no legacy ajax handlers or option migration', () => { assert.ok(!reportCenter.includes('ajax_update_status')) assert.ok(!reportCenter.includes('ajax_list')) assert.ok(!reportCenter.includes('ajax_counts')) assert.ok(!reportCenter.includes('migrate_from_option')) assert.ok(!reportCenter.includes('maybe_migrate')) assert.ok(!reportCenter.includes("get_option('aksrt_reports'")) assert.ok(!functions.includes('ReportCenter::get_instance()->init()'), 'ReportCenter init() is gone') assert.match(reportCenter, /public function has_pending_report/) assert.match(reportOps, /has_pending_report\(\$reporter_id, \$target_type, \$target_id\)/) }) test('report processing writes real restrictions, not a display-only meta', () => { assert.match(reportOps, /->restrict\(\s*\$target_id,\s*\$action_taken,/) assert.match(reportOps, /lift_user_restriction\(\$target_id\)/) assert.match(reportOps, /in_array\(\$action_taken, \\AKSRT\\User\\Restriction::TYPES, true\)/) assert.ok(!reportOps.includes('aksrt_user_ban_state'), 'dual-track ban state meta must not be written or read') for (const deadAction of ["'value' => 'warned'", "'value' => 'muted'", "'value' => 'restricted'", "'value' => 'banned'"]) { assert.ok(!reportOps.includes(deadAction), `action value must map to Restriction types: ${deadAction}`) } for (const action of ["'value' => 'warn'", "'value' => 'mute'", "'value' => 'suspend'", "'value' => 'ban'", "'value' => 'clear'"]) { assert.ok(reportOps.includes(action), `missing action option: ${action}`) } assert.match(reportOps, /get_user_restriction_state/) }) test('restriction class supports lifting and kicks sessions on ban', () => { assert.match(restriction, /public function lift_user_restriction\(int \$user_id/) assert.match(restriction, /public function lift_user_restriction\(int \$user_id, array \$types = \[self::TYPE_BAN, self::TYPE_SUSPEND, self::TYPE_MUTE\]\): int/) assert.match(restriction, /WP_Session_Tokens::get_instance\(\$user_id\)->destroy_all\(\)/) assert.ok(!restriction.includes('sync_user_restriction_meta'), 'write-only meta sync is dead code') assert.ok(!restriction.includes('_aksrt_is_banned')) }) test('ban admin REST endpoints stay in sync with the SPA client', () => { assert.match(userController, /'\/users\/\(\?P\\d\+\)\/restrictions'/) assert.match(userController, /'\/users\/\(\?P\\d\+\)\/restrict'/) assert.match(usersBan, /\/users\/\$\{addForm\.user_id\}\/restrict`/) assert.ok(!usersBan.includes('/restrictions`, {'), 'SPA must not POST to the unregistered /restrictions endpoint') assert.match(usersBan, /expires_at: durationToExpiresAt\(addForm\.duration\)/) for (const t of ["value: 'warn'", "value: 'mute'", "value: 'suspend'", "value: 'ban'"]) { assert.ok(usersBan.includes(t), `SPA restriction type missing: ${t}`) } for (const dead of ["value: 'muted'", "value: 'restricted'", "value: 'banned'"]) { assert.ok(!usersBan.includes(dead), `invalid SPA restriction type: ${dead}`) } }) test('ban appeal approval actually lifts restrictions', () => { assert.match(usersMenus, /lift_user_restriction\(\$user_id\)/) assert.ok(!usersMenus.includes("SET status = 'lifted'"), 'restriction table has no status column') assert.ok(!usersMenus.includes('clear_user_bans')) assert.ok(!usersMenus.includes('lift_ban')) }) test('profile governance notice reads from the restriction table', () => { assert.match(home, /->is_banned\(\$user_id\)/) assert.match(home, /\\AKSRT\\User\\Restriction::get_instance\(\)/) assert.ok(!home.includes('aksrt_user_ban_state')) }) test('admin report notification links to the real page', () => { assert.match(mailNotifications, /users\.php\?page=aksrt_user_ban&tab=reports/) assert.ok(!mailNotifications.includes('page=aksrt_reports&'), 'dead admin page link') }) test('comments expose a report entry for other users when reporting is enabled', () => { assert.match(commentItem, /data-aksrt-report=\\?'\{"target_type":"comment","target_id":/) assert.match(commentItem, /function aksrt_get_comment_report_html/) assert.match(commentItem, /report'\]\['enabled'\]/) assert.match(commentItem, /\$author_id === \$reporter_id/) }) test('uninstall cleans up every ban/report meta key written by the theme', () => { for (const key of ['_aksrt_active_restrictions', '_aksrt_is_banned', 'aksrt_user_ban_state']) { assert.ok(uninstall.includes(`'${key}'`), `missing uninstall cleanup: ${key}`) } }) test('restriction REST operations pass expiry through to the service', () => { assert.match(restrictionOps, /\$params\['expires_at'\] \?\? ''/) assert.match(restrictionOps, /Restriction::get_instance\(\)->restrict\(/) })