feat: multi-tenant architecture and tenant isolation changes
This commit is contained in:
172
app/Http/Controllers/ExecutiveInquiryController.php
Normal file
172
app/Http/Controllers/ExecutiveInquiryController.php
Normal file
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
use App\Models\Inquiry;
|
||||
use App\Jobs\ProvisionTenantJob;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class ExecutiveInquiryController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$status = $request->query('status');
|
||||
|
||||
$query = Inquiry::with('approver')->orderBy('created_at', 'desc');
|
||||
|
||||
if (!empty($status)) {
|
||||
$query->where('status', $status);
|
||||
}
|
||||
|
||||
$inquiries = $query->paginate(20);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => $inquiries,
|
||||
]);
|
||||
}
|
||||
|
||||
public function approve(Request $request, $id)
|
||||
{
|
||||
$inquiry = Inquiry::findOrFail($id);
|
||||
|
||||
$request->validate([
|
||||
'desired_subdomain' => 'nullable|string|max:50|alpha_dash',
|
||||
'payment_reference' => 'nullable|string|max:255',
|
||||
]);
|
||||
|
||||
if ($request->filled('desired_subdomain')) {
|
||||
$newSubdomain = \Illuminate\Support\Str::slug($request->desired_subdomain);
|
||||
if ($newSubdomain !== $inquiry->desired_subdomain) {
|
||||
if (\App\Models\Tenant::where('id', $newSubdomain)->exists()) {
|
||||
return response()->json(['success' => false, 'message' => 'The specified subdomain is already in use by an active tenant.'], 422);
|
||||
}
|
||||
if (\Stancl\Tenancy\Database\Models\Domain::where('domain', 'LIKE', $newSubdomain . '.%')->orWhere('domain', $newSubdomain)->exists()) {
|
||||
return response()->json(['success' => false, 'message' => 'The specified subdomain is already assigned to a domain.'], 422);
|
||||
}
|
||||
if (Inquiry::where('desired_subdomain', $newSubdomain)->where('id', '!=', $inquiry->id)->exists()) {
|
||||
return response()->json(['success' => false, 'message' => 'The specified subdomain is already reserved by another inquiry.'], 422);
|
||||
}
|
||||
}
|
||||
$inquiry->desired_subdomain = $newSubdomain;
|
||||
}
|
||||
|
||||
if ($request->filled('payment_reference')) {
|
||||
$inquiry->payment_reference = $request->payment_reference;
|
||||
}
|
||||
|
||||
if ($request->has('requested_features') && is_array($request->requested_features)) {
|
||||
$allowedModules = \App\Constants\ModuleContract::getAllInquiryKeys();
|
||||
$inquiry->requested_features = array_values(array_intersect($request->requested_features, $allowedModules));
|
||||
}
|
||||
|
||||
$inquiry->approved_by_user_id = $request->user()->id;
|
||||
$inquiry->approved_at = Carbon::now();
|
||||
$inquiry->status = 'approved';
|
||||
$inquiry->save();
|
||||
|
||||
// Dispatch tenant DB provisioning job to queue
|
||||
ProvisionTenantJob::dispatch($inquiry);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Inquiry approved and tenant provisioning pipeline dispatched successfully!',
|
||||
'data' => $inquiry,
|
||||
]);
|
||||
}
|
||||
|
||||
public function reject(Request $request, $id)
|
||||
{
|
||||
$inquiry = Inquiry::findOrFail($id);
|
||||
|
||||
$request->validate([
|
||||
'rejection_reason' => 'required|string|max:500',
|
||||
]);
|
||||
|
||||
$inquiry->status = 'rejected';
|
||||
$inquiry->rejection_reason = $request->rejection_reason;
|
||||
$inquiry->approved_by_user_id = $request->user()->id;
|
||||
$inquiry->approved_at = Carbon::now();
|
||||
$inquiry->save();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Inquiry rejected successfully.',
|
||||
'data' => $inquiry,
|
||||
]);
|
||||
}
|
||||
|
||||
public function approveInquiryFromWeb(Request $request)
|
||||
{
|
||||
$allowedModules = \App\Constants\ModuleContract::getAllInquiryKeys();
|
||||
|
||||
$request->validate([
|
||||
'company_name' => 'required|string|max:255',
|
||||
'contact_name' => 'required|string|max:255',
|
||||
'email' => 'required|email|max:255',
|
||||
'desired_subdomain' => 'required|string|max:50|alpha_dash',
|
||||
'requested_features' => 'nullable|array',
|
||||
'requested_features.*' => 'string|in:' . implode(',', $allowedModules),
|
||||
'payment_reference' => 'nullable|string|max:255',
|
||||
]);
|
||||
|
||||
$desiredSubdomain = \Illuminate\Support\Str::slug($request->desired_subdomain);
|
||||
|
||||
// Check if tenant is already active
|
||||
$existingInquiry = Inquiry::where('email', $request->email)->first();
|
||||
if ($existingInquiry && in_array($existingInquiry->status, ['active', 'provisioning'])) {
|
||||
if ($request->wantsJson()) {
|
||||
return response()->json(['success' => false, 'message' => 'This company tenant is already active and cannot be re-provisioned.'], 422);
|
||||
}
|
||||
return redirect()->back()->withErrors(['email' => 'This company tenant is already active and cannot be re-provisioned.']);
|
||||
}
|
||||
|
||||
// Check domain & tenant uniqueness if creating new
|
||||
if (\App\Models\Tenant::where('id', $desiredSubdomain)->exists() || \Stancl\Tenancy\Database\Models\Domain::where('domain', 'LIKE', $desiredSubdomain . '.%')->orWhere('domain', $desiredSubdomain)->exists()) {
|
||||
return redirect()->back()->with('error', 'The requested subdomain is already in use by an active tenant.');
|
||||
}
|
||||
|
||||
$inquiry = Inquiry::updateOrCreate(
|
||||
['email' => $request->email],
|
||||
[
|
||||
'company_name' => $request->company_name,
|
||||
'contact_name' => $request->contact_name,
|
||||
'desired_subdomain' => $desiredSubdomain,
|
||||
'employee_count' => $request->employee_count ?? 10,
|
||||
'requested_features' => $request->requested_features ?? ($existingInquiry->requested_features ?? \App\Constants\ModuleContract::getAllInquiryKeys()),
|
||||
'payment_reference' => $request->payment_reference ?? 'MANUAL-EXECUTIVE-PROVISION',
|
||||
'status' => 'approved',
|
||||
'email_verified_at' => Carbon::now(),
|
||||
'approved_by_user_id' => $request->user()->id,
|
||||
'approved_at' => Carbon::now(),
|
||||
]
|
||||
);
|
||||
|
||||
ProvisionTenantJob::dispatch($inquiry);
|
||||
|
||||
return redirect()->back()->with('success', 'Subdomain created and database provisioned successfully!');
|
||||
}
|
||||
|
||||
public function destroy(Request $request, $id)
|
||||
{
|
||||
$inquiry = Inquiry::findOrFail($id);
|
||||
|
||||
if ($inquiry->email) {
|
||||
\App\Models\Contact::where('email', $inquiry->email)->delete();
|
||||
}
|
||||
|
||||
$inquiry->delete();
|
||||
|
||||
if ($request->wantsJson()) {
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Inquiry and matching contact record deleted permanently from database.',
|
||||
]);
|
||||
}
|
||||
|
||||
return redirect()->back()->with('success', 'Inquiry and matching contact record deleted permanently from database.');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user