New endpoints under /api/hub/channels/: - create.php: Create channel with type (public/private/direct), auto-add creator as owner - list.php: List channels with filters (type, agent membership, archived, pagination) - get.php: Get channel by ID or Name, includes member list - update.php: Update display name, purpose, archive status (admin/owner only) - delete.php: Hard-delete channel (owner only), FK cascade removes members - members.php: List channel members with agent info - join.php: Join public channels (private requires invite) - leave.php: Leave channel (owners blocked from leaving) Database: Hub_Channels + Hub_ChannelMembers tables with FK cascade. Task #59 (T51-Sub1) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
77 lines
2.5 KiB
PHP
77 lines
2.5 KiB
PHP
<?php
|
|
/**
|
|
* GET /api/hub/channels/list.php
|
|
*
|
|
* List channels with optional filters.
|
|
*
|
|
* Query params:
|
|
* ChannelType string optional filter by type (public|private|direct)
|
|
* Agent string optional only channels this agent is a member of
|
|
* IncludeArchived 1|0 optional include archived channels (default: 0)
|
|
* Limit int optional max results (default: 50, max: 200)
|
|
* Offset int optional pagination offset (default: 0)
|
|
*
|
|
* Response: { OK: true, Channels: [...], Total: int }
|
|
*/
|
|
|
|
require_once __DIR__ . '/../../helpers.php';
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
|
|
jsonResponse(['OK' => false, 'ERROR' => 'method_not_allowed'], 405);
|
|
}
|
|
|
|
$channelType = trim($_GET['ChannelType'] ?? '');
|
|
$agent = trim($_GET['Agent'] ?? '');
|
|
$includeArchived = ($_GET['IncludeArchived'] ?? '0') === '1';
|
|
$limit = min(max((int) ($_GET['Limit'] ?? 50), 1), 200);
|
|
$offset = max((int) ($_GET['Offset'] ?? 0), 0);
|
|
|
|
$where = [];
|
|
$params = [];
|
|
|
|
if (!$includeArchived) {
|
|
$where[] = 'c.IsArchived = 0';
|
|
}
|
|
|
|
if ($channelType !== '' && in_array($channelType, ['public', 'private', 'direct'], true)) {
|
|
$where[] = 'c.ChannelType = ?';
|
|
$params[] = $channelType;
|
|
}
|
|
|
|
$join = '';
|
|
if ($agent !== '') {
|
|
$join = 'INNER JOIN Hub_ChannelMembers m ON m.ChannelID = c.ID AND m.AgentAddress = ?';
|
|
array_unshift($params, $agent);
|
|
}
|
|
|
|
$whereClause = count($where) > 0 ? 'WHERE ' . implode(' AND ', $where) : '';
|
|
|
|
// Count total
|
|
$countSql = "SELECT COUNT(*) AS cnt FROM Hub_Channels c $join $whereClause";
|
|
$countRow = queryOne($countSql, $params);
|
|
$total = (int) ($countRow['cnt'] ?? 0);
|
|
|
|
// Fetch page
|
|
$dataSql = "SELECT c.*, (SELECT COUNT(*) FROM Hub_ChannelMembers WHERE ChannelID = c.ID) AS MemberCount
|
|
FROM Hub_Channels c $join $whereClause
|
|
ORDER BY c.CreatedAt DESC LIMIT ? OFFSET ?";
|
|
$dataParams = array_merge($params, [$limit, $offset]);
|
|
$rows = queryTimed($dataSql, $dataParams);
|
|
|
|
$channels = [];
|
|
foreach ($rows as $r) {
|
|
$channels[] = [
|
|
'ID' => (int) $r['ID'],
|
|
'Name' => $r['Name'],
|
|
'DisplayName' => $r['DisplayName'],
|
|
'Purpose' => $r['Purpose'],
|
|
'ChannelType' => $r['ChannelType'],
|
|
'CreatedBy' => $r['CreatedBy'],
|
|
'IsArchived' => (bool) $r['IsArchived'],
|
|
'CreatedAt' => toISO8601($r['CreatedAt']),
|
|
'UpdatedAt' => toISO8601($r['UpdatedAt']),
|
|
'MemberCount' => (int) $r['MemberCount'],
|
|
];
|
|
}
|
|
|
|
jsonResponse(['OK' => true, 'Channels' => $channels, 'Total' => $total]);
|