@@ -49,83 +49,6 @@ async function connectMikroTik() {
49
49
}
50
50
}
51
51
52
- async function getAllUsers ( ) {
53
- try {
54
- await connectMikroTik ( ) ;
55
- const users = await connection . write ( "/ip/hotspot/user/print" ) ;
56
- return users . map ( ( user ) => ( {
57
- username : user . name ,
58
- profile : user . profile ,
59
- uptime : user . uptime ,
60
- bytesIn : user [ "bytes-in" ] ,
61
- bytesOut : user [ "bytes-out" ] ,
62
- disabled : user . disabled === "true" ,
63
- comment : user . comment || "" ,
64
- limitBytesIn : user [ "limit-bytes-in" ] ,
65
- limitBytesOut : user [ "limit-bytes-out" ] ,
66
- } ) ) ;
67
- } catch ( error ) {
68
- console . error ( "Error fetching users:" , error ) ;
69
- return [ ] ;
70
- }
71
- }
72
-
73
- // Get user details by username
74
- async function getUserDetails ( username ) {
75
- try {
76
- await connectMikroTik ( ) ;
77
- const user = await connection . write ( "/ip/hotspot/user/print" , [
78
- "=.proplist=name,profile,uptime,bytes-in,bytes-out,disabled,comment,limit-bytes-in,limit-bytes-out,last-logged-out" ,
79
- "?name=" + username ,
80
- ] ) ;
81
-
82
- if ( user . length === 0 ) {
83
- return null ;
84
- }
85
-
86
- // Get active sessions for the user
87
- const activeSessions = await connection . write ( "/ip/hotspot/active/print" , [
88
- "?user=" + username ,
89
- ] ) ;
90
-
91
- // Get user's connection history
92
- const history = await connection . write ( "/ip/hotspot/host/print" , [
93
- "?user=" + username ,
94
- ] ) ;
95
-
96
- return {
97
- basicInfo : {
98
- username : user [ 0 ] . name ,
99
- profile : user [ 0 ] . profile ,
100
- uptime : user [ 0 ] . uptime ,
101
- bytesIn : user [ 0 ] [ "bytes-in" ] ,
102
- bytesOut : user [ 0 ] [ "bytes-out" ] ,
103
- disabled : user [ 0 ] . disabled === "true" ,
104
- comment : user [ 0 ] . comment || "" ,
105
- limitBytesIn : user [ 0 ] [ "limit-bytes-in" ] ,
106
- limitBytesOut : user [ 0 ] [ "limit-bytes-out" ] ,
107
- lastLoggedOut : user [ 0 ] [ "last-logged-out" ] ,
108
- } ,
109
- activeSessions : activeSessions . map ( ( session ) => ( {
110
- ipAddress : session . address ,
111
- macAddress : session [ "mac-address" ] ,
112
- loginTime : session [ "login-by" ] ,
113
- uptime : session . uptime ,
114
- sessionId : session [ ".id" ] ,
115
- } ) ) ,
116
- connectionHistory : history . map ( ( entry ) => ( {
117
- ipAddress : entry . address ,
118
- macAddress : entry [ "mac-address" ] ,
119
- lastSeen : entry [ "last-seen" ] ,
120
- status : entry . status ,
121
- } ) ) ,
122
- } ;
123
- } catch ( error ) {
124
- console . error ( "Error fetching user details:" , error ) ;
125
- return null ;
126
- }
127
- }
128
-
129
52
// Get active IP addresses
130
53
async function getActiveIPs ( ) {
131
54
try {
@@ -234,28 +157,201 @@ app.get("/api/logs/all", async (req, res) => {
234
157
}
235
158
} ) ;
236
159
160
+ function formatUptime ( uptime ) {
161
+ if ( ! uptime ) return 0 ;
162
+ // Convert RouterOS uptime format to seconds
163
+ const parts = uptime . split ( / [ w h m s ] / ) ;
164
+ const units = uptime . match ( / [ w h m s ] / g) ;
165
+ let seconds = 0 ;
166
+
167
+ if ( ! parts || ! units ) return 0 ;
168
+
169
+ parts . forEach ( ( part , i ) => {
170
+ if ( ! part ) return ;
171
+ switch ( units [ i ] ) {
172
+ case "w" :
173
+ seconds += parseInt ( part ) * 7 * 24 * 3600 ;
174
+ break ;
175
+ case "h" :
176
+ seconds += parseInt ( part ) * 3600 ;
177
+ break ;
178
+ case "m" :
179
+ seconds += parseInt ( part ) * 60 ;
180
+ break ;
181
+ case "s" :
182
+ seconds += parseInt ( part ) ;
183
+ break ;
184
+ }
185
+ } ) ;
186
+
187
+ return seconds ;
188
+ }
189
+
190
+ function formatBytes ( bytes ) {
191
+ if ( ! bytes ) return '0' ;
192
+ return parseInt ( bytes ) ;
193
+ }
194
+
237
195
app . get ( "/api/users" , async ( req , res ) => {
238
196
try {
239
- const users = await getAllUsers ( ) ;
240
- res . json ( users ) ;
197
+ await connectMikroTik ( ) ;
198
+
199
+ // Get all users
200
+ const users = await connection . write ( "/ip/hotspot/user/print" ) ;
201
+
202
+ // Get active sessions for correlation
203
+ const activeSessions = await connection . write ( "/ip/hotspot/active/print" ) ;
204
+
205
+ const formattedUsers = users . map ( ( user ) => {
206
+ // Find active sessions for this user
207
+ const userSessions = activeSessions . filter (
208
+ ( session ) => session . user === user . name
209
+ ) ;
210
+
211
+ return {
212
+ username : user . name ,
213
+ profile : user . profile ,
214
+ uptime : formatUptime ( user . uptime ) ,
215
+ bytesIn : formatBytes ( user [ "bytes-in" ] ) ,
216
+ bytesOut : formatBytes ( user [ "bytes-out" ] ) ,
217
+ disabled : user . disabled === "true" ,
218
+ comment : user . comment || "" ,
219
+ limitBytesIn : formatBytes ( user [ "limit-bytes-in" ] ) ,
220
+ limitBytesOut : formatBytes ( user [ "limit-bytes-out" ] ) ,
221
+ isOnline : userSessions . length > 0 ,
222
+ activeSessions : userSessions . length ,
223
+ } ;
224
+ } ) ;
225
+
226
+ res . json ( formattedUsers ) ;
241
227
} catch ( error ) {
228
+ console . error ( "Error fetching users:" , error ) ;
242
229
res . status ( 500 ) . json ( { error : "Failed to fetch users" } ) ;
243
230
}
244
231
} ) ;
245
232
233
+ // Get user details
246
234
app . get ( "/api/users/:username" , async ( req , res ) => {
247
235
try {
248
- const userDetails = await getUserDetails ( req . params . username ) ;
249
- if ( ! userDetails ) {
236
+ await connectMikroTik ( ) ;
237
+ const username = req . params . username ;
238
+
239
+ // Get user basic info
240
+ const user = await connection . write ( "/ip/hotspot/user/print" , [
241
+ "=.proplist=name,profile,uptime,bytes-in,bytes-out,disabled,comment,limit-bytes-in,limit-bytes-out,last-logged-out" ,
242
+ "?name=" + username ,
243
+ ] ) ;
244
+
245
+ if ( user . length === 0 ) {
250
246
res . status ( 404 ) . json ( { error : "User not found" } ) ;
251
247
return ;
252
248
}
249
+
250
+ // Get active sessions
251
+ const activeSessions = await connection . write ( "/ip/hotspot/active/print" , [
252
+ "?user=" + username ,
253
+ ] ) ;
254
+
255
+ // Get connection history
256
+ const history = await connection . write ( "/ip/hotspot/host/print" , [
257
+ "?user=" + username ,
258
+ ] ) ;
259
+
260
+ const userDetails = {
261
+ basicInfo : {
262
+ username : user [ 0 ] . name ,
263
+ profile : user [ 0 ] . profile ,
264
+ uptime : formatUptime ( user [ 0 ] . uptime ) ,
265
+ bytesIn : formatBytes ( user [ 0 ] [ "bytes-in" ] ) ,
266
+ bytesOut : formatBytes ( user [ 0 ] [ "bytes-out" ] ) ,
267
+ disabled : user [ 0 ] . disabled === "true" ,
268
+ comment : user [ 0 ] . comment || "" ,
269
+ limitBytesIn : formatBytes ( user [ 0 ] [ "limit-bytes-in" ] ) ,
270
+ limitBytesOut : formatBytes ( user [ 0 ] [ "limit-bytes-out" ] ) ,
271
+ lastLoggedOut : user [ 0 ] [ "last-logged-out" ] || null ,
272
+ } ,
273
+ activeSessions : activeSessions . map ( ( session ) => ( {
274
+ ipAddress : session . address ,
275
+ macAddress : session [ "mac-address" ] ,
276
+ loginTime : session [ "login-by" ] ,
277
+ uptime : formatUptime ( session . uptime ) ,
278
+ sessionId : session [ ".id" ] ,
279
+ bytesIn : formatBytes ( session [ "bytes-in" ] ) ,
280
+ bytesOut : formatBytes ( session [ "bytes-out" ] ) ,
281
+ } ) ) ,
282
+ connectionHistory : history . map ( ( entry ) => ( {
283
+ ipAddress : entry . address ,
284
+ macAddress : entry [ "mac-address" ] ,
285
+ lastSeen : entry [ "last-seen" ] ,
286
+ status : entry . status ,
287
+ host : entry . host ,
288
+ bytesIn : formatBytes ( entry [ "bytes-in" ] ) ,
289
+ bytesOut : formatBytes ( entry [ "bytes-out" ] ) ,
290
+ } ) ) ,
291
+ } ;
292
+
253
293
res . json ( userDetails ) ;
254
294
} catch ( error ) {
295
+ console . error ( "Error fetching user details:" , error ) ;
255
296
res . status ( 500 ) . json ( { error : "Failed to fetch user details" } ) ;
256
297
}
257
298
} ) ;
258
299
300
+ // User management endpoints
301
+ // Enable/Disable user
302
+ app . post ( "/api/users/:username/toggle" , async ( req , res ) => {
303
+ try {
304
+ await connectMikroTik ( ) ;
305
+ const username = req . params . username ;
306
+
307
+ const user = await connection . write ( "/ip/hotspot/user/print" , [
308
+ "?name=" + username ,
309
+ ] ) ;
310
+
311
+ if ( user . length === 0 ) {
312
+ res . status ( 404 ) . json ( { error : "User not found" } ) ;
313
+ return ;
314
+ }
315
+
316
+ const currentState = user [ 0 ] . disabled === "true" ;
317
+ await connection . write ( "/ip/hotspot/user/set" , [
318
+ "=.id=" + user [ 0 ] [ ".id" ] ,
319
+ "=disabled=" + ! currentState ,
320
+ ] ) ;
321
+
322
+ res . json ( { success : true , disabled : ! currentState } ) ;
323
+ } catch ( error ) {
324
+ console . error ( "Error toggling user state:" , error ) ;
325
+ res . status ( 500 ) . json ( { error : "Failed to toggle user state" } ) ;
326
+ }
327
+ } ) ;
328
+
329
+ // Delete user
330
+ app . delete ( "/api/users/:username" , async ( req , res ) => {
331
+ try {
332
+ await connectMikroTik ( ) ;
333
+ const username = req . params . username ;
334
+
335
+ const user = await connection . write ( "/ip/hotspot/user/print" , [
336
+ "?name=" + username ,
337
+ ] ) ;
338
+
339
+ if ( user . length === 0 ) {
340
+ res . status ( 404 ) . json ( { error : "User not found" } ) ;
341
+ return ;
342
+ }
343
+
344
+ await connection . write ( "/ip/hotspot/user/remove" , [
345
+ "=.id=" + user [ 0 ] [ ".id" ] ,
346
+ ] ) ;
347
+
348
+ res . json ( { success : true } ) ;
349
+ } catch ( error ) {
350
+ console . error ( "Error deleting user:" , error ) ;
351
+ res . status ( 500 ) . json ( { error : "Failed to delete user" } ) ;
352
+ }
353
+ } ) ;
354
+
259
355
// REST endpoint for initial data
260
356
app . get ( "/api/network-data" , async ( req , res ) => {
261
357
try {
0 commit comments