Commit 085a50cb authored by Mahmoud Aglan's avatar Mahmoud Aglan

fixed

parent 6f356f13
...@@ -45,15 +45,13 @@ RUN mkdir -p \ ...@@ -45,15 +45,13 @@ RUN mkdir -p \
/var/www/html/storage/uploads/photos \ /var/www/html/storage/uploads/photos \
/var/www/html/storage/uploads/forms \ /var/www/html/storage/uploads/forms \
/var/www/html/storage/cache \ /var/www/html/storage/cache \
/var/www/html/storage/sessions \ /var/www/html/storage/sessions
/var/www/html/public/assets/uploads/branding
# ── Permissions ── # ── Permissions ──
RUN chown -R www-data:www-data /var/www/html/storage \ RUN chown -R www-data:www-data /var/www/html/storage \
&& chmod -R 775 /var/www/html/storage \ && chmod -R 775 /var/www/html/storage \
&& chown -R www-data:www-data /var/www/html/public \ && chown -R www-data:www-data /var/www/html/public \
&& chmod -R 755 /var/www/html/public \ && chmod -R 755 /var/www/html/public
&& chmod -R 775 /var/www/html/public/assets/uploads
# ── Environment defaults (overridden by CapRover env vars) ── # ── Environment defaults (overridden by CapRover env vars) ──
ENV APP_URL=http://localhost ENV APP_URL=http://localhost
......
...@@ -47,9 +47,9 @@ $dayLabels = AcademySchedule::getDayLabels(); ...@@ -47,9 +47,9 @@ $dayLabels = AcademySchedule::getDayLabels();
<code style="font-size:11px;background:#F3F4F6;padding:1px 6px;border-radius:4px;"><?= e($academy->code) ?></code> <code style="font-size:11px;background:#F3F4F6;padding:1px 6px;border-radius:4px;"><?= e($academy->code) ?></code>
</span> </span>
<?php if (!empty($discipline)): ?> <?php if (!empty($discipline)): ?>
<a href="/disciplines/<?= (int) $discipline['id'] ?>" style="display:inline-flex;align-items:center;gap:4px;color:#0D7377;text-decoration:none;"> <a href="/disciplines/<?= (int) $discipline->id ?>" style="display:inline-flex;align-items:center;gap:4px;color:#0D7377;text-decoration:none;">
<i data-lucide="activity" style="width:14px;height:14px;"></i> <i data-lucide="activity" style="width:14px;height:14px;"></i>
<?= e($discipline['name_ar'] ?? '') ?> <?= e($discipline->name_ar ?? '') ?>
</a> </a>
<?php endif; ?> <?php endif; ?>
<span style="display:inline-flex;align-items:center;gap:4px;"> <span style="display:inline-flex;align-items:center;gap:4px;">
......
...@@ -169,18 +169,18 @@ $slotTypeColors = [ ...@@ -169,18 +169,18 @@ $slotTypeColors = [
<h3 style="margin:0;color:#0D7377;font-size:15px;">النشاط المرتبط</h3> <h3 style="margin:0;color:#0D7377;font-size:15px;">النشاط المرتبط</h3>
</div> </div>
<div style="padding:20px;"> <div style="padding:20px;">
<?php if ($discipline): ?> <?php if ($linkedDiscipline): ?>
<div style="display:flex;align-items:center;gap:15px;"> <div style="display:flex;align-items:center;gap:15px;">
<div style="width:48px;height:48px;border-radius:12px;background:linear-gradient(135deg, #0D737715, #0D737730);display:flex;align-items:center;justify-content:center;flex-shrink:0;"> <div style="width:48px;height:48px;border-radius:12px;background:linear-gradient(135deg, #0D737715, #0D737730);display:flex;align-items:center;justify-content:center;flex-shrink:0;">
<i data-lucide="<?= e($discipline['icon'] ?? 'activity') ?>" style="width:24px;height:24px;color:#0D7377;"></i> <i data-lucide="<?= e($linkedDiscipline->icon ?? 'activity') ?>" style="width:24px;height:24px;color:#0D7377;"></i>
</div> </div>
<div style="flex:1;"> <div style="flex:1;">
<div style="font-size:16px;font-weight:700;color:#1A1A2E;margin-bottom:4px;"><?= e($discipline['name_ar'] ?? '') ?></div> <div style="font-size:16px;font-weight:700;color:#1A1A2E;margin-bottom:4px;"><?= e($linkedDiscipline->name_ar ?? '') ?></div>
<?php if (!empty($discipline['category'])): ?> <?php if (!empty($linkedDiscipline->category)): ?>
<span style="display:inline-block;padding:2px 10px;border-radius:10px;font-size:11px;font-weight:600;background:#F3F4F6;color:#6B7280;"><?= e($discipline['category']) ?></span> <span style="display:inline-block;padding:2px 10px;border-radius:10px;font-size:11px;font-weight:600;background:#F3F4F6;color:#6B7280;"><?= e($linkedDiscipline->category) ?></span>
<?php endif; ?> <?php endif; ?>
</div> </div>
<a href="/disciplines/<?= (int) $discipline['id'] ?>" class="btn btn-sm btn-outline" style="font-size:12px;"> <a href="/disciplines/<?= (int) $linkedDiscipline->id ?>" class="btn btn-sm btn-outline" style="font-size:12px;">
<i data-lucide="eye" style="width:13px;height:13px;vertical-align:middle;margin-left:4px;"></i> عرض النشاط <i data-lucide="eye" style="width:13px;height:13px;vertical-align:middle;margin-left:4px;"></i> عرض النشاط
</a> </a>
</div> </div>
......
...@@ -39,7 +39,7 @@ class BrandingController extends Controller ...@@ -39,7 +39,7 @@ class BrandingController extends Controller
} }
SystemConfig::set('branding.club_subtitle', $subtitle); SystemConfig::set('branding.club_subtitle', $subtitle);
// Handle logo upload // Handle logo upload — stored as base64 data URI in DB (survives Docker rebuilds)
if ($request->hasFile('logo_file')) { if ($request->hasFile('logo_file')) {
$file = $request->file('logo_file'); $file = $request->file('logo_file');
if ($file && $file['error'] === UPLOAD_ERR_OK) { if ($file && $file['error'] === UPLOAD_ERR_OK) {
...@@ -56,40 +56,22 @@ class BrandingController extends Controller ...@@ -56,40 +56,22 @@ class BrandingController extends Controller
return $this->redirect('/settings/branding')->withError('نوع الملف غير مسموح (PNG, JPG, SVG, WebP فقط)'); return $this->redirect('/settings/branding')->withError('نوع الملف غير مسموح (PNG, JPG, SVG, WebP فقط)');
} }
// Generate filename // Read file and encode as base64 data URI
$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)); $fileData = file_get_contents($file['tmp_name']);
if ($ext === 'svg') $ext = 'svg'; if ($fileData === false) {
$storedFilename = 'logo_' . date('Ymd_His') . '_' . bin2hex(random_bytes(4)) . '.' . $ext; return $this->redirect('/settings/branding')->withError('فشل في قراءة الملف');
// Ensure upload directory exists (inside public/ so Apache serves it directly)
$uploadDir = App::getInstance()->publicPath() . '/assets/uploads/branding/';
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
$filePath = $uploadDir . $storedFilename;
if (!move_uploaded_file($file['tmp_name'], $filePath)) {
return $this->redirect('/settings/branding')->withError('فشل في حفظ الشعار');
} }
// Delete old logo file if exists $dataUri = 'data:' . $mimeType . ';base64,' . base64_encode($fileData);
$oldPath = BrandingService::logoFilePath(); SystemConfig::set('branding.logo_data', $dataUri);
if ($oldPath && file_exists($oldPath)) { SystemConfig::set('branding.logo_path', '');
@unlink($oldPath);
}
// Save path to config (relative to public/)
SystemConfig::set('branding.logo_path', 'assets/uploads/branding/' . $storedFilename);
BrandingService::clearCache(); BrandingService::clearCache();
} }
} }
// Handle logo removal // Handle logo removal
if ($request->post('remove_logo') === '1') { if ($request->post('remove_logo') === '1') {
$oldPath = BrandingService::logoFilePath(); SystemConfig::set('branding.logo_data', '');
if ($oldPath && file_exists($oldPath)) {
@unlink($oldPath);
}
SystemConfig::set('branding.logo_path', ''); SystemConfig::set('branding.logo_path', '');
} }
......
...@@ -39,6 +39,20 @@ class SystemConfig ...@@ -39,6 +39,20 @@ class SystemConfig
'config_value' => $value, 'config_value' => $value,
'updated_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s'),
], '`id` = ?', [$existing['id']]); ], '`id` = ?', [$existing['id']]);
} else {
$group = 'general';
if (str_contains($key, '.')) {
$group = explode('.', $key, 2)[0];
}
$db->insert('system_config', [
'config_key' => $key,
'config_value' => $value,
'config_type' => 'string',
'group_name' => $group,
'is_editable' => 1,
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
]);
} }
} }
......
...@@ -53,32 +53,25 @@ class BrandingService ...@@ -53,32 +53,25 @@ class BrandingService
} }
/** /**
* Get URL path to the logo image, or null if not set. * Get logo as data URI string (base64), or null if not set.
*/ */
public static function logo(): ?string public static function logo(): ?string
{ {
$data = self::load(); $data = self::load();
// Prefer base64 data URI stored in DB (survives Docker rebuilds)
$dataUri = $data['logo_data'] ?? null;
if ($dataUri && $dataUri !== '') {
return $dataUri;
}
// Fallback: legacy file path (for backward compatibility)
$path = $data['logo_path'] ?? null; $path = $data['logo_path'] ?? null;
if ($path && $path !== '') { if ($path && $path !== '') {
// Path is relative to public/ (e.g. "assets/uploads/branding/logo_xxx.png")
$basePath = rtrim(parse_url(config('app.url', ''), PHP_URL_PATH) ?: '', '/'); $basePath = rtrim(parse_url(config('app.url', ''), PHP_URL_PATH) ?: '', '/');
return $basePath . '/' . ltrim($path, '/'); return $basePath . '/' . ltrim($path, '/');
} }
return null;
}
/**
* Get the absolute file path to the logo, or null.
*/
public static function logoFilePath(): ?string
{
$data = self::load();
$path = $data['logo_path'] ?? null;
if ($path && $path !== '') {
// Logo lives inside public/ directory
$full = App::getInstance()->publicPath() . '/' . ltrim($path, '/');
return file_exists($full) ? $full : null;
}
return null; return null;
} }
......
<?php
declare(strict_types=1);
return [
'up' => "ALTER TABLE `system_config` MODIFY COLUMN `config_value` MEDIUMTEXT NULL",
'down' => "ALTER TABLE `system_config` MODIFY COLUMN `config_value` TEXT NULL",
];
...@@ -10,8 +10,17 @@ return function (Database $db): void { ...@@ -10,8 +10,17 @@ return function (Database $db): void {
'config_value' => '', 'config_value' => '',
'config_type' => 'string', 'config_type' => 'string',
'group_name' => 'branding', 'group_name' => 'branding',
'description_ar' => 'مسار شعار النادي', 'description_ar' => 'مسار شعار النادي (قديم)',
'description_en' => 'Club logo file path', 'description_en' => 'Club logo file path (legacy)',
'is_editable' => 1,
],
[
'config_key' => 'branding.logo_data',
'config_value' => '',
'config_type' => 'string',
'group_name' => 'branding',
'description_ar' => 'بيانات شعار النادي (base64)',
'description_en' => 'Club logo data URI (base64)',
'is_editable' => 1, 'is_editable' => 1,
], ],
[ [
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment