can('manage-add-on')) { $modules = $this->getAllModules(); return Inertia::render('modules/index', [ 'modules' => $modules, ]); } else { return back()->with('error', __('Permission denied')); } } public function upload() { if (Auth::user()->can('manage-add-on')) { return Inertia::render('modules/upload'); } else { return back()->with('error', __('Permission denied')); } } public function enable(Request $request) { $module = (new Module())->find($request->name); if (!empty($module)) { \App::setLocale('en'); if ($module->isEnabled()) { $check_child_module = $this->Check_Child_Module($module); if ($check_child_module == true) { $module = (new Module())->find($request->name); $module->disable(); return redirect()->back()->with('success', __('Module Disable Successfully!')); } else { return redirect()->back()->with('error', __($check_child_module['msg'])); } } else { $addon = AddOn::where('module', $request->name)->first(); if (empty($addon)) { Artisan::call('migrate --path=/packages/workdo/' . $request->name . '/src/Database/Migrations --force'); Artisan::call('package:seed ' . $request->name); $filePath = base_path('packages/workdo/' . $request->name . '/module.json'); $jsonContent = file_get_contents($filePath); $data = json_decode($jsonContent, true); $addon = new AddOn; $addon->module = $data['name']; $addon->name = $data['alias']; $addon->monthly_price = $data['monthly_price'] ?? 0; $addon->yearly_price = $data['yearly_price'] ?? 0; $addon->package_name = $data['package_name']; $addon->for_admin = $data['for_admin'] ?? false; $addon->priority = $data['priority'] ?? 0; $addon->save(); } (new Module())->moduleCacheForget($request->name); $module = (new Module())->find($request->name); $check_parent_module = $this->Check_Parent_Module($module); if ($check_parent_module['status'] == true) { Artisan::call('migrate --path=/packages/workdo/' . $request->name . '/src/Database/Migrations --force'); Artisan::call('package:seed ' . $request->name); $module = (new Module())->find($request->name); $module->enable(); return redirect()->back()->with('success', __('Module Enable Successfully!')); } else { return redirect()->back()->with('error', __($check_parent_module['msg'])); } } } else { return redirect()->back()->with('error', __('oops something wren wrong!')); } } public function Check_Parent_Module($module) { $path = $module->getPath() . '/module.json'; $json = json_decode(file_get_contents($path), true); $data['status'] = true; $data['msg'] = ''; if (isset($json['parent_module']) && !empty($json['parent_module'])) { foreach ($json['parent_module'] as $key => $value) { $modules = implode(',', $json['parent_module']); $parent_module = module_is_active($value); if ($parent_module == true) { $module = (new Module())->find($value); if ($module) { $this->Check_Parent_Module($module); } } else { $data['status'] = false; $data['msg'] = 'please activate this module ' . $modules; return $data; } } return $data; } else { return $data; } } public function Check_Child_Module($module) { $path = $module->getPath() . '/module.json'; $json = json_decode(file_get_contents($path), true); if (isset($json['child_module']) && !empty($json['child_module'])) { foreach ($json['child_module'] as $key => $value) { $child_module = module_is_active($value); if ($child_module == true) { $module = (new Module())->find($value); $module->disable(); if ($module) { $this->Check_Child_Module($module); } } } return true; } else { return true; } } private function getAllModules() { $modules = []; $packagesPath = base_path('packages/workdo'); if (!File::exists($packagesPath)) { return $modules; } $directories = File::directories($packagesPath); foreach ($directories as $directory) { $moduleName = basename($directory); $moduleJsonPath = "{$directory}/module.json"; if (File::exists($moduleJsonPath)) { $moduleData = json_decode(File::get($moduleJsonPath), true); if ($moduleData) { $addon = AddOn::where('module', $moduleData['name'])->first(); $modules[] = [ 'name' => $moduleData['name'] ?? $moduleName, 'alias' => $addon ? $addon->name :$moduleData['alias'], 'description' => $moduleData['description'] ?? '', 'version' => $moduleData['version'] ?? '1.0.0', 'image' => url('/packages/workdo/' . $moduleName . '/favicon.png'), 'is_enabled' => $addon ? $addon->is_enable : false, 'package_name' => $moduleData['package_name'] ?? null, 'display' => $moduleData['display'] ?? true, 'priority' => $moduleData['priority'] ?? 10, ]; } } } usort($modules, function ($a, $b) { return $a['priority'] - $b['priority']; }); return $modules; } public function install(Request $request) { if (!Auth::user()->can('manage-add-on')) { return back()->with('error', __('Permission denied')); } $request->validate([ 'files' => 'required|array', 'files.*' => 'required|file|mimes:zip|max:51200' ], [ 'files.required' => __('Please select at least one file to upload.'), 'files.array' => __('Files must be provided as an array.'), 'files.*.required' => __('Each file is required.'), 'files.*.file' => __('Each item must be a valid file.'), 'files.*.mimes' => __('Only ZIP files are allowed.'), 'files.*.max' => __('File size cannot exceed 50MB.'), ]); $results = []; $successCount = 0; $errorCount = 0; foreach ($request->file('files') as $file) { try { $result = $this->installSinglePackage($file); $results[] = $result; if ($result['success']) { $successCount++; } else { $errorCount++; } } catch (\Exception $e) { $results[] = [ 'success' => false, 'filename' => $file->getClientOriginalName(), 'message' => $e->getMessage() ]; $errorCount++; } } $message = "Installed {$successCount} packages successfully"; if ($errorCount > 0) { $message .= ", {$errorCount} failed"; } return back()->with($errorCount > 0 ? 'warning' : 'success', $message); } private function installSinglePackage($file) { $zip = new ZipArchive; $fileName = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME); $res = $zip->open($file->getPathname()); if ($res !== TRUE) { throw new \Exception("Unable to open ZIP file: {$file->getClientOriginalName()}"); } $tempPath = base_path('packages/workdo/tmp_' . uniqid()); $zip->extractTo($tempPath); $zip->close(); $rootFolder = array_diff(scandir($tempPath), ['.', '..']); if (empty($rootFolder)) { $this->deleteDirectory($tempPath); throw new \Exception("Invalid ZIP structure: {$file->getClientOriginalName()}"); } $rootFolderName = array_values($rootFolder)[0]; $moduleJsonPath = $tempPath . '/' . $rootFolderName . '/module.json'; if (!file_exists($moduleJsonPath)) { $this->deleteDirectory($tempPath); throw new \Exception("module.json not found: {$file->getClientOriginalName()}"); } $moduleData = json_decode(file_get_contents($moduleJsonPath), true); if (!$moduleData) { $this->deleteDirectory($tempPath); throw new \Exception("Invalid module.json: {$file->getClientOriginalName()}"); } $extractPath = base_path('packages/workdo/' . $moduleData['name']); $this->createDirectory($extractPath); $this->moveExtractedFiles($tempPath . '/' . $rootFolderName, $extractPath); $this->deleteDirectory($tempPath); $this->setPermissions($extractPath); $addon = AddOn::where('module', $moduleData['name'])->first(); if (!$addon) { $addon = new AddOn; $addon->module = $moduleData['name']; $addon->name = $moduleData['alias']; $addon->monthly_price = $moduleData['monthly_price'] ?? 0; $addon->yearly_price = $moduleData['yearly_price'] ?? 0; $addon->is_enable = false; $addon->package_name = $moduleData['package_name'] ?? null; $addon->for_admin = $moduleData['for_admin'] ?? null; $addon->priority = $moduleData['priority'] ?? 0; $addon->save(); } return [ 'success' => true, 'filename' => $file->getClientOriginalName(), 'message' => "Installed successfully" ]; } private function createDirectory($path) { if (!is_dir($path)) { mkdir($path, 0777, true); $this->setPermissions($path); } else { $this->setPermissions($path); } } // Set directory permissions private function setPermissions($path) { if (function_exists('chmod')) { @chmod($path, 0777); // Set permissions if possible } } /** * Move files from one directory to another. * * @param string $source * @param string $destination */ private function moveExtractedFiles($source, $destination, $filename = null) { // Adjust the source directory if a root folder (e.g., $filename) exists in the zip if ($filename) { $source = $source . DIRECTORY_SEPARATOR . $filename; } $files = array_diff(scandir($source), ['.', '..']); foreach ($files as $file) { $srcPath = $source . DIRECTORY_SEPARATOR . $file; $destPath = $destination . DIRECTORY_SEPARATOR . $file; if (is_dir($srcPath)) { // Recursively move subdirectories if (!is_dir($destPath)) { mkdir($destPath, 0777, true); } // Check if chmod exists if (function_exists('chmod')) { @chmod($destPath, 0777); // Set permissions if possible } $this->moveExtractedFiles($srcPath, $destPath); } else { // Move file rename($srcPath, $destPath); // Check if chmod exists if (function_exists('chmod')) { @chmod($destPath, 0777); // Set permissions if possible } } } } /** * Delete a directory and its contents. * * @param string $dirPath * @return bool */ private function deleteDirectory($dirPath) { if (!is_dir($dirPath)) { return false; } $items = array_diff(scandir($dirPath), ['.', '..']); foreach ($items as $item) { $path = $dirPath . DIRECTORY_SEPARATOR . $item; is_dir($path) ? $this->deleteDirectory($path) : unlink($path); } return rmdir($dirPath); } public function getUserActiveModules() { $user = Auth::user(); $oldplan = $user && $user->active_plan ? Plan::where('id', $user->active_plan)->first() : null; $plan = Plan::find($oldplan->id); if ($plan->custom_plan == 0) { $modules = []; } else { $userActiveModules = UserActiveModule::where('user_id', Auth::id())->get(); $modules = []; foreach ($userActiveModules as $userModule) { $addon = AddOn::where('module', $userModule->module)->first(); if ($addon) { $modules[] = [ 'module' => $userModule->module, 'alias' => $addon->name, 'image' => url('/packages/workdo/' . $userModule->module . '/favicon.png'), 'monthly_price' => $addon->monthly_price, 'yearly_price' => $addon->yearly_price ]; } } return response()->json([ 'success' => true, 'modules' => $modules ]); } } public function removeUserActiveModule($moduleId) { $deleted = UserActiveModule::where('user_id', Auth::id()) ->where('module', $moduleId) ->delete(); return response()->json([ 'success' => $deleted > 0, 'message' => $deleted > 0 ? 'Module removed successfully' : 'Module not found' ]); } }