feat: 用户组同步+管理API (sync_user_groups, land_api endpoints)

This commit is contained in:
ypsdf1
2026-06-27 23:05:27 +08:00
parent c0672ad47a
commit 5f43fb1407
2 changed files with 282 additions and 0 deletions
+197
View File
@@ -307,6 +307,32 @@ try {
handleAckAdminChanges($db, $_POST + $_GET);
break;
// ===== 用户组管理 =====
case 'list_user_groups':
handleListUserGroups($db);
break;
case 'get_user_group':
handleGetUserGroup($db, $_GET['name'] ?? '');
break;
case 'update_user_group':
handleUpdateUserGroup($db, $_POST + $_GET);
break;
case 'delete_user_group':
handleDeleteUserGroup($db, $_GET['name'] ?? '');
break;
case 'list_group_members':
handleListGroupMembers($db, $_GET['group'] ?? '');
break;
case 'add_group_member':
handleAddGroupMember($db, $_POST + $_GET);
break;
case 'remove_group_member':
handleRemoveGroupMember($db, $_POST + $_GET);
break;
case 'get_player_groups':
handleGetPlayerGroups($db, $_GET['player'] ?? '');
break;
default:
echo json_encode(['success' => false, 'error' => 'unknown action']);
}
@@ -1415,6 +1441,177 @@ function handleAckAdminChanges($db, $post) {
echo json_encode(['success' => true, 'acked' => count($idList)]);
}
// ===== 用户组管理函数 =====
function handleListUserGroups($db) {
$db->exec("CREATE TABLE IF NOT EXISTS web_user_groups (
group_name TEXT PRIMARY KEY,
display_name TEXT DEFAULT '',
display_color TEXT DEFAULT '§f',
display_emoji TEXT DEFAULT '',
priority INTEGER DEFAULT 0,
land_price_per_sqm INTEGER DEFAULT -1,
max_lands INTEGER DEFAULT -1,
default_perms TEXT DEFAULT '{}',
synced_at INTEGER DEFAULT 0
)");
$rs = $db->query("SELECT * FROM web_user_groups ORDER BY priority DESC");
$groups = [];
while ($row = $rs->fetchArray(SQLITE3_ASSOC)) {
$groups[] = $row;
}
echo json_encode(['success' => true, 'groups' => $groups]);
}
function handleGetUserGroup($db, $name) {
if (empty($name)) { echo json_encode(['success' => false, 'error' => 'missing name']); return; }
$stmt = $db->prepare("SELECT * FROM web_user_groups WHERE group_name = :name");
$stmt->bindValue(':name', $name, SQLITE3_TEXT);
$rs = $stmt->execute();
$row = $rs->fetchArray(SQLITE3_ASSOC);
if (!$row) { echo json_encode(['success' => false, 'error' => 'group not found']); return; }
echo json_encode(['success' => true, 'group' => $row]);
}
function handleUpdateUserGroup($db, $data) {
$name = $data['name'] ?? $data['group_name'] ?? '';
if (empty($name)) { echo json_encode(['success' => false, 'error' => 'missing name']); return; }
$db->exec("CREATE TABLE IF NOT EXISTS web_user_groups (
group_name TEXT PRIMARY KEY,
display_name TEXT DEFAULT '',
display_color TEXT DEFAULT '§f',
display_emoji TEXT DEFAULT '',
priority INTEGER DEFAULT 0,
land_price_per_sqm INTEGER DEFAULT -1,
max_lands INTEGER DEFAULT -1,
default_perms TEXT DEFAULT '{}',
synced_at INTEGER DEFAULT 0
)");
$displayName = $data['display_name'] ?? '';
$displayColor = $data['display_color'] ?? '§f';
$displayEmoji = $data['display_emoji'] ?? '';
$priority = (int)($data['priority'] ?? 0);
$pricePerSqm = (int)($data['land_price_per_sqm'] ?? -1);
$maxLands = (int)($data['max_lands'] ?? -1);
$defaultPerms = $data['default_perms'] ?? '{}';
$stmt = $db->prepare("INSERT OR REPLACE INTO web_user_groups
(group_name, display_name, display_color, display_emoji, priority,
land_price_per_sqm, max_lands, default_perms, synced_at)
VALUES (:name, :display, :color, :emoji, :priority,
:price, :maxlands, :perms, :synced)");
$stmt->bindValue(':name', $name, SQLITE3_TEXT);
$stmt->bindValue(':display', $displayName, SQLITE3_TEXT);
$stmt->bindValue(':color', $displayColor, SQLITE3_TEXT);
$stmt->bindValue(':emoji', $displayEmoji, SQLITE3_TEXT);
$stmt->bindValue(':priority', $priority, SQLITE3_INTEGER);
$stmt->bindValue(':price', $pricePerSqm, SQLITE3_INTEGER);
$stmt->bindValue(':maxlands', $maxLands, SQLITE3_INTEGER);
$stmt->bindValue(':perms', $defaultPerms, SQLITE3_TEXT);
$stmt->bindValue(':synced', time(), SQLITE3_INTEGER);
$stmt->execute();
echo json_encode(['success' => true, 'message' => "用户组 {$name} 已更新"]);
}
function handleDeleteUserGroup($db, $name) {
if (empty($name)) { echo json_encode(['success' => false, 'error' => 'missing name']); return; }
$stmt = $db->prepare("DELETE FROM web_user_groups WHERE group_name = :name");
$stmt->bindValue(':name', $name, SQLITE3_TEXT);
$stmt->execute();
echo json_encode(['success' => true, 'message' => "用户组 {$name} 已删除"]);
}
function handleListGroupMembers($db, $group) {
if (empty($group)) { echo json_encode(['success' => false, 'error' => 'missing group']); return; }
$db->exec("CREATE TABLE IF NOT EXISTS web_user_group_members (
player_name TEXT NOT NULL,
group_name TEXT NOT NULL,
added_by TEXT DEFAULT 'system',
added_time INTEGER DEFAULT 0,
expiry_time INTEGER DEFAULT 0,
PRIMARY KEY(player_name, group_name)
)");
$stmt = $db->prepare("SELECT * FROM web_user_group_members WHERE group_name = :group");
$stmt->bindValue(':group', $group, SQLITE3_TEXT);
$rs = $stmt->execute();
$members = [];
while ($row = $rs->fetchArray(SQLITE3_ASSOC)) {
$members[] = $row;
}
echo json_encode(['success' => true, 'members' => $members]);
}
function handleAddGroupMember($db, $data) {
$player = $data['player'] ?? $data['player_name'] ?? '';
$group = $data['group'] ?? $data['group_name'] ?? '';
if (empty($player) || empty($group)) {
echo json_encode(['success' => false, 'error' => 'missing player or group']);
return;
}
$db->exec("CREATE TABLE IF NOT EXISTS web_user_group_members (
player_name TEXT NOT NULL,
group_name TEXT NOT NULL,
added_by TEXT DEFAULT 'system',
added_time INTEGER DEFAULT 0,
expiry_time INTEGER DEFAULT 0,
PRIMARY KEY(player_name, group_name)
)");
$addedBy = $data['added_by'] ?? 'admin';
$now = time();
$expiry = (int)($data['expiry_time'] ?? 0);
$stmt = $db->prepare("INSERT OR REPLACE INTO web_user_group_members
(player_name, group_name, added_by, added_time, expiry_time)
VALUES (:player, :group, :addedby, :added, :expiry)");
$stmt->bindValue(':player', $player, SQLITE3_TEXT);
$stmt->bindValue(':group', $group, SQLITE3_TEXT);
$stmt->bindValue(':addedby', $addedBy, SQLITE3_TEXT);
$stmt->bindValue(':added', $now, SQLITE3_INTEGER);
$stmt->bindValue(':expiry', $expiry, SQLITE3_INTEGER);
$stmt->execute();
echo json_encode(['success' => true, 'message' => "{$player} 已加入用户组 {$group}"]);
}
function handleRemoveGroupMember($db, $data) {
$player = $data['player'] ?? $data['player_name'] ?? '';
$group = $data['group'] ?? $data['group_name'] ?? '';
if (empty($player) || empty($group)) {
echo json_encode(['success' => false, 'error' => 'missing player or group']);
return;
}
$stmt = $db->prepare("DELETE FROM web_user_group_members WHERE player_name = :player AND group_name = :group");
$stmt->bindValue(':player', $player, SQLITE3_TEXT);
$stmt->bindValue(':group', $group, SQLITE3_TEXT);
$stmt->execute();
echo json_encode(['success' => true, 'message' => "{$player} 已移出用户组 {$group}"]);
}
function handleGetPlayerGroups($db, $player) {
if (empty($player)) { echo json_encode(['success' => false, 'error' => 'missing player']); return; }
$db->exec("CREATE TABLE IF NOT EXISTS web_user_group_members (
player_name TEXT NOT NULL,
group_name TEXT NOT NULL,
added_by TEXT DEFAULT 'system',
added_time INTEGER DEFAULT 0,
expiry_time INTEGER DEFAULT 0,
PRIMARY KEY(player_name, group_name)
)");
$stmt = $db->prepare("SELECT m.*, g.display_name, g.display_color, g.priority
FROM web_user_group_members m
LEFT JOIN web_user_groups g ON m.group_name = g.group_name
WHERE m.player_name = :player");
$stmt->bindValue(':player', $player, SQLITE3_TEXT);
$rs = $stmt->execute();
$groups = [];
while ($row = $rs->fetchArray(SQLITE3_ASSOC)) {
$groups[] = $row;
}
echo json_encode(['success' => true, 'groups' => $groups]);
}
function validateSecret($secret) {
if (empty($secret)) return false;
$validSecrets = [
+85
View File
@@ -312,6 +312,9 @@ switch ($action) {
case 'sync_permissions':
syncPermissions();
break;
case 'sync_user_groups':
syncUserGroups();
break;
default:
error('未知操作: ' . $action);
}
@@ -678,6 +681,88 @@ function syncPermissions() {
success("访客权限同步成功: {$count}个");
}
// ===== 用户组同步 =====
function syncUserGroups() {
$secret = getParam('secret');
if ($secret !== SECRET_KEY) error('密钥验证失败', 403);
$groupsRaw = getParam('groups');
if (!$groupsRaw) error('缺少groups参数');
$groups = is_array($groupsRaw) ? $groupsRaw : json_decode($groupsRaw, true);
if (!is_array($groups)) error('groups格式无效');
$db = getDB();
$db->exec("CREATE TABLE IF NOT EXISTS web_user_groups (
group_name TEXT PRIMARY KEY,
display_name TEXT DEFAULT '',
display_color TEXT DEFAULT '§f',
display_emoji TEXT DEFAULT '',
priority INTEGER DEFAULT 0,
land_price_per_sqm INTEGER DEFAULT -1,
max_lands INTEGER DEFAULT -1,
default_perms TEXT DEFAULT '{}',
synced_at INTEGER DEFAULT 0
)");
$now = time();
$stmt = $db->prepare("INSERT OR REPLACE INTO web_user_groups
(group_name, display_name, display_color, display_emoji, priority,
land_price_per_sqm, max_lands, default_perms, synced_at)
VALUES (:name, :display, :color, :emoji, :priority,
:price, :maxlands, :perms, :synced)");
$count = 0;
foreach ($groups as $g) {
$stmt->bindValue(':name', $g['group_name'] ?? '', SQLITE3_TEXT);
$stmt->bindValue(':display', $g['display_name'] ?? '', SQLITE3_TEXT);
$stmt->bindValue(':color', $g['display_color'] ?? '§f', SQLITE3_TEXT);
$stmt->bindValue(':emoji', $g['display_emoji'] ?? '', SQLITE3_TEXT);
$stmt->bindValue(':priority', (int)($g['priority'] ?? 0), SQLITE3_INTEGER);
$stmt->bindValue(':price', (int)($g['land_price_per_sqm'] ?? -1), SQLITE3_INTEGER);
$stmt->bindValue(':maxlands', (int)($g['max_lands'] ?? -1), SQLITE3_INTEGER);
$stmt->bindValue(':perms', $g['default_perms'] ?? '{}', SQLITE3_TEXT);
$stmt->bindValue(':synced', $now, SQLITE3_INTEGER);
$stmt->execute();
$count++;
}
success("用户组同步成功: {$count}个");
}
// ===== 用户组成员同步 =====
function syncUserGroupMembers() {
$secret = getParam('secret');
if ($secret !== SECRET_KEY) error('密钥验证失败', 403);
$membersRaw = getParam('members');
if (!$membersRaw) error('缺少members参数');
$members = is_array($membersRaw) ? $membersRaw : json_decode($membersRaw, true);
if (!is_array($members)) error('members格式无效');
$db = getDB();
$db->exec("CREATE TABLE IF NOT EXISTS web_user_group_members (
player_name TEXT NOT NULL,
group_name TEXT NOT NULL,
added_by TEXT DEFAULT 'system',
added_time INTEGER DEFAULT 0,
expiry_time INTEGER DEFAULT 0,
PRIMARY KEY(player_name, group_name)
)");
$stmt = $db->prepare("INSERT OR REPLACE INTO web_user_group_members
(player_name, group_name, added_by, added_time, expiry_time)
VALUES (:player, :group, :addedby, :added, :expiry)");
$count = 0;
foreach ($members as $m) {
$stmt->bindValue(':player', $m['player_name'] ?? '', SQLITE3_TEXT);
$stmt->bindValue(':group', $m['group_name'] ?? '', SQLITE3_TEXT);
$stmt->bindValue(':addedby', $m['added_by'] ?? 'system', SQLITE3_TEXT);
$stmt->bindValue(':added', (int)($m['added_time'] ?? 0), SQLITE3_INTEGER);
$stmt->bindValue(':expiry', (int)($m['expiry_time'] ?? 0), SQLITE3_INTEGER);
$stmt->execute();
$count++;
}
success("用户组成员同步成功: {$count}条");
}
// ===== 插件推送债券余额 =====
function syncBonds() {
// ★ 支持token或SECRET_KEY认证