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:
SamiAhmed7777
2025-10-21 00:39:45 -07:00
commit 0b7e2d0a5b
6080 changed files with 1332936 additions and 0 deletions

View File

@@ -0,0 +1,370 @@
<?php
/*******************************************************************************************************************
| EasyStream Token System Class
| Handles customizable platform tokens for monetization
|*******************************************************************************************************************/
defined('_ISVALID') or header('Location: /error');
class VToken {
private static $settings = null;
private static $db;
private static $cfg;
public function __construct() {
global $class_database, $cfg;
self::$db = $class_database;
self::$cfg = $cfg;
}
/**
* Get token settings from database
*/
public static function getSettings() {
if (self::$settings !== null) {
return self::$settings;
}
global $class_database;
// Default settings
$defaults = [
'name' => 'EasyCoins',
'symbol' => 'EC',
'plural' => 'EasyCoins',
'description' => 'Platform currency for tips and donations',
'icon' => '/f_templates/tpl_frontend/img/default-token.png',
'color_primary' => '#FFD700',
'color_secondary' => '#FFA500',
'exchange_rate' => 1.00,
'min_purchase' => 1.00,
'max_purchase' => 1000.00,
'enabled' => true
];
try {
$sql = "SELECT setting_key, setting_value FROM db_settings WHERE setting_key LIKE 'token_%'";
$result = $class_database->execute($sql);
$settings = $defaults;
while (!$result->EOF) {
$key = str_replace('token_', '', $result->fields['setting_key']);
$value = $result->fields['setting_value'];
// Convert numeric values
if (in_array($key, ['exchange_rate', 'min_purchase', 'max_purchase'])) {
$value = floatval($value);
} elseif ($key === 'enabled') {
$value = $value === '1';
}
$settings[$key] = $value;
$result->MoveNext();
}
self::$settings = $settings;
return $settings;
} catch (Exception $e) {
self::$settings = $defaults;
return $defaults;
}
}
/**
* Get token display HTML
*/
public static function getTokenDisplay($amount, $size = 'normal', $show_icon = true) {
$settings = self::getSettings();
if (!$settings['enabled']) {
return '$' . number_format($amount, 2);
}
$sizes = [
'small' => ['icon' => '16px', 'font' => '0.875rem'],
'normal' => ['icon' => '20px', 'font' => '1rem'],
'large' => ['icon' => '24px', 'font' => '1.25rem'],
'xlarge' => ['icon' => '32px', 'font' => '1.5rem']
];
$size_config = $sizes[$size] ?? $sizes['normal'];
$icon_html = '';
if ($show_icon) {
$icon_html = sprintf(
'<img src="%s" alt="%s" style="width: %s; height: %s; margin-right: 4px; vertical-align: middle; border-radius: 50%%;">',
htmlspecialchars($settings['icon']),
htmlspecialchars($settings['symbol']),
$size_config['icon'],
$size_config['icon']
);
}
$token_name = $amount == 1 ? $settings['name'] : $settings['plural'];
return sprintf(
'<span class="token-display" style="color: %s; font-size: %s; font-weight: 500; display: inline-flex; align-items: center;">%s%s %s</span>',
$settings['color_primary'],
$size_config['font'],
$icon_html,
number_format($amount, 0),
htmlspecialchars($token_name)
);
}
/**
* Get token symbol only
*/
public static function getSymbol() {
$settings = self::getSettings();
return $settings['symbol'];
}
/**
* Get token name
*/
public static function getName($plural = false) {
$settings = self::getSettings();
return $plural ? $settings['plural'] : $settings['name'];
}
/**
* Get token icon HTML
*/
public static function getIcon($size = '20px') {
$settings = self::getSettings();
return sprintf(
'<img src="%s" alt="%s" style="width: %s; height: %s; border-radius: 50%%; object-fit: cover;">',
htmlspecialchars($settings['icon']),
htmlspecialchars($settings['symbol']),
$size,
$size
);
}
/**
* Convert USD to tokens
*/
public static function usdToTokens($usd_amount) {
$settings = self::getSettings();
return round($usd_amount / $settings['exchange_rate']);
}
/**
* Convert tokens to USD
*/
public static function tokensToUsd($token_amount) {
$settings = self::getSettings();
return $token_amount * $settings['exchange_rate'];
}
/**
* Get purchase limits
*/
public static function getPurchaseLimits() {
$settings = self::getSettings();
return [
'min' => $settings['min_purchase'],
'max' => $settings['max_purchase'],
'min_tokens' => self::usdToTokens($settings['min_purchase']),
'max_tokens' => self::usdToTokens($settings['max_purchase'])
];
}
/**
* Validate token amount
*/
public static function validateAmount($amount, $type = 'usd') {
$limits = self::getPurchaseLimits();
if ($type === 'tokens') {
$min = $limits['min_tokens'];
$max = $limits['max_tokens'];
} else {
$min = $limits['min'];
$max = $limits['max'];
}
if ($amount < $min) {
return ['valid' => false, 'message' => "Minimum amount is $min"];
}
if ($amount > $max) {
return ['valid' => false, 'message' => "Maximum amount is $max"];
}
return ['valid' => true];
}
/**
* Get token CSS for styling
*/
public static function getTokenCSS() {
$settings = self::getSettings();
return sprintf('
<style>
:root {
--token-primary: %s;
--token-secondary: %s;
}
.token-display {
color: var(--token-primary);
font-weight: 500;
}
.token-button {
background: linear-gradient(135deg, var(--token-primary), var(--token-secondary));
color: white;
border: none;
padding: 8px 16px;
border-radius: 20px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
.token-button:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
}
.token-badge {
background: var(--token-primary);
color: white;
padding: 4px 8px;
border-radius: 12px;
font-size: 0.75rem;
font-weight: 600;
}
</style>
', $settings['color_primary'], $settings['color_secondary']);
}
/**
* Get donation button HTML
*/
public static function getDonationButton($streamer_id, $suggested_amount = null) {
$settings = self::getSettings();
if (!$settings['enabled']) {
return '';
}
$suggested_tokens = $suggested_amount ? self::usdToTokens($suggested_amount) : 10;
return sprintf('
<button class="token-button" onclick="openTokenDonation(%d, %d)">
%s Donate %s %s
</button>
',
$streamer_id,
$suggested_tokens,
self::getIcon('16px'),
number_format($suggested_tokens),
$settings['name']
);
}
/**
* Get token purchase form HTML
*/
public static function getPurchaseForm($user_id) {
$settings = self::getSettings();
$limits = self::getPurchaseLimits();
if (!$settings['enabled']) {
return '<p>Token system is currently disabled.</p>';
}
ob_start();
?>
<div class="token-purchase-form">
<div class="token-header">
<h3><?php echo self::getIcon('32px'); ?> Purchase <?php echo htmlspecialchars($settings['plural']); ?></h3>
<p><?php echo htmlspecialchars($settings['description']); ?></p>
</div>
<div class="purchase-options">
<div class="amount-selector">
<label>Amount (USD)</label>
<input type="number" id="usd-amount" min="<?php echo $limits['min']; ?>" max="<?php echo $limits['max']; ?>" step="0.01" value="10.00">
</div>
<div class="token-preview">
<span>You will receive:</span>
<div class="token-amount" id="token-amount">
<?php echo self::getTokenDisplay(self::usdToTokens(10), 'large'); ?>
</div>
</div>
<button class="token-button" onclick="processPurchase()">
💳 Purchase <?php echo htmlspecialchars($settings['plural']); ?>
</button>
</div>
</div>
<script>
document.getElementById('usd-amount').addEventListener('input', function() {
const usdAmount = parseFloat(this.value) || 0;
const tokenAmount = Math.round(usdAmount / <?php echo $settings['exchange_rate']; ?>);
document.getElementById('token-amount').innerHTML = '<?php echo self::getIcon('24px'); ?>' + tokenAmount + ' <?php echo htmlspecialchars($settings['plural']); ?>';
});
function processPurchase() {
const amount = document.getElementById('usd-amount').value;
window.location.href = '/donations/process?amount=' + amount + '&user_id=<?php echo $user_id; ?>';
}
</script>
<?php
return ob_get_clean();
}
/**
* Record token transaction
*/
public static function recordTransaction($user_id, $amount, $type, $description = '') {
global $class_database;
try {
$sql = "INSERT INTO token_transactions (user_id, amount, transaction_type, description, created_at)
VALUES (?, ?, ?, ?, NOW())";
$class_database->execute($sql, [$user_id, $amount, $type, $description]);
// Update user balance
$balance_sql = "UPDATE db_accountuser SET token_balance = COALESCE(token_balance, 0) + ? WHERE usr_id = ?";
$class_database->execute($balance_sql, [$amount, $user_id]);
return true;
} catch (Exception $e) {
return false;
}
}
/**
* Get user token balance
*/
public static function getUserBalance($user_id) {
global $class_database;
try {
$sql = "SELECT COALESCE(token_balance, 0) as balance FROM db_accountuser WHERE usr_id = ?";
$result = $class_database->execute($sql, [$user_id]);
return $result->fields['balance'] ?? 0;
} catch (Exception $e) {
return 0;
}
}
/**
* Check if user can afford amount
*/
public static function canAfford($user_id, $amount) {
$balance = self::getUserBalance($user_id);
return $balance >= $amount;
}
}
?>