feat: Add comprehensive documentation suite and reorganize project structure
- Created complete documentation in docs/ directory - Added PROJECT_OVERVIEW.md with feature highlights and getting started guide - Added ARCHITECTURE.md with system design and technical details - Added SECURITY.md with comprehensive security implementation guide - Added DEVELOPMENT.md with development workflows and best practices - Added DEPLOYMENT.md with production deployment instructions - Added API.md with complete REST API documentation - Added CONTRIBUTING.md with contribution guidelines - Added CHANGELOG.md with version history and migration notes - Reorganized all documentation files into docs/ directory for better organization - Updated README.md with proper documentation links and quick navigation - Enhanced project structure with professional documentation standards
This commit is contained in:
94
f_core/f_classes/class.membership.php
Normal file
94
f_core/f_classes/class.membership.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/*******************************************************************************************************************
|
||||
| Software Name : EasyStream
|
||||
| Software Description : High End YouTube Clone Script with Videos, Shorts, Streams, Images, Audio, Documents, Blogs
|
||||
| Software Author : (c) Sami Ahmed
|
||||
|*******************************************************************************************************************
|
||||
|
|
||||
|*******************************************************************************************************************
|
||||
| This source file is subject to the EasyStream Proprietary License Agreement.
|
||||
|
|
||||
| By using this software, you acknowledge having read this Agreement and agree to be bound thereby.
|
||||
|*******************************************************************************************************************
|
||||
| Copyright (c) 2025 Sami Ahmed. All rights reserved.
|
||||
|*******************************************************************************************************************/
|
||||
|
||||
defined('_ISVALID') or header('Location: /error');
|
||||
|
||||
class VMembership
|
||||
{
|
||||
public static function getRequiredTierForFile($type, $file_key)
|
||||
{
|
||||
global $db;
|
||||
// optional access rule table; if not present or cfg disabled, return null (no gating)
|
||||
if (!self::enabled()) return null;
|
||||
try {
|
||||
$t = $db->execute(sprintf("SELECT `required_tier_id` FROM `db_file_access_rules` WHERE `file_key`='%s' LIMIT 1;", htmlspecialchars($file_key, ENT_QUOTES, 'UTF-8')));
|
||||
$tier = (int) $t->fields['required_tier_id'];
|
||||
return $tier > 0 ? $tier : null;
|
||||
} catch (Exception $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static function hasAccess($viewerId, $channelId, $requiredTierId = null)
|
||||
{
|
||||
// no gating
|
||||
if (!self::enabled() || !$requiredTierId) return true;
|
||||
global $db;
|
||||
$viewerId = (int) $viewerId;
|
||||
$channelId = (int) $channelId;
|
||||
if ($viewerId <= 0) return false; // must sign in for member-only
|
||||
try {
|
||||
$q = $db->execute(sprintf("SELECT `tier_id`, `status`, `expires_at` FROM `db_user_memberships` WHERE `subscriber_usr_id`='%s' AND `channel_usr_id`='%s' AND `status`='active' ORDER BY `expires_at` DESC LIMIT 1;", $viewerId, $channelId));
|
||||
if (!$q->fields['tier_id']) return false;
|
||||
// allow if user tier >= required tier in simple numeric order, or exact match
|
||||
$userTier = (int) $q->fields['tier_id'];
|
||||
$exp = $q->fields['expires_at'];
|
||||
if ($exp && strtotime($exp) < time()) return false;
|
||||
return $userTier >= (int) $requiredTierId;
|
||||
} catch (Exception $e) {
|
||||
return true; // fail-open if table is missing
|
||||
}
|
||||
}
|
||||
|
||||
public static function badgeFor($viewerId, $channelId)
|
||||
{
|
||||
global $db;
|
||||
if (!self::badgesEnabled()) return '';
|
||||
try {
|
||||
$q = $db->execute(sprintf("SELECT `tier_id` FROM `db_user_memberships` WHERE `subscriber_usr_id`='%s' AND `channel_usr_id`='%s' AND `status`='active' ORDER BY `expires_at` DESC LIMIT 1;", (int) $viewerId, (int) $channelId));
|
||||
if ($q->fields['tier_id']) {
|
||||
$tier = (int) $q->fields['tier_id'];
|
||||
// simple star badge with tier number; matches existing icon classes
|
||||
return '<span class="mem-badge" title="Member Tier ' . $tier . '"><i class="icon-star"></i><span class="mem-tier">' . $tier . '</span></span>';
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
public static function issueChatToken($viewerId, $channelId)
|
||||
{
|
||||
global $cfg;
|
||||
// Very lightweight signed token for chat membership gating; 5 minute TTL
|
||||
$ttl = 300;
|
||||
$ts = time();
|
||||
$sig = md5($viewerId . '|' . $channelId . '|' . $ts . '|' . $cfg['live_chat_salt']);
|
||||
return base64_encode($viewerId . ':' . $channelId . ':' . $ts . ':' . $ttl . ':' . $sig);
|
||||
}
|
||||
|
||||
public static function enabled()
|
||||
{
|
||||
global $cfg; return (int) $cfg['channel_memberships'] === 1;
|
||||
}
|
||||
public static function chatMembersOnly()
|
||||
{
|
||||
global $cfg; return (int) $cfg['member_chat_only'] === 1;
|
||||
}
|
||||
public static function badgesEnabled()
|
||||
{
|
||||
global $cfg; return (int) $cfg['member_badges'] === 1;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user