payfrit-api/api/hub/channels/update.php
Mike 629c7d2cef Add Hub Channels API — CRUD endpoints for channel management
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>
2026-03-27 01:06:14 +00:00

98 lines
2.7 KiB
PHP

<?php
/**
* POST /api/hub/channels/update.php
*
* Update a channel's metadata.
*
* Body:
* ID int REQUIRED
* DisplayName string optional
* Purpose string optional
* IsArchived bool optional
* Agent string REQUIRED requesting agent (must be admin/owner)
*
* Response: { OK: true, Channel: { ... } }
*/
require_once __DIR__ . '/../../helpers.php';
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
jsonResponse(['OK' => false, 'ERROR' => 'method_not_allowed'], 405);
}
$body = readJsonBody();
$id = (int) ($body['ID'] ?? 0);
$agent = trim($body['Agent'] ?? '');
if ($id <= 0) {
jsonResponse(['OK' => false, 'ERROR' => 'id_required']);
}
if ($agent === '') {
jsonResponse(['OK' => false, 'ERROR' => 'agent_required']);
}
// Verify channel exists
$channel = queryOne("SELECT * FROM Hub_Channels WHERE ID = ?", [$id]);
if (!$channel) {
jsonResponse(['OK' => false, 'ERROR' => 'channel_not_found'], 404);
}
// Check permissions: must be admin or owner
$membership = queryOne(
"SELECT Role FROM Hub_ChannelMembers WHERE ChannelID = ? AND AgentAddress = ?",
[$id, $agent]
);
if (!$membership || !in_array($membership['Role'], ['admin', 'owner'], true)) {
jsonResponse(['OK' => false, 'ERROR' => 'not_authorized'], 403);
}
// Build update fields
$sets = [];
$params = [];
if (isset($body['DisplayName'])) {
$val = trim($body['DisplayName']);
if (strlen($val) > 200) $val = substr($val, 0, 200);
$sets[] = 'DisplayName = ?';
$params[] = $val;
}
if (isset($body['Purpose'])) {
$val = trim($body['Purpose']);
if (strlen($val) > 500) $val = substr($val, 0, 500);
$sets[] = 'Purpose = ?';
$params[] = $val;
}
if (isset($body['IsArchived'])) {
$sets[] = 'IsArchived = ?';
$params[] = $body['IsArchived'] ? 1 : 0;
}
if (count($sets) === 0) {
jsonResponse(['OK' => false, 'ERROR' => 'nothing_to_update']);
}
$params[] = $id;
queryTimed("UPDATE Hub_Channels SET " . implode(', ', $sets) . " WHERE ID = ?", $params);
// Fetch updated
$channel = queryOne("SELECT * FROM Hub_Channels WHERE ID = ?", [$id]);
$memberCount = queryOne("SELECT COUNT(*) AS cnt FROM Hub_ChannelMembers WHERE ChannelID = ?", [$id]);
jsonResponse([
'OK' => true,
'Channel' => [
'ID' => (int) $channel['ID'],
'Name' => $channel['Name'],
'DisplayName' => $channel['DisplayName'],
'Purpose' => $channel['Purpose'],
'ChannelType' => $channel['ChannelType'],
'CreatedBy' => $channel['CreatedBy'],
'IsArchived' => (bool) $channel['IsArchived'],
'CreatedAt' => toISO8601($channel['CreatedAt']),
'UpdatedAt' => toISO8601($channel['UpdatedAt']),
'MemberCount' => (int) ($memberCount['cnt'] ?? 0),
],
]);