Files
easystream-main/api/subscriptions.php
SamiAhmed7777 f0f346deb9
Some checks failed
EasyStream Test Suite / test (pull_request) Has been cancelled
EasyStream Test Suite / code-quality (pull_request) Has been cancelled
EasyStream Test Suite / integration-test (pull_request) Has been cancelled
Sync current dev state
2025-12-15 17:28:21 -08:00

369 lines
12 KiB
PHP

<?php
/**
* Subscriptions API Endpoint
* Handles subscription-related operations
*
* Supported Actions:
* - GET list: Get user's subscriptions or subscribers
* - POST subscribe: Subscribe to a channel
* - DELETE unsubscribe: Unsubscribe from a channel
* - GET feed: Get activity feed from subscribed channels
*/
// Include CORS configuration
require_once __DIR__ . '/cors.config.php';
header('Content-Type: application/json');
// Include core configuration
require_once dirname(__FILE__) . '/../f_core/config.core.php';
// Initialize response
$response = ['success' => false, 'data' => null, 'error' => null];
try {
// Get action from query parameter
$action = isset($_GET['action']) ? $_GET['action'] : null;
$method = $_SERVER['REQUEST_METHOD'];
// Get authenticated user (supports both session and JWT)
$userId = null;
// Try JWT authentication first
$authHeader = isset($_SERVER['HTTP_AUTHORIZATION']) ? $_SERVER['HTTP_AUTHORIZATION'] :
(isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) ? $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] : null);
if ($authHeader && preg_match('/Bearer\s+(.*)$/i', $authHeader, $matches)) {
$token = $matches[1];
$tokenData = VAuth::verifyToken($token);
if ($tokenData && isset($tokenData['user_id'])) {
$userId = $tokenData['user_id'];
}
}
// Fall back to session authentication
if (!$userId && isset($_SESSION['USER_ID'])) {
$userId = $_SESSION['USER_ID'];
} elseif (!$userId && isset($_SESSION['usr_id'])) {
$userId = $_SESSION['usr_id'];
}
if (!$userId) {
throw new Exception('Authentication required', 401);
}
// Route based on method and action
switch ($method) {
case 'GET':
switch ($action) {
case 'list':
case 'subscriptions':
case null:
handleGetSubscriptions($userId);
break;
case 'subscribers':
handleGetSubscribers($userId);
break;
case 'feed':
handleGetFeed($userId);
break;
case 'check':
handleCheckSubscription($userId);
break;
default:
throw new Exception('Invalid action', 400);
}
break;
case 'POST':
handleSubscribe($userId);
break;
case 'DELETE':
handleUnsubscribe($userId);
break;
default:
throw new Exception('Method not allowed', 405);
}
} catch (Exception $e) {
http_response_code($e->getCode() >= 400 && $e->getCode() < 600 ? $e->getCode() : 500);
$response['error'] = $e->getMessage();
echo json_encode($response);
exit;
}
/**
* Get user's subscriptions
*/
function handleGetSubscriptions($userId) {
global $class_database, $response;
$sql = "SELECT u.usr_id, u.usr_user, u.usr_dname, u.usr_avatar,
u.usr_verified, u.usr_partner,
s.sub_date,
(SELECT COUNT(*) FROM db_videofiles WHERE usr_id = u.usr_id AND approved = 1 AND privacy = 'public') as video_count,
(SELECT COUNT(*) FROM db_subscriptions WHERE channel_id = u.usr_id) as subscriber_count,
(SELECT MAX(upload_date) FROM db_videofiles WHERE usr_id = u.usr_id AND approved = 1) as last_upload
FROM db_subscriptions s
LEFT JOIN db_users u ON s.channel_id = u.usr_id
WHERE s.usr_id = ?
ORDER BY s.sub_date DESC";
$result = $class_database->execute($sql, [$userId]);
$subscriptions = $result ? $result->GetArray() : [];
$response['success'] = true;
$response['data'] = [
'subscriptions' => $subscriptions,
'total' => count($subscriptions)
];
echo json_encode($response);
}
/**
* Get subscribers for a channel
*/
function handleGetSubscribers($userId) {
global $class_database, $response;
$channelId = isset($_GET['channel_id']) ? (int)$_GET['channel_id'] : $userId;
$page = isset($_GET['page']) ? max(1, (int)$_GET['page']) : 1;
$limit = isset($_GET['limit']) ? min(100, max(1, (int)$_GET['limit'])) : 50;
$offset = ($page - 1) * $limit;
// Get total count
$countSql = "SELECT COUNT(*) FROM db_subscriptions WHERE channel_id = ?";
$total = (int)$class_database->singleFieldValue($countSql, [$channelId]);
// Get subscribers
$sql = "SELECT u.usr_id, u.usr_user, u.usr_dname, u.usr_avatar,
u.usr_verified, s.sub_date
FROM db_subscriptions s
LEFT JOIN db_users u ON s.usr_id = u.usr_id
WHERE s.channel_id = ?
ORDER BY s.sub_date DESC
LIMIT ? OFFSET ?";
$result = $class_database->execute($sql, [$channelId, $limit, $offset]);
$response['success'] = true;
$response['data'] = [
'subscribers' => $result ? $result->GetArray() : [],
'pagination' => [
'page' => $page,
'limit' => $limit,
'total' => $total,
'pages' => ceil($total / $limit)
]
];
echo json_encode($response);
}
/**
* Get activity feed from subscribed channels
*/
function handleGetFeed($userId) {
global $class_database, $response;
$page = isset($_GET['page']) ? max(1, (int)$_GET['page']) : 1;
$limit = isset($_GET['limit']) ? min(100, max(1, (int)$_GET['limit'])) : 20;
$offset = ($page - 1) * $limit;
// Get videos from subscribed channels
$sql = "SELECT v.file_key, v.file_title, v.file_description, v.file_duration,
v.file_views, v.upload_date, v.thumbnail, v.featured,
u.usr_id, u.usr_user, u.usr_dname, u.usr_avatar, u.usr_verified,
(SELECT COUNT(*) FROM db_likes WHERE file_key = v.file_key AND like_type = 'like') as like_count,
(SELECT COUNT(*) FROM db_comments WHERE file_key = v.file_key) as comment_count
FROM db_videofiles v
LEFT JOIN db_users u ON v.usr_id = u.usr_id
INNER JOIN db_subscriptions s ON s.channel_id = v.usr_id
WHERE s.usr_id = ? AND v.approved = 1 AND v.privacy = 'public'
ORDER BY v.upload_date DESC
LIMIT ? OFFSET ?";
$result = $class_database->execute($sql, [$userId, $limit, $offset]);
// Get total count
$countSql = "SELECT COUNT(*)
FROM db_videofiles v
INNER JOIN db_subscriptions s ON s.channel_id = v.usr_id
WHERE s.usr_id = ? AND v.approved = 1 AND v.privacy = 'public'";
$total = (int)$class_database->singleFieldValue($countSql, [$userId]);
$response['success'] = true;
$response['data'] = [
'videos' => $result ? $result->GetArray() : [],
'pagination' => [
'page' => $page,
'limit' => $limit,
'total' => $total,
'pages' => ceil($total / $limit)
]
];
echo json_encode($response);
}
/**
* Check if subscribed to a channel
*/
function handleCheckSubscription($userId) {
global $class_database, $response;
$channelId = isset($_GET['channel_id']) ? (int)$_GET['channel_id'] : null;
if (!$channelId) {
throw new Exception('channel_id is required', 400);
}
$sql = "SELECT sub_date FROM db_subscriptions WHERE usr_id = ? AND channel_id = ?";
$result = $class_database->execute($sql, [$userId, $channelId]);
$isSubscribed = $result && $result->RecordCount() > 0;
$subDate = $isSubscribed ? $result->fields['sub_date'] : null;
$response['success'] = true;
$response['data'] = [
'is_subscribed' => $isSubscribed,
'subscribed_since' => $subDate
];
echo json_encode($response);
}
/**
* Subscribe to a channel
*/
function handleSubscribe($userId) {
global $class_database, $response;
// Get JSON input or form data
$input = json_decode(file_get_contents('php://input'), true);
if (!$input) {
$input = $_POST;
}
$channelId = isset($input['channel_id']) ? (int)$input['channel_id'] : null;
if (!$channelId) {
throw new Exception('channel_id is required', 400);
}
if ($channelId == $userId) {
throw new Exception('Cannot subscribe to yourself', 400);
}
// Check if channel exists
$channelCheckSql = "SELECT usr_user FROM db_users WHERE usr_id = ?";
$channelExists = $class_database->execute($channelCheckSql, [$channelId]);
if (!$channelExists || $channelExists->RecordCount() === 0) {
throw new Exception('Channel not found', 404);
}
// Check if already subscribed
$checkSql = "SELECT 1 FROM db_subscriptions WHERE usr_id = ? AND channel_id = ?";
$existing = $class_database->execute($checkSql, [$userId, $channelId]);
if ($existing && $existing->RecordCount() > 0) {
throw new Exception('Already subscribed to this channel', 400);
}
// Add subscription
$sql = "INSERT INTO db_subscriptions (usr_id, channel_id, sub_date) VALUES (?, ?, NOW())";
$result = $class_database->execute($sql, [$userId, $channelId]);
if (!$result) {
throw new Exception('Failed to subscribe', 500);
}
// Create notification for channel owner
$notifSql = "INSERT INTO db_notifications (usr_id, notif_type, notif_from, notif_date)
VALUES (?, 'subscription', ?, NOW())";
$class_database->execute($notifSql, [$channelId, $userId]);
// Get updated subscriber count
$countSql = "SELECT COUNT(*) as count FROM db_subscriptions WHERE channel_id = ?";
$countResult = $class_database->execute($countSql, [$channelId]);
$subscriberCount = $countResult->fields['count'];
// Log the subscription
VLogger::log('info', 'User subscribed to channel', [
'user_id' => $userId,
'channel_id' => $channelId
]);
$response['success'] = true;
$response['data'] = [
'message' => 'Subscribed successfully',
'channel_name' => $channelExists->fields['usr_user'],
'subscriber_count' => $subscriberCount
];
echo json_encode($response);
}
/**
* Unsubscribe from a channel
*/
function handleUnsubscribe($userId) {
global $class_database, $response;
// Get channel ID from query string or JSON body
$channelId = isset($_GET['channel_id']) ? (int)$_GET['channel_id'] : null;
if (!$channelId) {
$input = json_decode(file_get_contents('php://input'), true);
if (!$input) {
$input = $_POST;
}
$channelId = isset($input['channel_id']) ? (int)$input['channel_id'] : null;
}
if (!$channelId) {
throw new Exception('channel_id is required', 400);
}
// Check if subscribed
$checkSql = "SELECT 1 FROM db_subscriptions WHERE usr_id = ? AND channel_id = ?";
$existing = $class_database->execute($checkSql, [$userId, $channelId]);
if (!$existing || $existing->RecordCount() === 0) {
throw new Exception('Not subscribed to this channel', 400);
}
// Remove subscription
$sql = "DELETE FROM db_subscriptions WHERE usr_id = ? AND channel_id = ?";
$result = $class_database->execute($sql, [$userId, $channelId]);
if (!$result) {
throw new Exception('Failed to unsubscribe', 500);
}
// Get updated subscriber count
$countSql = "SELECT COUNT(*) as count FROM db_subscriptions WHERE channel_id = ?";
$countResult = $class_database->execute($countSql, [$channelId]);
$subscriberCount = $countResult->fields['count'];
// Log the unsubscription
VLogger::log('info', 'User unsubscribed from channel', [
'user_id' => $userId,
'channel_id' => $channelId
]);
$response['success'] = true;
$response['data'] = [
'message' => 'Unsubscribed successfully',
'subscriber_count' => $subscriberCount
];
echo json_encode($response);
}