(function () {
"use strict";
var cfg = window.ADMIN_APP_CONFIG || {};
var api = cfg.api || {};
var root = document.getElementById("admin-app");
if (!root) {
return;
}
var state = {
token: readToken(),
user: null,
route: normalizeRoute(readRoute()),
message: "",
messageType: "",
config: null,
system: null,
plugins: [],
integration: {},
realname: null,
devices: null,
busy: false
};
boot();
async function boot() {
window.addEventListener("hashchange", function () {
state.route = normalizeRoute(readRoute());
render();
hydrateRoute();
});
root.addEventListener("click", onClick);
root.addEventListener("submit", onSubmit);
if (state.token) {
await loadBootstrap();
}
render();
hydrateRoute();
}
async function loadBootstrap() {
try {
state.busy = true;
var loginCheck = unwrap(await request("/api/v1/user/checkLogin", { method: "GET" }));
if (!loginCheck || !loginCheck.is_login || !loginCheck.is_admin) {
clearSession();
return;
}
state.user = loginCheck;
var results = await Promise.all([
request(api.adminConfig, { method: "GET" }),
request(api.systemStatus, { method: "GET" }),
request(api.plugins, { method: "GET" }),
request(api.integration, { method: "GET" })
]);
state.config = unwrap(results[0]) || {};
state.system = unwrap(results[1]) || {};
state.plugins = toArray(unwrap(results[2]));
state.integration = unwrap(results[3]) || {};
} catch (error) {
clearSession();
show(error.message || "Failed to load admin data.", "error");
} finally {
state.busy = false;
}
}
async function hydrateRoute() {
if (!state.user) {
return;
}
try {
if (state.route === "realname") {
state.realname = unwrap(await request(api.realnameBase + "/records?per_page=50", { method: "GET" })) || {};
render();
return;
}
if (state.route === "user-online-devices") {
state.devices = unwrap(await request(api.onlineDevices + "?per_page=50", { method: "GET" })) || {};
render();
}
} catch (error) {
show(error.message || "Failed to load page data.", "error");
render();
}
}
function onClick(event) {
var actionEl = event.target.closest("[data-action]");
if (!actionEl) {
return;
}
var action = actionEl.getAttribute("data-action");
if (action === "logout") {
clearSession();
render();
return;
}
if (action === "nav") {
window.location.hash = actionEl.getAttribute("data-route") || "overview";
return;
}
if (action === "refresh") {
refreshAll();
return;
}
if (action === "approve-all") {
adminPost(api.realnameBase + "/approve-all", {}, "Approved all pending records.").then(hydrateRoute);
return;
}
if (action === "sync-all") {
adminPost(api.realnameBase + "/sync-all", {}, "Triggered real-name sync.").then(hydrateRoute);
return;
}
if (action === "clear-cache") {
adminPost(api.realnameBase + "/clear-cache", {}, "Cleared plugin cache.");
return;
}
if (action === "review") {
var userId = actionEl.getAttribute("data-user-id");
var status = actionEl.getAttribute("data-status") || "approved";
var reason = "";
if (status === "rejected") {
reason = window.prompt("Reject reason", "") || "";
}
adminPost(
api.realnameBase + "/review/" + encodeURIComponent(userId),
{ status: status, reason: reason },
"Updated review result."
).then(hydrateRoute);
return;
}
if (action === "reset-record") {
var resetUserId = actionEl.getAttribute("data-user-id");
adminPost(
api.realnameBase + "/reset/" + encodeURIComponent(resetUserId),
{},
"Reset the verification record."
).then(hydrateRoute);
}
}
function onSubmit(event) {
var form = event.target;
if (form.getAttribute("data-form") !== "login") {
return;
}
event.preventDefault();
var formData = serializeForm(form);
request("/api/v1/passport/auth/login", {
method: "POST",
auth: false,
body: formData
}).then(function (response) {
var payload = unwrap(response);
if (!payload || !payload.auth_data || !payload.is_admin) {
throw new Error("This account does not have admin access.");
}
saveToken(payload.auth_data);
state.token = readToken();
return loadBootstrap();
}).then(function () {
show("Admin login successful.", "success");
render();
hydrateRoute();
}).catch(function (error) {
show(error.message || "Login failed.", "error");
render();
});
}
function refreshAll() {
state.realname = null;
state.devices = null;
state.busy = true;
render();
loadBootstrap().then(function () {
render();
return hydrateRoute();
});
}
function clearSession() {
clearToken();
state.user = null;
state.config = null;
state.system = null;
state.plugins = [];
state.integration = {};
state.realname = null;
state.devices = null;
state.route = "overview";
state.busy = false;
}
function render() {
root.innerHTML = state.user ? renderDashboard() : renderLogin();
}
function renderLogin() {
return [
'
',
'
',
'' + escapeHtml(cfg.title || "Admin") + '
Use an administrator account to sign in and open the rebuilt backend workspace.
',
state.message ? renderNotice() : "",
'',
'The backend now uses a single Go-rendered admin shell with integrated plugin pages.
',
'',
'
'
].join("");
}
function renderDashboard() {
return [
'',
renderSidebar(),
'
',
renderTopbar(),
'',
state.message ? renderNotice() : "",
renderMainContent(),
'
',
'',
'
'
].join("");
}
function renderSidebar() {
var items = [
navItem("overview", "Overview", "System status, plugin visibility, and entry summary"),
navItem("realname", "Real Name", "Review and operate the verification workflow"),
navItem("user-online-devices", "Online Devices", "Inspect user sessions and online device data"),
navItem("ipv6-subscription", "IPv6 Subscription", "Check the IPv6 shadow-account integration state"),
navItem("plugin-status", "Plugin Status", "Compare current backend integrations by module")
];
return [
''
].join("");
}
function renderTopbar() {
return [
'',
'',
'
Admin Workspace',
'
' + escapeHtml(getRouteTitle(state.route)) + '
',
'
' + escapeHtml(getRouteDescription(state.route)) + '
',
'
',
'Secure Path /' + escapeHtml(getSecurePath()) + '',
'Server Time ' + escapeHtml(formatDate(state.system && state.system.server_time)) + '',
state.busy ? 'Refreshing' : "",
'
',
'
',
'',
''
].join("");
}
function renderMainContent() {
if (state.route === "realname") {
return renderRealName();
}
if (state.route === "user-online-devices") {
return renderOnlineDevices();
}
if (state.route === "ipv6-subscription") {
return renderIPv6Integration();
}
if (state.route === "plugin-status") {
return renderPluginStatus();
}
return renderOverview();
}
function renderOverview() {
var enabledCount = countEnabledPlugins();
return [
'',
'',
'
Overview',
'
Classic backend structure, rebuilt with the current Go APIs.
',
'
The page keeps the familiar admin navigation pattern while exposing plugin data, system state, and backend integration results in one place.
',
'
',
'',
'
Enabled Plugins' + escapeHtml(String(enabledCount)) + '
',
'
Secure Path/' + escapeHtml(getSecurePath()) + '
',
'
',
'',
'',
statCard("Server Time", formatDate(state.system && state.system.server_time), "Source: /system/getSystemStatus"),
statCard("Admin Path", "/" + getSecurePath(), "Synced from current backend settings"),
statCard("Plugin Count", String((state.plugins || []).length), "Read from the integrated plugin list"),
'',
'Plugins
Integrated plugin list
Each entry reflects the current Go backend response and the copied integration status.
' + renderPluginsTable() + '
'
].join("");
}
function renderRealName() {
var rows = toArray(state.realname, "data");
var loading = state.realname === null;
return [
'',
'Workflow
Real-name verification
Batch actions stay in the toolbar while the review table keeps the classic admin operating rhythm.
',
'',
'| ID | Email | Status | Real Name | ID Number | Submitted At | Actions |
',
loading ? '| Loading verification records... |
' : rows.length ? rows.map(function (row) {
return [
'',
'| ' + escapeHtml(String(row.id || "")) + ' | ',
'' + escapeHtml(row.email || "-") + ' | ',
'' + renderStatus(row.status) + ' | ',
'' + escapeHtml(row.real_name || "-") + ' | ',
'' + escapeHtml(row.identity_no_masked || "-") + ' | ',
'' + escapeHtml(formatDate(row.submitted_at)) + ' | ',
' | ',
'
'
].join("");
}).join("") : '| No verification records available. |
',
'
',
''
].join("");
}
function renderOnlineDevices() {
var rows = toArray(state.devices, "list");
var loading = state.devices === null;
return [
'',
'Monitoring
Online devices
This table keeps the admin-friendly scan pattern for sessions, subscription names, IPs, and recent activity.
',
'| User | Subscription | Online Count | Online IPs | Last Seen | Created At |
',
loading ? '| Loading device records... |
' : rows.length ? rows.map(function (row) {
return [
'',
'| ' + escapeHtml(row.email || "-") + ' | ',
'' + escapeHtml(row.subscription_name || "-") + ' | ',
'' + escapeHtml(String(row.online_count || 0)) + ' | ',
'' + escapeHtml(formatDeviceList(row.online_devices)) + ' | ',
'' + escapeHtml(row.last_online_text || "-") + ' | ',
'' + escapeHtml(row.created_text || "-") + ' | ',
'
'
].join("");
}).join("") : '| No online device records available. |
',
'
',
''
].join("");
}
function renderIPv6Integration() {
var integration = (state.integration && state.integration.user_add_ipv6_subscription) || {};
return [
'',
'Integration
IPv6 shadow subscription
' + escapeHtml(buildSummary(integration, "This panel shows the current runtime status of the IPv6 shadow-account integration.")) + '
',
'' + renderStatus(integration.status || "unknown") + '
',
'' + escapeHtml(stringifyJSON(integration)) + '
',
''
].join("");
}
function renderPluginStatus() {
var cards = [
sectionCard("Real-name verification", state.integration && state.integration.real_name_verification),
sectionCard("Online devices", state.integration && state.integration.user_online_devices),
sectionCard("IPv6 shadow subscription", state.integration && state.integration.user_add_ipv6_subscription)
];
return '';
}
function renderPluginsTable() {
var rows = toArray(state.plugins);
return '| ID | Code | Status | Config |
' + (rows.length ? rows.map(function (row) {
return '| ' + escapeHtml(String(row.id || "")) + ' | ' + escapeHtml(row.code || row.name || "-") + ' | ' + renderStatus(row.is_enabled ? "enabled" : "disabled") + ' | ' + escapeHtml(formatPluginConfig(row.config)) + ' |
';
}).join("") : '| No plugin data available. |
') + '
';
}
function sectionCard(title, data) {
data = data || {};
return [
'',
'Module
' + escapeHtml(title) + '
',
'' + escapeHtml(buildSummary(data, "No summary has been returned by the backend for this module.")) + '
',
renderStatus(data.status || "unknown"),
'' + escapeHtml(stringifyJSON(data)) + '
',
''
].join("");
}
function navItem(route, title, desc) {
return '';
}
function statCard(title, value, hint) {
return '' + escapeHtml(title) + '' + escapeHtml(value || "-") + '' + escapeHtml(hint || "") + '
';
}
function renderNotice() {
return '' + escapeHtml(state.message || "") + '
';
}
function countEnabledPlugins() {
return toArray(state.plugins).filter(function (item) {
return !!item.is_enabled;
}).length;
}
function buildSummary(data, fallback) {
if (!data) {
return fallback;
}
if (typeof data.summary === "string" && data.summary.trim()) {
return data.summary.trim();
}
if (typeof data.message === "string" && data.message.trim()) {
return data.message.trim();
}
return fallback;
}
function formatPluginConfig(value) {
if (typeof value === "string" && value.trim()) {
return value;
}
return stringifyJSON(value || {});
}
function stringifyJSON(value) {
try {
return JSON.stringify(value == null ? {} : value, null, 2);
} catch (error) {
return String(value == null ? "" : value);
}
}
function formatDeviceList(value) {
if (Array.isArray(value)) {
return value.join(", ") || "-";
}
if (typeof value === "string" && value.trim()) {
return value;
}
return "-";
}
function toArray(value, preferredKey) {
if (Array.isArray(value)) {
return value;
}
if (!value || typeof value !== "object") {
return [];
}
if (preferredKey && Array.isArray(value[preferredKey])) {
return value[preferredKey];
}
if (Array.isArray(value.data)) {
return value.data;
}
if (Array.isArray(value.list)) {
return value.list;
}
return [];
}
function request(url, options) {
options = options || {};
var headers = {
"Content-Type": "application/json"
};
if (options.auth !== false && state.token) {
headers.Authorization = state.token;
}
return fetch(url, {
method: options.method || "GET",
headers: headers,
credentials: "same-origin",
body: options.body ? JSON.stringify(options.body) : undefined
}).then(async function (response) {
var payload = null;
try {
payload = await response.json();
} catch (error) {
payload = null;
}
if (!response.ok) {
if (response.status === 401) {
clearSession();
render();
}
throw new Error(getErrorMessage(payload) || "Request failed.");
}
return payload;
});
}
function adminPost(url, body, successMessage) {
return request(url, {
method: "POST",
body: body || {}
}).then(function (payload) {
show(successMessage || "Operation completed.", "success");
render();
return payload;
}).catch(function (error) {
show(error.message || "Operation failed.", "error");
render();
throw error;
});
}
function unwrap(payload) {
if (!payload) {
return null;
}
return typeof payload.data !== "undefined" ? payload.data : payload;
}
function getErrorMessage(payload) {
if (!payload) {
return "";
}
return payload.message || payload.msg || payload.error || "";
}
function saveToken(token) {
var normalized = /^Bearer /.test(token) ? token : "Bearer " + token;
window.localStorage.setItem("__gopanel_admin_auth__", normalized);
}
function serializeForm(form) {
var result = {};
var formData = new FormData(form);
formData.forEach(function (value, key) {
result[key] = value;
});
return result;
}
function readToken() {
var token = window.localStorage.getItem("__gopanel_admin_auth__") ||
window.localStorage.getItem("__nebula_auth_data__") ||
window.localStorage.getItem("auth_data") ||
"";
if (!token) {
return "";
}
return /^Bearer /.test(token) ? token : "Bearer " + token;
}
function clearToken() {
window.localStorage.removeItem("__gopanel_admin_auth__");
state.token = "";
}
function readRoute() {
return (window.location.hash || "#overview").slice(1) || "overview";
}
function normalizeRoute(route) {
var allowed = {
overview: true,
realname: true,
"user-online-devices": true,
"ipv6-subscription": true,
"plugin-status": true
};
return allowed[route] ? route : "overview";
}
function getSecurePath() {
return (state.config && state.config.secure_path) || cfg.securePath || "admin";
}
function getRouteTitle(route) {
if (route === "realname") {
return "Real-name Verification";
}
if (route === "user-online-devices") {
return "Online Devices";
}
if (route === "ipv6-subscription") {
return "IPv6 Subscription";
}
if (route === "plugin-status") {
return "Plugin Status";
}
return "Overview";
}
function getRouteDescription(route) {
if (route === "realname") {
return "Review records, run batch actions, and keep the original backend workflow readable.";
}
if (route === "user-online-devices") {
return "Inspect active users, current devices, and recent online activity in one table.";
}
if (route === "ipv6-subscription") {
return "Check the replicated backend integration output for the IPv6 shadow-account module.";
}
if (route === "plugin-status") {
return "Compare plugin integration payloads and runtime summaries side by side.";
}
return "A familiar backend workspace with sidebar navigation, top control bar, and focused content cards.";
}
function show(message, type) {
state.message = message || "";
state.messageType = type || "";
}
function formatDate(value) {
if (!value) {
return "-";
}
var numeric = Number(value);
if (!Number.isNaN(numeric) && numeric > 0) {
return new Date(numeric * 1000).toLocaleString();
}
var parsed = Date.parse(value);
if (!Number.isNaN(parsed)) {
return new Date(parsed).toLocaleString();
}
return String(value);
}
function renderStatus(status) {
var raw = String(status || "unknown");
var normalized = raw.toLowerCase();
var klass = "status-pill status-ok";
if (normalized.indexOf("warn") !== -1 || normalized.indexOf("pending") !== -1 || normalized.indexOf("runtime") !== -1) {
klass = "status-pill status-warn";
}
if (normalized.indexOf("disabled") !== -1 || normalized.indexOf("fail") !== -1 || normalized.indexOf("error") !== -1 || normalized.indexOf("reject") !== -1 || normalized.indexOf("unknown") !== -1) {
klass = "status-pill status-danger";
}
return '' + escapeHtml(raw) + '';
}
function escapeHtml(value) {
return String(value == null ? "" : value)
.replace(/&/g, "&")
.replace(//g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
})();