false, 'ERROR' => 'method_not_allowed'], 405); } $body = readJsonBody(); $channelId = (int) ($body['ChannelID'] ?? 0); $senderAddress = trim($body['SenderAddress'] ?? ''); $content = trim($body['Content'] ?? ''); $parentId = isset($body['ParentID']) ? (int) $body['ParentID'] : null; if ($channelId <= 0) jsonResponse(['OK' => false, 'ERROR' => 'channel_id_required']); if ($senderAddress === '') jsonResponse(['OK' => false, 'ERROR' => 'sender_address_required']); if ($content === '') jsonResponse(['OK' => false, 'ERROR' => 'content_required']); // Verify channel exists and is not archived $channel = queryOne("SELECT ID, IsArchived FROM Hub_Channels WHERE ID = ?", [$channelId]); if (!$channel) jsonResponse(['OK' => false, 'ERROR' => 'channel_not_found']); if ((bool) $channel['IsArchived']) jsonResponse(['OK' => false, 'ERROR' => 'channel_archived']); // Verify sender is a member of the channel $member = queryOne( "SELECT ID FROM Hub_ChannelMembers WHERE ChannelID = ? AND AgentAddress = ?", [$channelId, $senderAddress] ); if (!$member) jsonResponse(['OK' => false, 'ERROR' => 'not_a_member']); // Verify parent message exists and belongs to same channel (if threaded) if ($parentId !== null) { $parent = queryOne( "SELECT ID FROM Hub_Messages WHERE ID = ? AND ChannelID = ? AND IsDeleted = 0", [$parentId, $channelId] ); if (!$parent) jsonResponse(['OK' => false, 'ERROR' => 'parent_message_not_found']); } // Insert message queryTimed( "INSERT INTO Hub_Messages (ChannelID, SenderAddress, Content, ParentID) VALUES (?, ?, ?, ?)", [$channelId, $senderAddress, $content, $parentId] ); $messageId = (int) lastInsertId(); // Update member's last viewed queryTimed( "UPDATE Hub_ChannelMembers SET LastViewedAt = NOW() WHERE ChannelID = ? AND AgentAddress = ?", [$channelId, $senderAddress] ); $msg = queryOne("SELECT * FROM Hub_Messages WHERE ID = ?", [$messageId]); jsonResponse([ 'OK' => true, 'Message' => [ 'ID' => (int) $msg['ID'], 'ChannelID' => (int) $msg['ChannelID'], 'SenderAddress' => $msg['SenderAddress'], 'Content' => $msg['Content'], 'ParentID' => $msg['ParentID'] ? (int) $msg['ParentID'] : null, 'IsEdited' => (bool) $msg['IsEdited'], 'IsDeleted' => false, 'CreatedAt' => toISO8601($msg['CreatedAt']), 'UpdatedAt' => toISO8601($msg['UpdatedAt']), ], ]);