added new radius module
This commit is contained in:
@@ -134,6 +134,7 @@
|
||||
<?php if($me->isAdmin()) : ?><li><a href="<?=self::getUrl("IpNetwork")?>"><i class="fa-solid fa-network-wired text-info"></i> IPAM</a></li><?php endif; ?>
|
||||
<?php if($me->isAdmin()) : ?><li><a href="<?=self::getUrl("DeviceMonitoring/congestion")?>"><i class="fa-solid fa-block-brick-fire text-info"></i> Device Congestion</a></li><?php endif; ?>
|
||||
<?php if($me->isAdmin()) : ?><li><a href="<?=self::getUrl("MaintenanceNotification")?>"><i class="fa-solid fa-envelope-badge text-info"></i> Wartungsmeldungen</a></li><?php endif; ?>
|
||||
<?php if($me->isAdmin()) : ?><li><a href="<?=self::getUrl("Radius")?>"><i class="fas fa-broadcast-tower text-info"></i> Radius</a></li><?php endif; ?>
|
||||
</ul>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
|
||||
22
application/Radius/RadiusController.php
Normal file
22
application/Radius/RadiusController.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
class RadiusController extends mfBaseController {
|
||||
private User $me;
|
||||
|
||||
protected function init(): void {
|
||||
$this->needlogin=true;
|
||||
$me = new User();
|
||||
$me->loadMe();
|
||||
$this->layout()->set("me", $me);
|
||||
$this->me = $me;
|
||||
|
||||
if (!$this->me->is("Admin")) $this->redirect("Dashboard");
|
||||
}
|
||||
|
||||
protected function indexAction() {
|
||||
$this->layout()->set('additionalJS', ["plugins/chart.js/chart.4.4.6.js", "plugins/chart.js/chartjs-adapter-moment.min.js"]);
|
||||
Helper::renderVue($this, $this->mod, "Radius", []);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
55
public/js/pages/Radius/Radius.css
Normal file
55
public/js/pages/Radius/Radius.css
Normal file
@@ -0,0 +1,55 @@
|
||||
.radius-view-selector {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, max-content));
|
||||
grid-gap: 10px;
|
||||
justify-content: start;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.radius-view-selector {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.filters {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
grid-gap: 15px;
|
||||
margin-bottom: 20px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.status-dot {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.status-dot.online {
|
||||
background-color: green;
|
||||
}
|
||||
|
||||
.status-dot.offline {
|
||||
background-color: grey;
|
||||
}
|
||||
|
||||
.free-users-container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-gap: 20px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.free-users-container {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.free-users-column {
|
||||
background-color: #f8f9fa;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
229
public/js/pages/Radius/Radius.js
Normal file
229
public/js/pages/Radius/Radius.js
Normal file
@@ -0,0 +1,229 @@
|
||||
Vue.component('radius', {
|
||||
template: `
|
||||
<tt-card>
|
||||
<template v-slot:header>
|
||||
<h3>Radius</h3>
|
||||
</template>
|
||||
|
||||
<div class="radius-view-selector">
|
||||
<tt-button
|
||||
icon="fas fa-user"
|
||||
additional-class="btn-primary"
|
||||
text="Radius Benutzer"
|
||||
@click="view = 'radius'"
|
||||
></tt-button>
|
||||
<tt-button
|
||||
icon="fas fa-user-plus"
|
||||
additional-class="btn-primary"
|
||||
text="Freie Radius Benutzer"
|
||||
@click="view = 'free'"
|
||||
></tt-button>
|
||||
</div>
|
||||
|
||||
<div v-if="view === 'radius'">
|
||||
<div class="filters">
|
||||
<tt-autocomplete sm :api-url="billAddrAutoCompleteUrl" label="Rechnungsadresse" v-model="custnum" ref="billAddr"/>
|
||||
<tt-input sm label="Username" name="username" v-model="username"/>
|
||||
<tt-input sm label="Info" name="info" v-model="info"/>
|
||||
<tt-button sm icon="fas fa-search" text="Suchen" additional-class="btn-primary" style="justify-self:center" @click="loadRadiusUsers"/>
|
||||
</div>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Kundennummer</th>
|
||||
<th>Username</th>
|
||||
<th>Info</th>
|
||||
<th>Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="user in radiusUsers" :key="user.id">
|
||||
<td>
|
||||
<a target="_blank" :href="window['TT_CONFIG']['BASE_PATH'] + '/Address?filter%5Bcustomer_number%5D=' + user.customerNumber">
|
||||
{{ user.customerNumber }}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a target="_blank" :href="'http://radius.xinon.at/edit_user.php?user=' + user.username">
|
||||
{{ user.username }}
|
||||
</a>
|
||||
</td>
|
||||
<td>{{ user.info }}</td>
|
||||
<td>
|
||||
<tt-button sm icon="fas fa-sync" text="Fetch" @click="fetchRadacctData(user.username)" additional-class="btn-primary"/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div v-if="view === 'free'" class="free-users-container">
|
||||
<div class="free-users-column">
|
||||
<h4>Freie NAT Benutzer ({{ freeNatUsers.length }})</h4>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Username</th>
|
||||
<th>Info</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="user in freeNatUsers" :key="user.id">
|
||||
<td>{{ user.username }}</td>
|
||||
<td>{{ user.info }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="free-users-column">
|
||||
<h4>Freie STF Benutzer ({{ freeStfUsers.length }})</h4>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Username</th>
|
||||
<th>Info</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="user in freeStfUsers" :key="user.id">
|
||||
<td>{{ user.username }}</td>
|
||||
<td>{{ user.info }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<tt-modal :show.sync="showRadacctModal" title="Radacct Data" :save="false" :delete="false">
|
||||
<div v-if="radacctData">
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>Status:</th>
|
||||
<td><span :class="['status-dot', radacctData.online ? 'online' : 'offline']"></span> {{ radacctData.online ? 'Online' : 'Offline' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>IP:</th>
|
||||
<td>{{ radacctData.ip }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Username:</th>
|
||||
<td><a target="_blank" :href="'http://radius.xinon.at/edit_user.php?user=' + radacctData.username">{{ radacctData.username }}</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Customer Number:</th>
|
||||
<td>{{ radacctData.customerNumber }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Customer Name:</th>
|
||||
<td>{{ radacctData.customerName }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Info:</th>
|
||||
<td>{{ radacctData.info }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>WLAN Password:</th>
|
||||
<td>{{ radacctData.wlanPassword }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Bandbreite:</th>
|
||||
<td>{{ radacctData.actualBandwidth }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</tt-modal>
|
||||
</tt-card>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
view: 'radius',
|
||||
billAddrAutoCompleteUrl: window.TT_CONFIG['BASE_PATH'] + '/Address/Api?do=findAddress&fibu_primary_account=1',
|
||||
radiusUsers: [],
|
||||
freeNatUsers: [],
|
||||
freeStfUsers: [],
|
||||
username: '',
|
||||
info: '',
|
||||
custnum: '',
|
||||
window: window,
|
||||
showRadacctModal: false,
|
||||
radacctData: null,
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
await this.loadFreeUsers();
|
||||
},
|
||||
methods: {
|
||||
hideRadacctModal() {
|
||||
console.log('hideRadacctModal');
|
||||
this.showRadacctModal = false;
|
||||
},
|
||||
async loadRadiusUsers() {
|
||||
let custnum = '';
|
||||
if (this.$refs.billAddr.displayValue.length > 5) {
|
||||
custnum = this.$refs.billAddr.displayValue.match(/\[(\d+)\]/)[1];
|
||||
}
|
||||
|
||||
const params = new URLSearchParams({
|
||||
username: this.username,
|
||||
info: this.info,
|
||||
custnum: custnum,
|
||||
});
|
||||
const response = await fetch(`http://radius.xinon.at/api.php?${params.toString()}`, {
|
||||
headers: {
|
||||
'Authorization': 'Basic ' + btoa('admin:saveman')
|
||||
}
|
||||
});
|
||||
if (response.ok) {
|
||||
this.radiusUsers = await response.json();
|
||||
} else {
|
||||
console.error('Failed to load radius users');
|
||||
}
|
||||
},
|
||||
async fetchRadacctData(username) {
|
||||
const params = new URLSearchParams({
|
||||
action: 'fetchRadacct',
|
||||
username: username,
|
||||
});
|
||||
const response = await fetch(`http://radius.xinon.at/api.php?${params.toString()}`, {
|
||||
headers: {
|
||||
'Authorization': 'Basic ' + btoa('admin:saveman')
|
||||
}
|
||||
});
|
||||
if (response.ok) {
|
||||
this.radacctData = await response.json();
|
||||
this.showRadacctModal = true;
|
||||
} else {
|
||||
console.error('Failed to fetch radacct data');
|
||||
}
|
||||
},
|
||||
async loadFreeUsers() {
|
||||
try {
|
||||
const natResponse = await fetch('http://radius.xinon.at/api.php?action=free_user&filter=nat', {
|
||||
headers: {
|
||||
'Authorization': 'Basic ' + btoa('admin:saveman')
|
||||
}
|
||||
});
|
||||
const stfResponse = await fetch('http://radius.xinon.at/api.php?action=free_user&filter=stf', {
|
||||
headers: {
|
||||
'Authorization': 'Basic ' + btoa('admin:saveman')
|
||||
}
|
||||
});
|
||||
|
||||
if (natResponse.ok && stfResponse.ok) {
|
||||
const natData = await natResponse.json();
|
||||
const stfData = await stfResponse.json();
|
||||
|
||||
this.freeNatUsers = natData.users;
|
||||
this.freeStfUsers = stfData.users;
|
||||
} else {
|
||||
console.error('Failed to load free users');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading free users:', error);
|
||||
}
|
||||
|
||||
},
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user