Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
Clubphp
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Clubphp
Commits
085a50cb
Commit
085a50cb
authored
Apr 11, 2026
by
Mahmoud Aglan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fixed
parent
6f356f13
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
60 additions
and
57 deletions
+60
-57
Dockerfile
Dockerfile
+2
-4
show.php
app/Modules/Academies/Views/show.php
+2
-2
show.php
app/Modules/Facilities/Views/show.php
+6
-6
BrandingController.php
app/Modules/Settings/Controllers/BrandingController.php
+9
-27
SystemConfig.php
app/Modules/Settings/Models/SystemConfig.php
+14
-0
BrandingService.php
app/Modules/Settings/Services/BrandingService.php
+9
-16
Phase_24_002_alter_system_config_value_to_mediumtext.php
.../Phase_24_002_alter_system_config_value_to_mediumtext.php
+7
-0
Phase_16_001_seed_branding_config.php
database/seeds/Phase_16_001_seed_branding_config.php
+11
-2
No files found.
Dockerfile
View file @
085a50cb
...
@@ -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
...
...
app/Modules/Academies/Views/show.php
View file @
085a50cb
...
@@ -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;"
>
...
...
app/Modules/Facilities/Views/show.php
View file @
085a50cb
...
@@ -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
(
$
d
iscipline
)
:
?>
<?php
if
(
$
linkedD
iscipline
)
:
?>
<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>
...
...
app/Modules/Settings/Controllers/BrandingController.php
View file @
085a50cb
...
@@ -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'
,
''
);
}
}
...
...
app/Modules/Settings/Models/SystemConfig.php
View file @
085a50cb
...
@@ -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'
),
]);
}
}
}
}
...
...
app/Modules/Settings/Services/BrandingService.php
View file @
085a50cb
...
@@ -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
;
}
}
...
...
database/migrations/Phase_24_002_alter_system_config_value_to_mediumtext.php
0 → 100644
View file @
085a50cb
<?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"
,
];
database/seeds/Phase_16_001_seed_branding_config.php
View file @
085a50cb
...
@@ -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
,
],
],
[
[
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment