Sync current dev state
This commit is contained in:
368
api/subscriptions.php
Normal file
368
api/subscriptions.php
Normal file
@@ -0,0 +1,368 @@
|
||||
<?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);
|
||||
}
|
||||
Reference in New Issue
Block a user