Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
184 changes: 37 additions & 147 deletions app/Http/Controllers/BackEnd/ThemesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,20 @@

use App\Http\Controllers\BackEndController;
use App\Models\Themes;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\File;
use App\Services\ThemeService;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Artisan;

class ThemesController extends BackEndController
{
protected ThemeService $themeService;

public function __construct(ThemeService $themeService)
{
$this->themeService = $themeService;
// In Laravel, if parent has no constructor this is fine, if it does,
// we might need parent::__construct(), but usually it's injected.
}

public function index()
{
$page_title = 'Tema';
Expand All @@ -22,25 +29,25 @@ public function index()

public function activate(Themes $themes)
{
Themes::where('active', 1)->update(['active' => 0]);
$themes->update(['active' => 1]);

// Clear all theme API cache
$this->clearThemeCache();
try {
$this->themeService->activate($themes);
} catch (\RuntimeException $e) {
Log::critical('Theme hooks rejected during activation', [
'theme' => $themes->name,
'reason' => $e->getMessage(),
]);

// Load theme hooks if exists
$this->loadThemeHooks($themes->name);
return redirect()->route('setting.themes.index')
->with('error', 'Tema diaktifkan tetapi hooks.php ditolak: ' . $e->getMessage());
}

return redirect()->route('setting.themes.index')
->with('success', 'Tema berhasil diaktifkan. Cache API telah dibersihkan.');
}

public function reScan()
{
scan_themes();

// Clear cache after rescan
$this->clearThemeCache();
$this->themeService->reScan();

return redirect()->route('setting.themes.index')
->with('success', 'Tema berhasil dipindai ulang');
Expand All @@ -50,81 +57,30 @@ public function upload()
{
try {
$file = request()->file('file');

// Use FileUploadService for secure file upload
$fileUploadService = new \App\Services\FileUploadService();

// Define allowed MIME types for zip files
$allowedMimes = \App\Services\FileUploadService::getAllowedMimes('archive');

// Validate file type
$fileMimeType = $file->getMimeType();
if (!in_array($fileMimeType, $allowedMimes)) {
if (!$file) {
return response()->json([
'status' => 'error',
'message' => 'File harus berformat .zip',
'message' => 'File tema tidak ditemukan',
]);
}

// Use FileUploadService for secure file upload
$fileUploadService = new \App\Services\FileUploadService();

// Define allowed MIME types for zip files
$allowedMimes = \App\Services\FileUploadService::getAllowedMimes('archive');

// Upload file securely to temp directory
$path = $fileUploadService->uploadSecure($file, 'framework/themes', $allowedMimes, 51200); // 50MB max
$result = $this->themeService->installFromZip($file);

// Extract filename from path
$fileName = basename($path);

// Get the full file path for further processing
$filePath = storage_path('framework/themes');

$zip = new \ZipArchive;
if ($zip->open("$filePath/$fileName") === true) {
$extractedPath = base_path('themes/extracted');
$zip->extractTo($extractedPath);
$zip->close();

$folderTheme = explode('.', $fileName)[0];
$composerPath = "$extractedPath/$folderTheme/composer.json";

if (file_exists($composerPath)) {
$composerData = json_decode(file_get_contents($composerPath), true);

// Validate theme structure
$this->validateThemeStructure($extractedPath, $folderTheme);

$newFolder = base_path('themes/' . $composerData['name']);

if (File::move("$extractedPath/$folderTheme", $newFolder)) {
File::deleteDirectory($extractedPath);
File::deleteDirectory($filePath);
return response()->json($result);

scan_themes();

// Load theme hooks
$this->loadThemeHooks($composerData['name']);

return response()->json([
'status' => 'success',
'message' => 'Tema berhasil diunggah dan siap digunakan',
]);
} else {
File::deleteDirectory($extractedPath);
File::deleteDirectory($filePath);
}
}
}
} catch (\Exception $e) {
Log::error('File upload failed: ' . $e->getMessage());
Log::error('Theme upload failed: ' . $e->getMessage(), [
'action' => 'theme_upload_failed',
'user_id' => auth()->id(),
'error' => $e->getMessage(),
]);

return response()->json([
'status' => 'error',
'message' => 'Tema gagal diunggah. Silakan periksa log untuk detail.',
]);
}

return response()->json([
'status' => 'error',
'message' => 'Tema gagal diunggah',
]);
}

public function destroy(Themes $themes)
Expand All @@ -138,84 +94,18 @@ public function destroy(Themes $themes)
$themes->delete();

// Clear cache
$this->clearThemeCache();
$this->themeService->clearCache();

return redirect()->route('setting.themes.index')
->with('success', 'Tema berhasil dihapus');
}

/**
* Clear all theme-related cache
*/
private function clearThemeCache()
{
// Clear specific cache keys
Cache::forget('active_theme');
$store = Cache::getStore();
if (method_exists($store, 'tags')) {
// Tagged cache supported, clear tag and exit to avoid duplicate calls below
Cache::tags(['theme_api'])->flush();
Log::info('Theme cache cleared via tags');
} else {
// Alternative: Clear by prefix
$keys = Cache::get('theme_api:*');
foreach ($keys ?? [] as $key) {
Cache::forget($key);
}
}

Log::info('Theme cache cleared');
}

/**
* Load theme hooks/filters
*/
private function loadThemeHooks(string $themePath)
{
$hooksFile = base_path("themes/{$themePath}/hooks.php");

if (file_exists($hooksFile)) {
try {
include_once $hooksFile;
Log::info("Theme hooks loaded: {$themePath}");
} catch (\Exception $e) {
Log::error("Failed to load theme hooks: {$e->getMessage()}");
}
}
}

/**
* Validate theme structure for API compatibility
*/
private function validateThemeStructure(string $path, string $folder)
{
$requiredFiles = [
'composer.json',
'theme.json',
];

foreach ($requiredFiles as $file) {
if (!file_exists("$path/$folder/$file")) {
throw new \Exception("File {$file} tidak ditemukan di tema");
}
}

// Validate theme.json
$themeConfig = json_decode(file_get_contents("$path/$folder/theme.json"), true);

if (!isset($themeConfig['api_version'])) {
Log::warning("Tema tidak mendefinisikan api_version, gunakan v1 sebagai default");
}

return true;
}

/**
* Clear API cache manually (untuk admin)
*/
public function clearCache()
{
$this->clearThemeCache();
$this->themeService->clearCache();

return redirect()->route('setting.themes.index')
->with('success', 'Cache API tema berhasil dibersihkan');
Expand Down
Loading
Loading