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:
686
f_core/f_classes/class.privacy.php
Normal file
686
f_core/f_classes/class.privacy.php
Normal file
@@ -0,0 +1,686 @@
|
||||
<?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');
|
||||
|
||||
/**
|
||||
* VPrivacy - Comprehensive Privacy and Access Control System
|
||||
*
|
||||
* This class handles all aspects of privacy and access control:
|
||||
* - Site-wide access modes (public, members-only, invite-only)
|
||||
* - Content privacy levels
|
||||
* - User privacy preferences
|
||||
* - Geographic restrictions
|
||||
* - Age verification
|
||||
* - GDPR compliance
|
||||
* - Access logging
|
||||
*/
|
||||
class VPrivacy
|
||||
{
|
||||
private static $instance = null;
|
||||
private $branding;
|
||||
private $currentUser = null;
|
||||
private $userPrivacyLevel = 'guest';
|
||||
|
||||
public static function getInstance()
|
||||
{
|
||||
if (self::$instance === null) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
$this->branding = VBranding::getInstance();
|
||||
$this->initializeUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize current user and privacy level
|
||||
*/
|
||||
private function initializeUser()
|
||||
{
|
||||
if (isset($_SESSION['USER_ID']) && $_SESSION['USER_ID'] > 0) {
|
||||
$this->currentUser = $_SESSION['USER_ID'];
|
||||
$this->userPrivacyLevel = $this->getUserPrivacyLevel($_SESSION['USER_ID']);
|
||||
} else {
|
||||
$this->userPrivacyLevel = 'guest';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user's privacy level
|
||||
*/
|
||||
private function getUserPrivacyLevel($userId)
|
||||
{
|
||||
global $db;
|
||||
|
||||
try {
|
||||
// Check if user is admin
|
||||
$sql = "SELECT usr_status FROM db_accountuser WHERE usr_id = ?";
|
||||
$result = $db->Execute($sql, [$userId]);
|
||||
|
||||
if ($result && !$result->EOF) {
|
||||
$status = $result->fields['usr_status'];
|
||||
if ($status == 'admin' || $status == 'administrator') {
|
||||
return 'admin';
|
||||
}
|
||||
if ($status == 'premium') {
|
||||
return 'premium';
|
||||
}
|
||||
if ($status == 'verified') {
|
||||
return 'verified';
|
||||
}
|
||||
return 'member';
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$logger = VLogger::getInstance();
|
||||
$logger->logError('Failed to get user privacy level: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
return 'guest';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if site access is allowed
|
||||
*/
|
||||
public function checkSiteAccess()
|
||||
{
|
||||
$accessMode = $this->branding->get('site_access_mode', 'public');
|
||||
$maintenanceMode = $this->branding->get('maintenance_mode', false);
|
||||
|
||||
// Check maintenance mode first
|
||||
if ($maintenanceMode) {
|
||||
return $this->checkMaintenanceAccess();
|
||||
}
|
||||
|
||||
switch ($accessMode) {
|
||||
case 'public':
|
||||
return ['allowed' => true];
|
||||
|
||||
case 'members_only':
|
||||
if ($this->userPrivacyLevel === 'guest') {
|
||||
return [
|
||||
'allowed' => false,
|
||||
'reason' => 'members_only',
|
||||
'message' => $this->branding->get('members_only_message', 'This site is available to members only.')
|
||||
];
|
||||
}
|
||||
return ['allowed' => true];
|
||||
|
||||
case 'invite_only':
|
||||
if ($this->userPrivacyLevel === 'guest' || !$this->hasValidInvite()) {
|
||||
return [
|
||||
'allowed' => false,
|
||||
'reason' => 'invite_only',
|
||||
'message' => 'This site is invite-only. Please contact an administrator for access.'
|
||||
];
|
||||
}
|
||||
return ['allowed' => true];
|
||||
|
||||
default:
|
||||
return ['allowed' => true];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check maintenance mode access
|
||||
*/
|
||||
private function checkMaintenanceAccess()
|
||||
{
|
||||
// Allow admin access
|
||||
if ($this->userPrivacyLevel === 'admin') {
|
||||
return ['allowed' => true];
|
||||
}
|
||||
|
||||
// Check allowed IPs
|
||||
$allowedIPs = $this->branding->get('maintenance_allowed_ips', '');
|
||||
if (!empty($allowedIPs)) {
|
||||
$userIP = $_SERVER['REMOTE_ADDR'];
|
||||
$allowedList = array_map('trim', explode(',', $allowedIPs));
|
||||
if (in_array($userIP, $allowedList)) {
|
||||
return ['allowed' => true];
|
||||
}
|
||||
}
|
||||
|
||||
// Check bypass key
|
||||
$bypassKey = $this->branding->get('maintenance_bypass_key', '');
|
||||
if (!empty($bypassKey) && isset($_GET['bypass']) && $_GET['bypass'] === $bypassKey) {
|
||||
return ['allowed' => true];
|
||||
}
|
||||
|
||||
return [
|
||||
'allowed' => false,
|
||||
'reason' => 'maintenance',
|
||||
'message' => $this->branding->get('maintenance_message', 'Site is currently under maintenance.')
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check content access permissions
|
||||
*/
|
||||
public function checkContentAccess($contentType, $contentId, $contentData = null)
|
||||
{
|
||||
// Get content privacy settings
|
||||
$privacySettings = $this->getContentPrivacySettings($contentType, $contentId);
|
||||
|
||||
if (!$privacySettings) {
|
||||
// Use default privacy level
|
||||
$privacyLevel = $this->branding->get("default_{$contentType}_privacy", 'public');
|
||||
} else {
|
||||
$privacyLevel = $privacySettings['privacy_level'];
|
||||
}
|
||||
|
||||
// Check basic privacy level
|
||||
$accessCheck = $this->checkPrivacyLevel($privacyLevel);
|
||||
if (!$accessCheck['allowed']) {
|
||||
$this->logAccess($contentType, $contentId, false, $accessCheck['reason']);
|
||||
return $accessCheck;
|
||||
}
|
||||
|
||||
// Check additional restrictions
|
||||
if ($privacySettings) {
|
||||
// Password protection
|
||||
if ($privacySettings['password_protected']) {
|
||||
if (!$this->checkContentPassword($contentType, $contentId, $privacySettings['content_password'])) {
|
||||
return [
|
||||
'allowed' => false,
|
||||
'reason' => 'password_required',
|
||||
'message' => 'This content is password protected.'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Age restrictions
|
||||
if ($privacySettings['age_restricted']) {
|
||||
$ageCheck = $this->checkAgeRestriction();
|
||||
if (!$ageCheck['allowed']) {
|
||||
return $ageCheck;
|
||||
}
|
||||
}
|
||||
|
||||
// Geographic restrictions
|
||||
if ($privacySettings['geo_restricted']) {
|
||||
$geoCheck = $this->checkGeographicRestriction($privacySettings);
|
||||
if (!$geoCheck['allowed']) {
|
||||
return $geoCheck;
|
||||
}
|
||||
}
|
||||
|
||||
// Scheduled content
|
||||
if ($privacySettings['scheduled_public'] && strtotime($privacySettings['scheduled_public']) > time()) {
|
||||
if ($this->userPrivacyLevel !== 'admin') {
|
||||
return [
|
||||
'allowed' => false,
|
||||
'reason' => 'scheduled',
|
||||
'message' => 'This content is not yet available.'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Expired content
|
||||
if ($privacySettings['expires_at'] && strtotime($privacySettings['expires_at']) < time()) {
|
||||
return [
|
||||
'allowed' => false,
|
||||
'reason' => 'expired',
|
||||
'message' => 'This content is no longer available.'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$this->logAccess($contentType, $contentId, true);
|
||||
return ['allowed' => true];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check privacy level access
|
||||
*/
|
||||
private function checkPrivacyLevel($privacyLevel)
|
||||
{
|
||||
switch ($privacyLevel) {
|
||||
case 'public':
|
||||
return ['allowed' => true];
|
||||
|
||||
case 'members_only':
|
||||
if ($this->userPrivacyLevel === 'guest') {
|
||||
return [
|
||||
'allowed' => false,
|
||||
'reason' => 'login_required',
|
||||
'message' => $this->branding->get('login_required_message', 'Please log in to view this content.')
|
||||
];
|
||||
}
|
||||
return ['allowed' => true];
|
||||
|
||||
case 'verified_only':
|
||||
if (!in_array($this->userPrivacyLevel, ['verified', 'premium', 'admin'])) {
|
||||
return [
|
||||
'allowed' => false,
|
||||
'reason' => 'verification_required',
|
||||
'message' => 'This content is available to verified users only.'
|
||||
];
|
||||
}
|
||||
return ['allowed' => true];
|
||||
|
||||
case 'premium_only':
|
||||
if (!in_array($this->userPrivacyLevel, ['premium', 'admin'])) {
|
||||
return [
|
||||
'allowed' => false,
|
||||
'reason' => 'premium_required',
|
||||
'message' => 'This content is available to premium members only.'
|
||||
];
|
||||
}
|
||||
return ['allowed' => true];
|
||||
|
||||
case 'admin_only':
|
||||
if ($this->userPrivacyLevel !== 'admin') {
|
||||
return [
|
||||
'allowed' => false,
|
||||
'reason' => 'admin_required',
|
||||
'message' => 'This content is restricted to administrators.'
|
||||
];
|
||||
}
|
||||
return ['allowed' => true];
|
||||
|
||||
case 'private':
|
||||
return [
|
||||
'allowed' => false,
|
||||
'reason' => 'private',
|
||||
'message' => $this->branding->get('private_content_message', 'This content is private.')
|
||||
];
|
||||
|
||||
case 'unlisted':
|
||||
// Unlisted content can be viewed if you have the direct link
|
||||
return ['allowed' => true];
|
||||
|
||||
default:
|
||||
return ['allowed' => true];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get content privacy settings
|
||||
*/
|
||||
private function getContentPrivacySettings($contentType, $contentId)
|
||||
{
|
||||
global $db;
|
||||
|
||||
try {
|
||||
$sql = "SELECT * FROM db_content_privacy WHERE content_type = ? AND content_id = ?";
|
||||
$result = $db->Execute($sql, [$contentType, $contentId]);
|
||||
|
||||
if ($result && !$result->EOF) {
|
||||
return $result->fields;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$logger = VLogger::getInstance();
|
||||
$logger->logError('Failed to get content privacy settings: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check content password
|
||||
*/
|
||||
private function checkContentPassword($contentType, $contentId, $hashedPassword)
|
||||
{
|
||||
$sessionKey = "content_password_{$contentType}_{$contentId}";
|
||||
|
||||
// Check if password already verified in session
|
||||
if (isset($_SESSION[$sessionKey]) && $_SESSION[$sessionKey] === true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check submitted password
|
||||
if (isset($_POST['content_password'])) {
|
||||
$submittedPassword = $_POST['content_password'];
|
||||
if (password_verify($submittedPassword, $hashedPassword)) {
|
||||
$_SESSION[$sessionKey] = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check age restriction
|
||||
*/
|
||||
private function checkAgeRestriction()
|
||||
{
|
||||
if (!$this->branding->get('enable_age_verification', false)) {
|
||||
return ['allowed' => true];
|
||||
}
|
||||
|
||||
// Check if user has verified age
|
||||
if ($this->currentUser) {
|
||||
$ageVerified = $this->getUserPreference($this->currentUser, 'age_verified');
|
||||
if ($ageVerified) {
|
||||
return ['allowed' => true];
|
||||
}
|
||||
}
|
||||
|
||||
// Check session for age verification
|
||||
if (isset($_SESSION['age_verified']) && $_SESSION['age_verified'] === true) {
|
||||
return ['allowed' => true];
|
||||
}
|
||||
|
||||
return [
|
||||
'allowed' => false,
|
||||
'reason' => 'age_verification_required',
|
||||
'message' => $this->branding->get('age_restricted_message', 'This content is age-restricted.')
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check geographic restriction
|
||||
*/
|
||||
private function checkGeographicRestriction($privacySettings)
|
||||
{
|
||||
if (!$this->branding->get('enable_geo_blocking', false)) {
|
||||
return ['allowed' => true];
|
||||
}
|
||||
|
||||
$userCountry = $this->getUserCountry();
|
||||
|
||||
// Check blocked countries
|
||||
if (!empty($privacySettings['blocked_countries'])) {
|
||||
$blockedCountries = array_map('trim', explode(',', $privacySettings['blocked_countries']));
|
||||
if (in_array($userCountry, $blockedCountries)) {
|
||||
return [
|
||||
'allowed' => false,
|
||||
'reason' => 'geo_blocked',
|
||||
'message' => $this->branding->get('geo_block_message', 'This content is not available in your region.')
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Check allowed countries
|
||||
if (!empty($privacySettings['allowed_countries'])) {
|
||||
$allowedCountries = array_map('trim', explode(',', $privacySettings['allowed_countries']));
|
||||
if (!in_array($userCountry, $allowedCountries)) {
|
||||
return [
|
||||
'allowed' => false,
|
||||
'reason' => 'geo_blocked',
|
||||
'message' => $this->branding->get('geo_block_message', 'This content is not available in your region.')
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return ['allowed' => true];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user's country from IP
|
||||
*/
|
||||
private function getUserCountry()
|
||||
{
|
||||
// This is a simplified version - in production, you'd use a GeoIP service
|
||||
$ip = $_SERVER['REMOTE_ADDR'];
|
||||
|
||||
// For localhost/development
|
||||
if ($ip === '127.0.0.1' || $ip === '::1') {
|
||||
return 'US'; // Default for development
|
||||
}
|
||||
|
||||
// You would integrate with a GeoIP service here
|
||||
// For now, return a default
|
||||
return 'US';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set content privacy settings
|
||||
*/
|
||||
public function setContentPrivacy($contentType, $contentId, $settings)
|
||||
{
|
||||
global $db;
|
||||
|
||||
try {
|
||||
$sql = "INSERT INTO db_content_privacy
|
||||
(content_type, content_id, privacy_level, password_protected, content_password,
|
||||
age_restricted, geo_restricted, allowed_countries, blocked_countries,
|
||||
scheduled_public, expires_at, custom_message)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
privacy_level = VALUES(privacy_level),
|
||||
password_protected = VALUES(password_protected),
|
||||
content_password = VALUES(content_password),
|
||||
age_restricted = VALUES(age_restricted),
|
||||
geo_restricted = VALUES(geo_restricted),
|
||||
allowed_countries = VALUES(allowed_countries),
|
||||
blocked_countries = VALUES(blocked_countries),
|
||||
scheduled_public = VALUES(scheduled_public),
|
||||
expires_at = VALUES(expires_at),
|
||||
custom_message = VALUES(custom_message),
|
||||
updated_at = NOW()";
|
||||
|
||||
$password = null;
|
||||
if (!empty($settings['password'])) {
|
||||
$password = password_hash($settings['password'], PASSWORD_DEFAULT);
|
||||
}
|
||||
|
||||
return $db->Execute($sql, [
|
||||
$contentType,
|
||||
$contentId,
|
||||
$settings['privacy_level'] ?? 'public',
|
||||
$settings['password_protected'] ?? false,
|
||||
$password,
|
||||
$settings['age_restricted'] ?? false,
|
||||
$settings['geo_restricted'] ?? false,
|
||||
$settings['allowed_countries'] ?? '',
|
||||
$settings['blocked_countries'] ?? '',
|
||||
$settings['scheduled_public'] ?? null,
|
||||
$settings['expires_at'] ?? null,
|
||||
$settings['custom_message'] ?? ''
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
$logger = VLogger::getInstance();
|
||||
$logger->logError('Failed to set content privacy: ' . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user privacy preference
|
||||
*/
|
||||
public function getUserPreference($userId, $key)
|
||||
{
|
||||
global $db;
|
||||
|
||||
try {
|
||||
$sql = "SELECT preference_value FROM db_user_privacy_preferences WHERE usr_id = ? AND preference_key = ?";
|
||||
$result = $db->Execute($sql, [$userId, $key]);
|
||||
|
||||
if ($result && !$result->EOF) {
|
||||
return $result->fields['preference_value'];
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$logger = VLogger::getInstance();
|
||||
$logger->logError('Failed to get user preference: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set user privacy preference
|
||||
*/
|
||||
public function setUserPreference($userId, $key, $value)
|
||||
{
|
||||
global $db;
|
||||
|
||||
try {
|
||||
$sql = "INSERT INTO db_user_privacy_preferences (usr_id, preference_key, preference_value)
|
||||
VALUES (?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE preference_value = VALUES(preference_value), updated_at = NOW()";
|
||||
|
||||
return $db->Execute($sql, [$userId, $key, $value]);
|
||||
} catch (Exception $e) {
|
||||
$logger = VLogger::getInstance();
|
||||
$logger->logError('Failed to set user preference: ' . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log access attempt
|
||||
*/
|
||||
private function logAccess($contentType, $contentId, $granted, $reason = null)
|
||||
{
|
||||
global $db;
|
||||
|
||||
try {
|
||||
$sql = "INSERT INTO db_privacy_access_logs
|
||||
(usr_id, ip_address, user_agent, access_type, content_type, content_id,
|
||||
access_granted, denial_reason, privacy_level_required, user_privacy_level)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
|
||||
$db->Execute($sql, [
|
||||
$this->currentUser,
|
||||
$_SERVER['REMOTE_ADDR'],
|
||||
$_SERVER['HTTP_USER_AGENT'] ?? '',
|
||||
'view',
|
||||
$contentType,
|
||||
$contentId,
|
||||
$granted ? 1 : 0,
|
||||
$reason,
|
||||
'', // Would be filled based on content settings
|
||||
$this->userPrivacyLevel
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
// Fail silently for logging
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user has valid invite
|
||||
*/
|
||||
private function hasValidInvite()
|
||||
{
|
||||
// This would check for valid invite codes
|
||||
// Implementation depends on your invite system
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate privacy-aware content list
|
||||
*/
|
||||
public function filterContentList($contentList, $contentType = 'video')
|
||||
{
|
||||
$filteredList = [];
|
||||
|
||||
foreach ($contentList as $content) {
|
||||
$accessCheck = $this->checkContentAccess($contentType, $content['id'], $content);
|
||||
|
||||
if ($accessCheck['allowed']) {
|
||||
$filteredList[] = $content;
|
||||
} else {
|
||||
// Optionally include placeholder for restricted content
|
||||
if ($this->branding->get('show_content_previews', true)) {
|
||||
$content['restricted'] = true;
|
||||
$content['restriction_reason'] = $accessCheck['reason'];
|
||||
$content['restriction_message'] = $accessCheck['message'];
|
||||
$filteredList[] = $content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $filteredList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get privacy statistics for admin
|
||||
*/
|
||||
public function getPrivacyStatistics()
|
||||
{
|
||||
global $db;
|
||||
$stats = [];
|
||||
|
||||
try {
|
||||
// Access attempts in last 24 hours
|
||||
$sql = "SELECT COUNT(*) as total,
|
||||
SUM(access_granted) as granted,
|
||||
SUM(CASE WHEN access_granted = 0 THEN 1 ELSE 0 END) as denied
|
||||
FROM db_privacy_access_logs
|
||||
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR)";
|
||||
$result = $db->Execute($sql);
|
||||
|
||||
if ($result && !$result->EOF) {
|
||||
$stats['access_attempts_24h'] = [
|
||||
'total' => (int) $result->fields['total'],
|
||||
'granted' => (int) $result->fields['granted'],
|
||||
'denied' => (int) $result->fields['denied']
|
||||
];
|
||||
}
|
||||
|
||||
// Content privacy distribution
|
||||
$sql = "SELECT privacy_level, COUNT(*) as count
|
||||
FROM db_content_privacy
|
||||
GROUP BY privacy_level";
|
||||
$result = $db->Execute($sql);
|
||||
|
||||
$privacyDistribution = [];
|
||||
if ($result) {
|
||||
while (!$result->EOF) {
|
||||
$privacyDistribution[$result->fields['privacy_level']] = (int) $result->fields['count'];
|
||||
$result->MoveNext();
|
||||
}
|
||||
}
|
||||
$stats['privacy_distribution'] = $privacyDistribution;
|
||||
|
||||
} catch (Exception $e) {
|
||||
$logger = VLogger::getInstance();
|
||||
$logger->logError('Failed to get privacy statistics: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
return $stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current user's privacy level
|
||||
*/
|
||||
public function getCurrentUserPrivacyLevel()
|
||||
{
|
||||
return $this->userPrivacyLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if feature is accessible
|
||||
*/
|
||||
public function checkFeatureAccess($featureName)
|
||||
{
|
||||
$featureSettings = [
|
||||
'search' => $this->branding->get('search_requires_login', false),
|
||||
'trending' => $this->branding->get('trending_requires_login', false),
|
||||
'categories' => $this->branding->get('categories_require_login', false),
|
||||
'recommendations' => $this->branding->get('recommendations_require_login', true),
|
||||
'upload' => true, // Always requires login
|
||||
'comments' => true, // Always requires login
|
||||
];
|
||||
|
||||
$requiresLogin = $featureSettings[$featureName] ?? false;
|
||||
|
||||
if ($requiresLogin && $this->userPrivacyLevel === 'guest') {
|
||||
return [
|
||||
'allowed' => false,
|
||||
'reason' => 'login_required',
|
||||
'message' => $this->branding->get('login_required_message', 'Please log in to use this feature.')
|
||||
];
|
||||
}
|
||||
|
||||
return ['allowed' => true];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user