snapshot of https://github.com/krayin/laravel-crm.git (2.2, 2026-09-18; blobs > 131072B omitted)
Some checks failed
Admin | Playwright Tests / Admin | Playwright Tests | Shard 1 Of 6 (push) Failing after 37s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 2 Of 6 (push) Failing after 7s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 4 Of 6 (push) Failing after 7s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 6 Of 6 (push) Failing after 6s
Linting Tests / PHP 8.3 test on ubuntu-latest (push) Failing after 5s
CI / PHP 8.3 test on ubuntu-latest (push) Failing after 6s
Skills Consistency / validate-skills (push) Successful in 10s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 3 Of 6 (push) Failing after 7s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 5 Of 6 (push) Failing after 6s

This commit is contained in:
upstream-mirror
2026-09-18 04:37:41 +05:00
commit 135ffdb085
1274 changed files with 144880 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
<?php
namespace Webkul\Installer\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
class Controller extends BaseController
{
use DispatchesJobs, ValidatesRequests;
}

View File

@@ -0,0 +1,109 @@
<?php
namespace Webkul\Installer\Http\Controllers;
use Illuminate\Http\Response as IlluminateResponse;
use Illuminate\Support\Facades\Cache;
use Intervention\Image\Image;
class ImageCacheController
{
/**
* Cache template
*
* @var string
*/
protected $template;
/**
* Logo
*
* @var string
*/
const KRAYIN_LOGO = 'https://updates.krayincrm.com/krayin.png';
/**
* Get HTTP response of template applied image file
*
* @param string $filename
* @return Illuminate\Http\Response
*/
public function getImage($filename)
{
try {
$content = Cache::remember('krayin-logo', 10080, function () {
return $this->getImageFromUrl(self::KRAYIN_LOGO);
});
} catch (\Exception $e) {
$content = '';
}
return $this->buildResponse($content);
}
/**
* Init from given URL
*
* @param string $url
* @return Image
*/
public function getImageFromUrl($url)
{
$domain = config('app.url');
$options = [
'http' => [
'method' => 'GET',
'protocol_version' => 1.1, // force use HTTP 1.1 for service mesh environment with envoy
'header' => "Accept-language: en\r\n".
"Domain: $domain\r\n".
"User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36\r\n",
],
];
$context = stream_context_create($options);
if ($data = @file_get_contents($url, false, $context)) {
return $data;
}
throw new \Exception(
'Unable to init from given url ('.$url.').'
);
}
/**
* Builds HTTP response from given image data
*
* @param string $content
* @return Illuminate\Http\Response
*/
protected function buildResponse($content)
{
/**
* Define mime type
*/
$mime = finfo_buffer(finfo_open(FILEINFO_MIME_TYPE), $content);
/**
* Respond with 304 not modified if browser has the image cached
*/
$eTag = md5($content);
$notModified = isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == $eTag;
$content = $notModified ? null : $content;
$statusCode = $notModified ? 304 : 200;
/**
* Return http response
*/
return new IlluminateResponse($content, $statusCode, [
'Content-Type' => $mime,
'Cache-Control' => 'max-age=10080, public',
'Content-Length' => strlen($content),
'Etag' => $eTag,
]);
}
}

View File

@@ -0,0 +1,181 @@
<?php
namespace Webkul\Installer\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\File;
use Webkul\Installer\Helpers\DatabaseManager;
use Webkul\Installer\Helpers\EnvironmentManager;
use Webkul\Installer\Helpers\ServerRequirements;
class InstallerController extends Controller
{
/**
* Const Variable For Min PHP Version
*
* @var string
*/
const MIN_PHP_VERSION = '8.1.0';
/**
* Const Variable for Static Customer Id
*
* @var int
*/
const USER_ID = 1;
/**
* Create a new controller instance
*
* @return void
*/
public function __construct(
protected ServerRequirements $serverRequirements,
protected EnvironmentManager $environmentManager,
protected DatabaseManager $databaseManager
) {}
/**
* Installer View Root Page
*/
public function index()
{
$phpVersion = $this->serverRequirements->checkPHPversion(self::MIN_PHP_VERSION);
$requirements = $this->serverRequirements->validate();
if (request()->has('locale')) {
return redirect()->route('installer.index');
}
return view('installer::installer.index', compact('requirements', 'phpVersion'));
}
/**
* ENV File Setup
*/
public function envFileSetup(Request $request): JsonResponse
{
$this->abortIfInstalled();
/**
* From here the database is about to be built, and the seeder will create the default
* administrator before the final step runs. Recording that an installation is under way
* keeps that half-built state from being mistaken for a finished installation.
*/
$this->databaseManager->markInstallationInProgress();
$message = $this->environmentManager->generateEnv($request);
return new JsonResponse(['data' => $message]);
}
/**
* Run Migration
*/
public function runMigration(): mixed
{
$this->abortIfInstalled();
return $this->databaseManager->migration();
}
/**
* Run Seeder.
*
* @return void|string
*/
public function runSeeder()
{
$this->abortIfInstalled();
$allParameters = request()->allParameters;
$parameter = [
'parameter' => [
'default_locales' => $allParameters['app_locale'] ?? null,
'default_currency' => $allParameters['app_currency'] ?? null,
],
];
$response = $this->environmentManager->setEnvConfiguration($allParameters);
if ($response) {
$seeder = $this->databaseManager->seeder($parameter);
return $seeder;
}
}
/**
* Admin Configuration Setup.
*/
public function adminConfigSetup(): bool
{
$this->abortIfInstalled();
$password = password_hash(request()->input('password'), PASSWORD_BCRYPT, ['cost' => 10]);
try {
DB::table('users')->updateOrInsert(
[
'id' => self::USER_ID,
], [
'name' => request()->input('admin'),
'email' => request()->input('email'),
'password' => $password,
'role_id' => 1,
'status' => 1,
]
);
$this->smtpConfigSetup();
return true;
} catch (\Throwable $th) {
report($th);
return false;
}
}
/**
* Abort the request when the application has already been installed.
*
* The installer API endpoints re-write the environment file, run migrations/seeders and overwrite
* the administrator account. Once the completion marker exists the installation has finished, so
* these endpoints must not run again — this prevents an already installed application from being
* reconfigured or its administrator overwritten through the installer routes.
*/
private function abortIfInstalled(): void
{
if ($this->databaseManager->isInstallationComplete()) {
abort(403);
}
}
/**
* SMTP connection setup for Mail
*/
private function smtpConfigSetup()
{
$filePath = storage_path('installed');
File::put($filePath, 'Your Krayin App is Successfully Installed');
/**
* Recorded in the database as well as on disk, so losing the marker file cannot reopen the
* installer on an application that already holds real data.
*/
$this->databaseManager->markInstallationCompleted();
$this->databaseManager->clearInstallationInProgress();
Event::dispatch('krayin.installed');
return $filePath;
}
}

View File

@@ -0,0 +1,79 @@
<?php
namespace Webkul\Installer\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Str;
use Webkul\Installer\Helpers\DatabaseManager;
class CanInstall
{
/**
* Handles Requests if application is already installed then redirect to dashboard else to installer.
*/
public function handle(Request $request, Closure $next): mixed
{
if (Str::contains($request->getPathInfo(), '/install')) {
/**
* Once the application is fully installed, the installer and its API endpoints must be
* unreachable. Previously AJAX requests were exempted here, but whether a request is
* "AJAX" is decided solely by the client supplied `X-Requested-With` header, which let an
* unauthenticated request reach the installer endpoints on a live application. The
* completion state is recorded only when the installation finishes, so an installation in
* progress is unaffected.
*/
if ($this->isInstallationComplete()) {
if ($request->ajax()) {
abort(403);
}
return redirect()->route('admin.dashboard.index');
}
} elseif (! $this->isAlreadyInstalled()) {
return redirect()->route('installer.index');
}
return $next($request);
}
/**
* Whether the installation has fully completed.
*
* Delegates to the single authority, which consults the completion marker, the database flag and
* finally the database itself, while excluding an installation that is genuinely under way.
*/
public function isInstallationComplete(): bool
{
return app(DatabaseManager::class)->isInstallationComplete();
}
/**
* Check if application is already installed.
*/
public function isAlreadyInstalled(): bool
{
if (file_exists(storage_path('installed'))) {
return true;
}
if (($databaseManager = app(DatabaseManager::class))->isInstalled()) {
touch(storage_path('installed'));
/**
* Backfill for an application installed before completion was recorded in the database.
* Reaching here means the marker file was missing while the database was fully
* installed, so the flag is written once and then travels with the data, keeping the
* installer closed on every later deploy that arrives without `storage/`.
*/
$databaseManager->markInstallationCompleted();
Event::dispatch('krayin.installed');
return true;
}
return false;
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace Webkul\Installer\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class Locale
{
/**
* Handle an incoming request.
*
* @param Request $request
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($localeCode = $request->query('locale')) {
app()->setLocale($localeCode);
session()->put('installer_locale', $localeCode);
} else {
app()->setLocale(session()->get('installer_locale') ?? config('app.locale'));
}
return $next($request);
}
}