migrate to gtea from bistbucket

This commit is contained in:
2026-03-15 17:08:23 +07:00
commit 129ca2260c
3716 changed files with 566316 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
<?php
namespace App\Http\Controllers;
use App\Traits\ResponseTrait;
abstract class Controller
{
use ResponseTrait;
}

View File

@@ -0,0 +1,317 @@
<?php
namespace App\Http\Controllers\WEB;
use App\Http\Controllers\Controller;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Nwidart\Modules\Facades\Module;
use ZipArchive;
class InstallController extends Controller
{
public function index()
{
return view('install.start');
}
public function requirements()
{
$requirements = [
'PHP Version (^8.2)' => version_compare(phpversion(), '^8.2', '>='),
'OpenSSL Extension' => extension_loaded('openssl'),
'PDO Extension' => extension_loaded('PDO'),
'PDO MySQL Extension' => extension_loaded('pdo_mysql'),
'Mbstring Extension' => extension_loaded('mbstring'),
'Tokenizer Extension' => extension_loaded('tokenizer'),
'GD Extension' => extension_loaded('gd'),
'Fileinfo Extension' => extension_loaded('fileinfo'),
];
$next = true;
foreach ($requirements as $key) {
if ($key == false) {
$next = false;
}
}
return view('install.requirements', compact('requirements', 'next'));
}
public function keyWorld()
{
$next = true;
return view('install.codeniche_file', compact('next'));
}
public function step5(Request $request)
{
return view('install.database');
}
public function permissions()
{
$permissions = [
'storage/app' => is_writable(storage_path('app')),
'storage/framework/cache' => is_writable(storage_path('framework/cache')),
'storage/framework/sessions' => is_writable(storage_path('framework/sessions')),
'storage/framework/views' => is_writable(storage_path('framework/views')),
'storage/logs' => is_writable(storage_path('logs')),
'storage' => is_writable(storage_path('')),
'bootstrap/cache' => is_writable(base_path('bootstrap/cache')),
];
$next = true;
foreach ($permissions as $key) {
if ($key == false) {
$next = false;
}
}
return view('install.permissions', compact('permissions', 'next'));
}
public function database(Request $request)
{
if ($request->isMethod('post')) {
$credentials = [
'software_name' => $request->software_name,
'host' => $request->host,
'username' => $request->username,
'password' => $request->password,
'name' => $request->name,
'port' => $request->port,
];
// Step 1: Update the .env file
$this->updateEnvFile($credentials);
// Step 3: Test the Database Connection
try {
DB::purge('mysql'); // Reset connection
DB::reconnect('mysql'); // Reconnect with new settings
DB::connection()->getPdo(); // Attempt to connect
// Step 4: Check if Database Exists
if (! DB::select('SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = ?', [$credentials['name']])) {
return redirect()->back()->withErrors(['error' => __('The specified database does not exist.')]);
}
return redirect('install/installation');
} catch (Exception $e) {
return redirect()->back()->withErrors(['error' => 'Database connection failed: '.$e->getMessage()]);
}
}
return view('install.database');
}
private function updateEnvFile(array $credentials)
{
$path = base_path('.env');
if (file_exists($path)) {
$envContent = file_get_contents($path);
$envContent = preg_replace('/^APP_NAME=.*/m', 'APP_NAME="'.$credentials['software_name'].'"', $envContent);
$envContent = preg_replace('/^DB_HOST=.*/m', 'DB_HOST='.$credentials['host'], $envContent);
$envContent = preg_replace('/^DB_DATABASE=.*/m', 'DB_DATABASE='.$credentials['name'], $envContent);
$envContent = preg_replace('/^DB_USERNAME=.*/m', 'DB_USERNAME='.$credentials['username'], $envContent);
$envContent = preg_replace('/^DB_PASSWORD=.*/m', 'DB_PASSWORD='.$credentials['password'], $envContent);
$envContent = preg_replace('/^DB_PORT=.*/m', 'DB_PORT='.$credentials['port'], $envContent);
file_put_contents($path, $envContent);
}
}
public function installation(Request $request)
{
if ($request->isMethod('post')) {
try {
Artisan::call('view:clear');
Artisan::call('cache:clear');
Artisan::call('config:clear');
Artisan::call('migrate:fresh');
Artisan::call('db:seed');
// Seed all modules
$modules = Module::allEnabled(); // Fetch all enabled modules
foreach ($modules as $module) {
Artisan::call('module:seed', ['module' => $module->getName()]);
}
// OAuth Client for Users
$clientId1 = (string) Str::uuid();
$clientSecret1 = Str::random(40);
DB::table('oauth_clients')->insert([
'id' => $clientId1,
'owner_type' => null,
'owner_id' => null,
'name' => '1',
'secret' => Hash::make($clientSecret1),
'provider' => 'users',
'redirect_uris' => json_encode([]),
'grant_types' => json_encode(['personal_access']),
'revoked' => 0,
'created_at' => now(),
'updated_at' => now(),
]);
// OAuth Client for Customers
$clientId2 = (string) Str::uuid();
$clientSecret2 = Str::random(40);
DB::table('oauth_clients')->insert([
'id' => $clientId2,
'owner_type' => null,
'owner_id' => null,
'name' => '0',
'secret' => Hash::make($clientSecret2),
'provider' => 'customers',
'redirect_uris' => json_encode([]),
'grant_types' => json_encode(['personal_access']),
'revoked' => 0,
'created_at' => now(),
'updated_at' => now(),
]);
file_put_contents(storage_path('mightyRestaurant'), 'Welcome to MightyRestaurant Software');
// 🔥 Delete migration and seeder files
$this->deleteInstallationFiles();
return redirect('install/complete');
} catch (Exception $e) {
return redirect()->back();
}
}
return view('install.installation');
}
public function complete()
{
Artisan::call('view:clear');
Artisan::call('cache:clear');
Artisan::call('config:clear');
return view('install.complete');
}
public function validateInput(Request $request)
{
// Basic local validation for required fields
$validator = Validator::make($request->all(), [
'purchase_key' => 'required|string',
'username' => 'required|string',
]);
if ($validator->fails()) {
return response()->json([
'status' => 'error',
'errors' => $validator->errors(),
]);
}
$domain = $request->getHost(); // Get current domain
$purchaseKey = $request->purchase_key;
$userName = $request->username;
try {
$domainCheckUrl = config('install.codeniche.domain_register_check');
$response = Http::post($domainCheckUrl, [
'purchase_key' => $purchaseKey,
'domain' => $domain,
'username' => $userName,
]);
if ($response->successful()) {
return response()->json([
'status' => 'success',
'message' => $response['message'] ?? 'Domain successfully validated.',
]);
} else {
$errorMessage = $response->json()['message'] ?? 'Validation failed.';
return response()->json([
'status' => 'error',
'message' => $errorMessage,
], $response->status());
}
} catch (Exception $e) {
return response()->json([
'status' => 'error',
'message' => 'An unexpected error occurred. Please try again later.',
], 500);
}
}
/**
* Delete all migration and seeder files permanently.
*/
private function deleteInstallationFiles()
{
// Delete Laravel migrations
$migrationFiles = glob(database_path('migrations/*.php'));
foreach ($migrationFiles as $file) {
@unlink($file);
}
// Delete Laravel seeders
$seederFiles = glob(database_path('seeders/*.php'));
foreach ($seederFiles as $file) {
@unlink($file);
}
// Optional: Delete module-specific migration and seeder files
foreach (Module::all() as $module) {
$moduleMigrationPath = module_path($module->getName()).'/Database/Migrations';
$moduleSeederPath = module_path($module->getName()).'/Database/Seeders';
$moduleMigrations = glob($moduleMigrationPath.'/*.php');
foreach ($moduleMigrations as $file) {
@unlink($file);
}
$moduleSeeders = glob($moduleSeederPath.'/*.php');
foreach ($moduleSeeders as $file) {
@unlink($file);
}
}
}
public function upgradeIndex(Request $request)
{
return view('upgrade');
}
public function uploadStore(Request $request)
{
$request->validate([
'upgrade_zip' => 'required|file|mimes:zip',
]);
$file = $request->file('upgrade_zip');
$zip = new ZipArchive;
$filePath = storage_path('app/temp_upgrade.zip');
$file->move(storage_path(), 'temp_upgrade.zip');
if ($zip->open($filePath) === true) {
$zip->extractTo(base_path()); // ⚠️ this will overwrite existing files
$zip->close();
File::delete($filePath);
return back()->with('success', 'Upgrade applied successfully!');
}
return back()->with('error', 'Failed to extract zip file.');
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace App\Http\Controllers\WEB;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Modules\Frontend\Models\Onboarding;
class PublicOnboardingController extends Controller
{
public function create()
{
return view('public.onboarding.create');
}
public function store(Request $request)
{
$request->validate([
'restaurant_name' => 'required|string|max:100',
'restaurant_email' => 'required|email|max:255|unique:restaurants,email',
'restaurant_phone' => 'required|string|max:15|unique:restaurants,phone',
'restaurant_domain' => 'nullable|string|max:100|unique:restaurants,domain',
'restaurant_type' => 'nullable|string|max:100',
'restaurant_address' => 'nullable|string|max:255',
'restaurant_logo' => 'nullable|image|mimes:jpeg,png,jpg,gif|max:2048',
'name' => 'required|string|max:100',
'email' => 'required|email|max:255|unique:users,email',
'phone' => 'required|string|max:50',
'password' => 'required|string|min:4|confirmed',
'avatar' => 'nullable|image|mimes:jpeg,png,jpg,gif|max:2048',
]);
// Handle the restaurant_logo file upload if it exists
$restaurantLogoPath = $request->hasFile('restaurant_logo')
? fileUploader('restaurants/', 'png', $request->file('restaurant_logo'))
: null;
// Handle the user_avatar file upload if it exists
$userAvatarPath = $request->hasFile('avatar')
? fileUploader('user_avatars/', 'png', $request->file('avatar'))
: null;
// Save onboarding data
Onboarding::create([
'restaurant_name' => $request->restaurant_name,
'restaurant_email' => $request->restaurant_email,
'restaurant_phone' => $request->restaurant_phone,
'restaurant_domain' => $request->restaurant_domain,
'restaurant_type' => $request->restaurant_type,
'restaurant_address' => $request->restaurant_address,
'name' => $request->name,
'email' => $request->email,
'phone' => $request->phone,
'password' => Hash::make($request->password),
'restaurant_logo' => $restaurantLogoPath,
'user_avatar' => $userAvatarPath,
'status' => 'pending',
]);
return redirect()->back()->with('success', 'Your onboarding request has been submitted successfully!');
}
}

View File

@@ -0,0 +1,104 @@
<?php
namespace App\Http\Controllers\WEB;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use PDO;
use PDOException;
class TestDbController extends Controller
{
protected $myDb;
public function testDB(Request $request)
{
$request->session()->put('env.DB_CONNECTION', $request->db_connection);
$request->session()->put('env.DB_HOST', $request->db_host);
$request->session()->put('env.DB_PORT', $request->db_port);
$request->session()->put('env.DB_DATABASE', $request->db_database);
$request->session()->put('env.DB_USERNAME', $request->db_username);
$request->session()->put('env.DB_PASSWORD', $request->db_password);
if ($request->db_connection == 'mysql') {
return $this->testMySql();
}
return response()->json([
'Error' => 'DB Type not Supported for testing',
'State' => '999',
]);
}
public function testMySql()
{
$db_type = session('env.DB_CONNECTION');
$db_host = session('env.DB_HOST');
$db_name = session('env.DB_DATABASE');
$db_user = session('env.DB_USERNAME');
$db_pass = session('env.DB_PASSWORD');
$db_port = session('env.DB_PORT');
if (! $db_name) {
return response()->json([
'Error' => 'No Database',
'State' => '999',
]);
}
if (! $db_user) {
return response()->json([
'Error' => 'No Username',
'State' => '999',
]);
}
if (! $db_port) {
return response()->json([
'Error' => 'No Port',
'State' => '999',
]);
}
if (! $db_host) {
return response()->json([
'Error' => 'No Host',
'State' => '999',
]);
}
try {
$db = new PDO($db_type.':host='.$db_host.';port='.$db_port.';dbname='.$db_name, $db_user, $db_pass, [
PDO::ATTR_TIMEOUT => '5',
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::MYSQL_ATTR_LOCAL_INFILE => true,
]);
} catch (PDOException $e) {
if ($e->getCode() == '1049') {
$db = new PDO($db_type.':host='.$db_host.';port='.$db_port.';dbname='.'', $db_user, $db_pass, [
PDO::ATTR_TIMEOUT => '5',
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::MYSQL_ATTR_LOCAL_INFILE => true,
]);
$db->query("CREATE DATABASE IF NOT EXISTS $db_name");
return response()->json([
'State' => '200',
'Success' => 'Database '.$db_name.' created',
]);
}
return response()->json([
'Error' => $e->getMessage(),
'State' => $e->getCode(),
]);
}
return response()->json([
'State' => '200',
'Success' => 'Seems okay',
]);
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace App\Http\Controllers;
use App\Services\Firebase\FirebaseService;
use Illuminate\Http\Request;
class WebsiteController extends Controller
{
public function index()
{
return view('welcome');
}
public function saveFcmToken(Request $request)
{
$request->validate(['token' => 'required|string']);
$user = auth()->user();
$user->fcm_token = $request->token;
$user->save();
return response()->json(['message' => 'FCM token saved']);
}
public function sentNotification(FirebaseService $firebase)
{
$token = auth()->user?->fcm_token;
if ($token) {
$firebase->sendNotification(
$token,
'A Push notification',
'Check the latest reply on your push notification.',
);
}
// Logic to send notification using Firebase
return response()->json(['message' => 'Notification sent']);
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Http\Middleware;
use Closure;
class CheckInstallation
{
public function handle($request, Closure $next)
{
if (! file_exists(storage_path('mightyRestaurant'))) {
return redirect('/install');
}
return $next($request);
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class CheckInstallationStatus
{
/**
* Handle an incoming request.
*/
public function handle(Request $request, Closure $next)
{
if (file_exists(storage_path('mightyRestaurant'))) {
return redirect('/'); // already installed
}
return $next($request);
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace App\Http\Middleware;
use App\Traits\ResponseTrait;
use Closure;
class CheckSubscription
{
use ResponseTrait;
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @return mixed
*/
public function handle($request, Closure $next)
{
$restaurant = auth()->user()->restaurant ?? null;
if (! $restaurant || ! $restaurant->activeSubscription()) {
return $this->responseError([], _lang('No active subscription.'), 403);
}
$subscription = $restaurant->activeSubscription();
$plan = $subscription->plan;
if (! $subscription->isActive()) {
return $this->responseError([], _lang('Subscription expired.'), 403);
}
return $next($request);
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace App\Http\Middleware;
use App\Traits\ResponseTrait;
use Closure;
class Customer
{
use ResponseTrait;
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @return mixed
*/
public function handle($request, Closure $next)
{
// Check if the authenticated user is not a Customer
if (auth()->user()->user_type != 'Customer') {
return $this->responseError([], _lang('You are not authorized to access this feature!'), 403);
}
return $next($request);
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class DeviceApiKeyMiddleware
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
$apiKey = $request->header('X-DEVICE-API-KEY');
if (! $apiKey) {
return response()->json([
'status' => false,
'message' => 'API key missing',
], 401);
}
// ENV based (demo)
if ($apiKey !== config('services.device.api_key')) {
return response()->json([
'status' => false,
'message' => 'Invalid API key',
], 403);
}
return $next($request);
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
/**
* Indicates whether the XSRF-TOKEN cookie should be set on the response.
*
* @var bool
*/
protected $addHttpCookie = true;
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array
*/
protected $except = [
'/pay-via-ajax',
'/success',
'payment/sslcommerz/*',
'payment/paytm/pay',
'/cancel',
'/fail',
'/ipn',
'/bkash/*',
'/paytabs-response',
'/customer/choose-shipping-address',
'/system_settings',
'/paytm*',
'payment/paytabs/callback*',
];
}

View File

@@ -0,0 +1,33 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Symfony\Component\HttpFoundation\Response;
class VerifyTokenOrigin
{
public function handle(Request $request, Closure $next): Response
{
$requestAgent = strtolower($request->header('User-Agent'));
// Only enforce this block in production
if (! App::hasDebugModeEnabled()) {
$blockedClients = ['postman', 'curl', 'insomnia'];
foreach ($blockedClients as $client) {
if (str_contains($requestAgent, $client)) {
return response()->json(['message' => 'API clients are not allowed in production.'], 403);
}
}
// Optional: Only allow browsers
if (! str_contains($requestAgent, 'mozilla') && ! str_contains($requestAgent, 'chrome')) {
return response()->json(['message' => 'Requests must come from a browser in production.'], 403);
}
}
return $next($request);
}
}