added vpn feature to mno
This commit is contained in:
@@ -4,6 +4,7 @@ namespace App\Http\Controllers;
|
|||||||
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Models\NetworkOperator;
|
use App\Models\NetworkOperator;
|
||||||
|
use App\Models\NetworkOperatorConnection;
|
||||||
|
|
||||||
class NetworkOperatorsController extends Controller
|
class NetworkOperatorsController extends Controller
|
||||||
{
|
{
|
||||||
@@ -34,9 +35,10 @@ class NetworkOperatorsController extends Controller
|
|||||||
|
|
||||||
$totalActive = NetworkOperator::where('connection_status', 'Active')->count();
|
$totalActive = NetworkOperator::where('connection_status', 'Active')->count();
|
||||||
$totalSipLinks = NetworkOperator::where('connection_type', 'like', '%VPN%')->count();
|
$totalSipLinks = NetworkOperator::where('connection_type', 'like', '%VPN%')->count();
|
||||||
|
$uniqueCountries = $uniqueCountriesCount = NetworkOperator::distinct('country')->count('country');
|
||||||
$totalOperators = NetworkOperator::count();
|
$totalOperators = NetworkOperator::count();
|
||||||
|
|
||||||
return view('network_operators.index', compact('operators', 'totalActive', 'totalSipLinks', 'totalOperators'));
|
return view('network_operators.index', compact('operators', 'totalActive', 'uniqueCountries', 'totalOperators'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
@@ -111,5 +113,61 @@ class NetworkOperatorsController extends Controller
|
|||||||
return view('network_operators.show', compact('operator'));
|
return view('network_operators.show', compact('operator'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function storeConnection(Request $request, $operatorId)
|
||||||
|
{
|
||||||
|
$request->validate([
|
||||||
|
'connection_mode' => 'required|string',
|
||||||
|
'identifier' => [
|
||||||
|
'required',
|
||||||
|
'string',
|
||||||
|
function ($attribute, $value, $fail) {
|
||||||
|
// 1. Check if valid IP Address (IPv4 or IPv6)
|
||||||
|
$isIp = filter_var($value, FILTER_VALIDATE_IP);
|
||||||
|
|
||||||
|
// 2. Check if valid Domain Name (e.g., smpp.operator.com)
|
||||||
|
$isDomain = preg_match('/^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/i', $value);
|
||||||
|
|
||||||
|
// 3. Check if valid CIDR Subnet (e.g., 196.200.15.0/24)
|
||||||
|
$isSubnet = preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}\/([0-9]|[1-2][0-9]|3[0-2])$/', $value);
|
||||||
|
|
||||||
|
if (!$isIp && !$isDomain && !$isSubnet) {
|
||||||
|
$fail('The identifier must be a valid IP address, CIDR subnet, or Domain Name.');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'port' => 'nullable|integer|min:1|max:65535',
|
||||||
|
'vpn_file' => 'nullable|file|mimes:pdf,doc,docx|max:5120',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$filePath = null;
|
||||||
|
if ($request->hasFile('vpn_file')) {
|
||||||
|
$filePath = $request->file('vpn_file')->store('vpn_forms', 'public');
|
||||||
|
}
|
||||||
|
|
||||||
|
$connection = NetworkOperatorConnection::create([
|
||||||
|
'network_operator_id' => $operatorId,
|
||||||
|
'connection_mode' => $request->connection_mode,
|
||||||
|
'identifier' => $request->identifier,
|
||||||
|
'port' => $request->port,
|
||||||
|
'status' => $request->status ?? 'Active',
|
||||||
|
'notes' => $request->notes,
|
||||||
|
'vpn_file_path' => $filePath,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'Connection detail added successfully!',
|
||||||
|
'connection' => $connection
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroyConnection($id)
|
||||||
|
{
|
||||||
|
$connection = NetworkOperatorConnection::findOrFail($id);
|
||||||
|
$connection->delete();
|
||||||
|
|
||||||
|
return redirect()->back()->with('success', 'Connection detail removed.');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -19,6 +19,10 @@ class NetworkOperator extends Model
|
|||||||
public function account_manager_info(){
|
public function account_manager_info(){
|
||||||
return $this->hasOne('App\Models\StaffMember', 'id', 'account_manager_id');
|
return $this->hasOne('App\Models\StaffMember', 'id', 'account_manager_id');
|
||||||
}
|
}
|
||||||
|
public function connectionDetails()
|
||||||
|
{
|
||||||
|
return $this->hasMany(NetworkOperatorConnection::class, 'network_operator_id');
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
public function setBuyingRateAttribute($value)
|
public function setBuyingRateAttribute($value)
|
||||||
{
|
{
|
||||||
@@ -32,4 +36,5 @@ class NetworkOperator extends Model
|
|||||||
set: fn (string $value) => filter_var($value, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION)
|
set: fn (string $value) => filter_var($value, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
16
app/Models/NetworkOperatorConnection.php
Normal file
16
app/Models/NetworkOperatorConnection.php
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class NetworkOperatorConnection extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'network_operator_connections';
|
||||||
|
protected $guarded = [];
|
||||||
|
|
||||||
|
public function operator()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(NetworkOperator::class, 'network_operator_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,13 +34,13 @@
|
|||||||
<div class="col-xl-4 col-md-6">
|
<div class="col-xl-4 col-md-6">
|
||||||
<div class="content-card p-3 h-100 border-start border-4 border-0" style="border-left-color: #5c4df0 !important;">
|
<div class="content-card p-3 h-100 border-start border-4 border-0" style="border-left-color: #5c4df0 !important;">
|
||||||
<div class="text-secondary fw-bold mb-1" style="font-size: 0.75rem; letter-spacing: 0.5px;">ACTIVE CONNECTIONS</div>
|
<div class="text-secondary fw-bold mb-1" style="font-size: 0.75rem; letter-spacing: 0.5px;">ACTIVE CONNECTIONS</div>
|
||||||
<h3 class="fw-bold mb-0">{{ $totalActive }} <span class="fs-6 fw-normal text-success"><i class="bi bi-arrow-up"></i> Online</span></h3>
|
<h3 class="fw-bold mb-0">{{ $totalActive }} <span class="fs-6 fw-normal text-success"><i class="bi bi-arrow-up"></i> Active</span></h3>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xl-4 col-md-6">
|
<div class="col-xl-4 col-md-6">
|
||||||
<div class="content-card p-3 h-100 border-start border-4 border-0" style="border-left-color: #10b981 !important;">
|
<div class="content-card p-3 h-100 border-start border-4 border-0" style="border-left-color: #10b981 !important;">
|
||||||
<div class="text-secondary fw-bold mb-1" style="font-size: 0.75rem; letter-spacing: 0.5px;">VPN LINKS </div>
|
<div class="text-secondary fw-bold mb-1" style="font-size: 0.75rem; letter-spacing: 0.5px;">Countries </div>
|
||||||
<h3 class="fw-bold mb-0">{{ $totalSipLinks }} Links</h3>
|
<h3 class="fw-bold mb-0">{{ $uniqueCountries }} </h3>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xl-4 col-md-6">
|
<div class="col-xl-4 col-md-6">
|
||||||
|
|||||||
@@ -108,8 +108,8 @@
|
|||||||
<input type="text" class="form-control" id="mnoTechSupport" name="technical_support_person" placeholder="Tech contact">
|
<input type="text" class="form-control" id="mnoTechSupport" name="technical_support_person" placeholder="Tech contact">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<label class="form-label text-secondary fw-semibold" style="font-size: 0.85rem;">Support Skype</label>
|
<label class="form-label text-secondary fw-semibold" style="font-size: 0.85rem;">Support MS Teams</label>
|
||||||
<input type="text" class="form-control" id="mnoSupportSkype" name="support_skype" placeholder="Skype ID">
|
<input type="text" class="form-control" id="mnoSupportSkype" name="support_skype" placeholder="MS Teams ID">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<label class="form-label text-secondary fw-semibold" style="font-size: 0.85rem;">Account Manager</label>
|
<label class="form-label text-secondary fw-semibold" style="font-size: 0.85rem;">Account Manager</label>
|
||||||
|
|||||||
@@ -155,7 +155,247 @@
|
|||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> <!-- Close Support Contacts content-card -->
|
||||||
|
</div> <!-- Close Right Column (col-lg-4) -->
|
||||||
|
</div> <!-- Close the main row (row g-4) -->
|
||||||
|
<!-- Connections & Interconnect Details Section -->
|
||||||
|
<div class="content-card p-4 mb-4">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||||
|
<h5 class="fw-bold mb-0 text-secondary" style="font-size: 0.9rem; text-transform: uppercase; letter-spacing: 0.5px;">
|
||||||
|
<i class="bi bi-shield-lock me-2 text-primary"></i> Connection Endpoints (VPN / Whitelisted IPs & Domains)
|
||||||
|
</h5>
|
||||||
|
<button type="button" class="btn btn-sm text-white fw-bold" style="background-color: #5c4df0;" data-bs-toggle="modal" data-bs-target="#addConnectionModal">
|
||||||
|
<i class="bi bi-plus-lg me-1"></i> Add Connection Detail
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<hr class="text-muted opacity-25">
|
||||||
|
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-custom align-middle mb-0">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Mode</th>
|
||||||
|
<th>Identifier (IP / Domain / VPN)</th>
|
||||||
|
<th>Port</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Notes</th>
|
||||||
|
<th class="text-end">Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@forelse($operator->connectionDetails as $conn)
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<span class="badge bg-secondary bg-opacity-10 text-dark border">{{ $conn->connection_mode }}</span>
|
||||||
|
@if($conn->vpn_file_path)
|
||||||
|
<a href="{{ asset('storage/' . $conn->vpn_file_path) }}" target="_blank" class="d-block mt-1" style="font-size: 0.75rem;">
|
||||||
|
<i class="bi bi-paperclip"></i> View Form
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
|
</td>
|
||||||
|
<td><code>{{ $conn->identifier }}</code></td>
|
||||||
|
<td>{{ $conn->port ?? 'N/A' }}</td>
|
||||||
|
<td>
|
||||||
|
<span class="badge {{ $conn->status == 'Active' ? 'bg-success' : 'bg-warning' }} bg-opacity-10 text-success px-2 py-1">
|
||||||
|
{{ $conn->status }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>{{ $conn->notes ?? '-' }}</td>
|
||||||
|
<td class="text-end">
|
||||||
|
<form action="{{ route('mnos.connections.destroy', $conn->id) }}" method="POST" class="d-inline">
|
||||||
|
@csrf
|
||||||
|
@method('DELETE')
|
||||||
|
<button type="submit" class="btn btn-sm btn-light text-danger" onclick="return confirm('Delete this connection detail?')">
|
||||||
|
<i class="bi bi-trash"></i>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@empty
|
||||||
|
<tr>
|
||||||
|
<td colspan="6" class="text-center text-secondary py-4">No specific VPN or IP whitelisting rules added yet.</td>
|
||||||
|
</tr>
|
||||||
|
@endforelse
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endsection
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@endsection
|
||||||
|
@push('modals')
|
||||||
|
|
||||||
|
<!-- Add Connection Modal -->
|
||||||
|
<!-- Add Connection Modal -->
|
||||||
|
<div class="modal fade" id="addConnectionModal" tabindex="-1" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-dialog-centered">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header bg-light">
|
||||||
|
<h5 class="modal-title fw-bold">Add Interconnect Detail</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Added ID to the form -->
|
||||||
|
<form id="addConnectionForm" action="{{ route('mnos.connections.store', $operator->id) }}" method="POST" enctype="multipart/form-data">
|
||||||
|
@csrf
|
||||||
|
<div class="modal-body p-4">
|
||||||
|
<!-- Alert container for AJAX errors -->
|
||||||
|
<div id="connectionModalAlert"></div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label text-secondary fw-semibold small">Connection Mode *</label>
|
||||||
|
<select name="connection_mode" id="connectionModeSelect" class="form-select" required>
|
||||||
|
<option value="Whitelisted IP">Whitelisted IP Address</option>
|
||||||
|
<option value="Domain">Domain / Hostname</option>
|
||||||
|
<option value="VPN Tunnel">VPN Tunnel Endpoint</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3" id="vpnFormContainer" style="display: none;">
|
||||||
|
<label class="form-label text-secondary fw-semibold small">Upload VPN Form (PDF, DOCX)</label>
|
||||||
|
<input type="file" name="vpn_file" id="vpnFileInput" class="form-control" accept=".pdf,.doc,.docx,.xlsx,.jpg,.png">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label text-secondary fw-semibold small">Identifier (IP / Domain / VPN Peer) *</label>
|
||||||
|
<input type="text" name="identifier" class="form-control" required placeholder="e.g. 196.200.15.22 or smpp.operator.com">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-3 mb-3">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label text-secondary fw-semibold small">Port</label>
|
||||||
|
<!-- Added type="number", min, and max -->
|
||||||
|
<input type="number" name="port" class="form-control" placeholder="e.g. 2775" min="1" max="65535">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="form-label text-secondary fw-semibold small">Status</label>
|
||||||
|
<select name="status" class="form-select">
|
||||||
|
<option value="Active">Active</option>
|
||||||
|
<option value="Testing">Testing</option>
|
||||||
|
<option value="Disabled">Disabled</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label text-secondary fw-semibold small">Notes / Description</label>
|
||||||
|
<textarea name="notes" class="form-control" rows="2" placeholder="Optional context or routing details..."></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer bg-light">
|
||||||
|
<button type="button" class="btn btn-outline-secondary btn-sm" data-bs-dismiss="modal">Cancel</button>
|
||||||
|
<button type="submit" id="btnSubmitConnection" class="btn text-white btn-sm fw-bold px-4" style="background-color: #5c4df0;">Save Endpoint</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endpush
|
||||||
|
@push('scripts')
|
||||||
|
<script>
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
console.log('foo bar')
|
||||||
|
$('#connectionModeSelect').on('change', function() {
|
||||||
|
if ($(this).val() === 'VPN Tunnel') {
|
||||||
|
$('#vpnFormContainer').slideDown();
|
||||||
|
} else {
|
||||||
|
$('#vpnFormContainer').slideUp();
|
||||||
|
$('#vpnFileInput').val(''); // Clear the file input if they switch away
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
$(document).ready(function() {
|
||||||
|
// Toggle VPN File input visibility
|
||||||
|
$('#connectionModeSelect').on('change', function() {
|
||||||
|
if ($(this).val() === 'VPN Tunnel') {
|
||||||
|
$('#vpnFormContainer').slideDown();
|
||||||
|
} else {
|
||||||
|
$('#vpnFormContainer').slideUp();
|
||||||
|
$('#vpnFileInput').val('');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle AJAX Form Submission
|
||||||
|
$('#addConnectionForm').on('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
let $form = $(this);
|
||||||
|
let $submitBtn = $('#btnSubmitConnection');
|
||||||
|
let originalText = $submitBtn.html();
|
||||||
|
let $alertBox = $('#connectionModalAlert');
|
||||||
|
|
||||||
|
// Use FormData to handle the file upload payload
|
||||||
|
let formData = new FormData(this);
|
||||||
|
|
||||||
|
$submitBtn.html('<span class="spinner-border spinner-border-sm me-2"></span>Saving...').prop('disabled', true);
|
||||||
|
$alertBox.html('');
|
||||||
|
$form.find('.is-invalid').removeClass('is-invalid');
|
||||||
|
$form.find('.invalid-feedback').remove();
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: $form.attr('action'),
|
||||||
|
type: 'POST',
|
||||||
|
data: formData,
|
||||||
|
processData: false, // Prevent jQuery from converting the data into a query string
|
||||||
|
contentType: false, // Prevent jQuery from overriding the multipart header
|
||||||
|
success: function(response) {
|
||||||
|
if (response.success) {
|
||||||
|
$('#addConnectionModal').modal('hide');
|
||||||
|
Swal.fire({
|
||||||
|
icon: 'success',
|
||||||
|
title: 'Success!',
|
||||||
|
text: response.message,
|
||||||
|
confirmButtonColor: '#5c4df0'
|
||||||
|
}).then(() => {
|
||||||
|
// Reload the page to reflect the new connection in the table
|
||||||
|
location.reload();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(xhr) {
|
||||||
|
if (xhr.status === 422) {
|
||||||
|
let errors = xhr.responseJSON.errors;
|
||||||
|
|
||||||
|
$alertBox.html(`
|
||||||
|
<div class="alert alert-danger d-flex align-items-center py-2 px-3 small" role="alert">
|
||||||
|
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
||||||
|
<div>Please check the highlighted fields below.</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
|
||||||
|
// Highlight specific fields
|
||||||
|
$.each(errors, function(key, value) {
|
||||||
|
let $input = $form.find('[name="' + key + '"]');
|
||||||
|
if ($input.length) {
|
||||||
|
$input.addClass('is-invalid');
|
||||||
|
$input.parent().append('<div class="invalid-feedback d-block fw-medium small">' + value[0] + '</div>');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$alertBox.html(`
|
||||||
|
<div class="alert alert-danger d-flex align-items-center py-2 px-3 small" role="alert">
|
||||||
|
<i class="bi bi-x-circle-fill me-2"></i>
|
||||||
|
<div>An error occurred. Please try again.</div>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
complete: function() {
|
||||||
|
$submitBtn.html(originalText).prop('disabled', false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Reset the form when the modal is closed
|
||||||
|
$('#addConnectionModal').on('hidden.bs.modal', function () {
|
||||||
|
$('#addConnectionForm')[0].reset();
|
||||||
|
$('#vpnFormContainer').hide();
|
||||||
|
$('#connectionModalAlert').html('');
|
||||||
|
$('#addConnectionForm').find('.is-invalid').removeClass('is-invalid');
|
||||||
|
$('#addConnectionForm').find('.invalid-feedback').remove();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endpush
|
||||||
@@ -27,6 +27,8 @@ Route::middleware(['auth'])->group(function () {
|
|||||||
Route::resource('clients', App\Http\Controllers\ClientsController::class);
|
Route::resource('clients', App\Http\Controllers\ClientsController::class);
|
||||||
|
|
||||||
#MNOs mnos.store
|
#MNOs mnos.store
|
||||||
|
Route::post('/mnos/{id}/connections', [App\Http\Controllers\NetworkOperatorsController::class, 'storeConnection'])->name('mnos.connections.store');
|
||||||
|
Route::delete('/mnos/connections/{id}', [App\Http\Controllers\NetworkOperatorsController::class, 'destroyConnection'])->name('mnos.connections.destroy');
|
||||||
Route::get('/mnos/{id}', [App\Http\Controllers\NetworkOperatorsController::class, 'show'])->name('mnos.show');
|
Route::get('/mnos/{id}', [App\Http\Controllers\NetworkOperatorsController::class, 'show'])->name('mnos.show');
|
||||||
Route::get('/mnos', [App\Http\Controllers\NetworkOperatorsController::class, 'index'])->name('mnos.index');
|
Route::get('/mnos', [App\Http\Controllers\NetworkOperatorsController::class, 'index'])->name('mnos.index');
|
||||||
Route::post('/mnos', [App\Http\Controllers\NetworkOperatorsController::class, 'store'])->name('mnos.store');
|
Route::post('/mnos', [App\Http\Controllers\NetworkOperatorsController::class, 'store'])->name('mnos.store');
|
||||||
|
|||||||
Reference in New Issue
Block a user