This commit is contained in:
usmannasir
2025-06-02 22:11:56 +05:00
parent 3d1b29bfec
commit 705c7c8f4d
4 changed files with 130 additions and 149 deletions

View File

@@ -869,10 +869,6 @@ app.controller('OnboardingCP', function ($scope, $http, $timeout, $window) {
});
app.controller('dashboardStatsController', function ($scope, $http, $timeout) {
// Defensive: force modal hidden on load
$scope.showSessionModal = false;
$timeout(function() { $scope.showSessionModal = false; }, 200);
// Card values
$scope.totalSites = 0;
$scope.totalWPSites = 0;
@@ -1201,54 +1197,41 @@ app.controller('dashboardStatsController', function ($scope, $http, $timeout) {
pollAll();
}, 500);
// User Session Modal logic
$scope.showSessionModal = false;
$scope.sessionUser = '';
$scope.sessionTTY = '';
$scope.sessionWOutput = '';
$scope.sessionTTYProcesses = '';
$scope.sessionProcesses = '';
$scope.sessionLoading = false;
$scope.sessionError = '';
$scope.showUserSession = function(login) {
$scope.sessionUser = login.user;
$scope.sessionTTY = login.tty || '';
$scope.sessionWOutput = '';
$scope.sessionTTYProcesses = '';
$scope.sessionProcesses = '';
$scope.sessionLoading = true;
$scope.sessionError = '';
$scope.showSessionModal = true;
var postData = { user: login.user };
// Try to extract tty from login.raw or login.tty if available
// SSH User Activity Modal
$scope.showSSHActivityModal = false;
$scope.sshActivity = { processes: [], w: [] };
$scope.sshActivityUser = '';
$scope.loadingSSHActivity = false;
$scope.errorSSHActivity = '';
$scope.viewSSHActivity = function(login) {
$scope.showSSHActivityModal = true;
$scope.sshActivity = { processes: [], w: [] };
$scope.sshActivityUser = login.user;
$scope.loadingSSHActivity = true;
$scope.errorSSHActivity = '';
var tty = '';
// Try to extract tty from login.raw or login.session if available
if (login.raw) {
var m = login.raw.match(/(pts\/[0-9]+)/);
if (m) postData.tty = m[1];
} else if (login.tty) {
postData.tty = login.tty;
var match = login.raw.match(/(pts\/[0-9]+)/);
if (match) tty = match[1];
}
$http.post('/baseTemplate/getSSHUserActivity', { user: login.user, tty: tty }).then(function(response) {
$scope.loadingSSHActivity = false;
if (response.data) {
$scope.sshActivity = response.data;
} else {
$scope.sshActivity = { processes: [], w: [] };
}
$http.post('/base/getUserSessionInfo', postData).then(function(response) {
$scope.sessionLoading = false;
var data = response.data;
$scope.sessionWOutput = data.w_output || '';
$scope.sessionTTYProcesses = data.tty_processes || '';
$scope.sessionProcesses = data.processes || '';
}, function(err) {
$scope.sessionLoading = false;
$scope.sessionError = (err.data && err.data.error) ? err.data.error : 'Failed to fetch session info.';
$scope.loadingSSHActivity = false;
$scope.errorSSHActivity = (err.data && err.data.error) ? err.data.error : 'Failed to fetch activity.';
});
};
$scope.closeSessionModal = function() {
$scope.showSessionModal = false;
$scope.sessionUser = '';
$scope.sessionTTY = '';
$scope.sessionWOutput = '';
$scope.sessionTTYProcesses = '';
$scope.sessionProcesses = '';
$scope.sessionLoading = false;
$scope.sessionError = '';
$timeout(function() { $scope.showSessionModal = false; }, 200);
$scope.closeSSHActivityModal = function() {
$scope.showSSHActivityModal = false;
$scope.sshActivity = { processes: [], w: [] };
$scope.sshActivityUser = '';
$scope.loadingSSHActivity = false;
$scope.errorSSHActivity = '';
};
});

View File

@@ -512,7 +512,7 @@
<th style="font-weight: 700; color: #4c5fad; background: #e3eafc;">Country</th>
<th style="font-weight: 700; color: #4c5fad; background: #e3eafc;">Date</th>
<th style="font-weight: 700; color: #4c5fad; background: #e3eafc;">Session</th>
<th style="font-weight: 700; color: #4c5fad; background: #e3eafc;">Actions</th>
<th style="font-weight: 700; color: #4c5fad; background: #e3eafc;">Activity</th>
</tr>
</thead>
<tbody>
@@ -523,9 +523,7 @@
<td style="padding: 8px 8px; font-family: 'Menlo', 'Monaco', 'Consolas', monospace;">{$ login.date $}</td>
<td style="padding: 8px 8px;">{$ login.session $}</td>
<td style="padding: 8px 8px;">
<button class="btn btn-xs btn-outline-primary view-session-btn" ng-click="showUserSession(login)" title="View Session" style="font-size: 0.98rem; font-weight: 600; border-radius: 16px; padding: 4px 14px; border: 2px solid #4c5fad; color: #4c5fad; background: #fff; transition: all 0.2s;">
<span style="font-size: 1.1rem; margin-right: 4px;">&#128065;</span> View Session
</button>
<button class="btn btn-xs btn-outline-primary" style="padding: 4px 12px; font-size: 0.95rem; border-radius: 14px; font-weight: 600;" ng-click="viewSSHActivity(login)">View Activity</button>
</td>
</tr>
</tbody>
@@ -1038,31 +1036,6 @@
.refresh-btn:hover .refresh-icon {
transform: rotate(360deg);
}
/* User Session Modal */
.view-session-btn:hover {
background: #4c5fad !important;
color: #fff !important;
border-color: #4c5fad !important;
transform: translateY(-2px);
box-shadow: 0 4px 15px rgba(76,95,173,0.10);
}
.modal.fade[ng-show] {
display: block !important;
opacity: 1;
pointer-events: auto;
z-index: 9999;
}
[ng-cloak] { display: none !important; }
.modal.fade[ng-show] {
display: block !important;
opacity: 1;
pointer-events: auto;
z-index: 9999;
transition: opacity 0.2s;
}
</style>
<!-- Chart.js (unchanged) -->
@@ -1118,35 +1091,42 @@
}, 100);
});
</script>
</div>
<!-- User Session Modal -->
<div id="userSessionModal" class="modal fade" tabindex="-1" role="dialog" ng-show="showSessionModal" ng-cloak style="background: rgba(44,62,80,0.25); transition: opacity 0.2s;">
<div class="modal-dialog modal-lg" role="document" style="max-width: 800px;">
<div class="modal-content" style="border-radius: 16px; box-shadow: 0 8px 32px rgba(44,62,80,0.18);">
<div class="modal-header" style="background: #4c5fad; color: #fff; border-radius: 16px 16px 0 0;">
<h5 class="modal-title" style="font-weight: 700;">User Session Info: <span style="font-family: monospace;">{$ sessionUser $}</span></h5>
<button type="button" class="close" ng-click="closeSessionModal()" style="color: #fff; font-size: 1.8rem; background: none; border: none; outline: none;">&times;</button>
<!-- Modal for SSH User Activity -->
<div ng-if="showSSHActivityModal" class="modal fade show" tabindex="-1" style="display: block; background: rgba(44,62,80,0.25); position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 9999;">
<div style="max-width: 540px; margin: 80px auto; background: #fff; border-radius: 16px; box-shadow: 0 8px 40px rgba(44,62,80,0.18); padding: 32px 28px 24px 28px; position: relative;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 18px;">
<div style="font-size: 1.2rem; font-weight: 800; color: #4c5fad; letter-spacing: 0.5px;">User Activity: <span style="color: #222;">{$ sshActivityUser $}</span></div>
<button class="btn btn-sm btn-outline-primary" style="border-radius: 12px; font-size: 1.1rem; padding: 2px 12px;" ng-click="closeSSHActivityModal()">&times;</button>
</div>
<div class="modal-body" style="background: #f8fafc; max-height: 500px; overflow-y: auto;">
<div ng-if="sessionLoading" style="color: #888; text-align: center; padding: 30px 0;">Loading session info...</div>
<div ng-if="sessionError" style="color: #e53935; padding: 10px 0;">{$ sessionError $}</div>
<div ng-if="!sessionLoading && !sessionError">
<div style="margin-bottom: 18px;">
<strong>TTY:</strong> <span style="font-family: monospace;">{$ sessionTTY $}</span>
</div>
<div style="margin-bottom: 18px;">
<strong>Current Command (w):</strong>
<pre style="background: #fff; border-radius: 8px; padding: 12px; font-size: 1rem; font-family: 'Menlo', 'Monaco', 'Consolas', monospace; color: #333;">{$ sessionWOutput $}</pre>
</div>
<div style="margin-bottom: 18px;">
<strong>TTY Processes:</strong>
<pre style="background: #fff; border-radius: 8px; padding: 12px; font-size: 1rem; font-family: 'Menlo', 'Monaco', 'Consolas', monospace; color: #333;">{$ sessionTTYProcesses $}</pre>
</div>
<div>
<strong>All User Processes:</strong>
<pre style="background: #fff; border-radius: 8px; padding: 12px; font-size: 1rem; font-family: 'Menlo', 'Monaco', 'Consolas', monospace; color: #333;">{$ sessionProcesses $}</pre>
<div ng-if="loadingSSHActivity" style="text-align: center; color: #888; padding: 20px 0;">Loading activity...</div>
<div ng-if="errorSSHActivity" style="color: #e53935; padding: 10px 0;">{$ errorSSHActivity $}</div>
<div ng-if="!loadingSSHActivity && !errorSSHActivity">
<div ng-if="sshActivity.processes.length === 0 && sshActivity.w.length === 0" style="text-align: center; color: #888; padding: 20px 0;">No active processes found for this user.</div>
<div ng-if="sshActivity.processes.length > 0">
<div style="font-weight: 700; color: #4c5fad; margin-bottom: 8px;">Processes:</div>
<table class="table table-sm" style="font-size: 0.98rem;">
<thead>
<tr style="background: #e3eafc;">
<th>PID</th>
<th>TTY</th>
<th>Time</th>
<th>Command</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="proc in sshActivity.processes">
<td style="font-family: 'Menlo', monospace;">{$ proc.pid $}</td>
<td style="font-family: 'Menlo', monospace;">{$ proc.tty $}</td>
<td style="font-family: 'Menlo', monospace;">{$ proc.time $}</td>
<td style="font-family: 'Menlo', monospace;">{$ proc.cmd $}</td>
</tr>
</tbody>
</table>
</div>
<div ng-if="sshActivity.w.length > 0">
<div style="font-weight: 700; color: #4c5fad; margin: 12px 0 8px 0;">w output:</div>
<pre style="background: #f8f9fa; border-radius: 8px; padding: 10px 12px; color: #333; font-size: 0.97rem;">{$ sshActivity.w.join('\n') $}</pre>
</div>
</div>
</div>

View File

@@ -21,5 +21,5 @@ urlpatterns = [
re_path(r'^getCPULoadGraph$', views.getCPULoadGraph, name='getCPULoadGraph'),
re_path(r'^getRecentSSHLogins$', views.getRecentSSHLogins, name='getRecentSSHLogins'),
re_path(r'^getRecentSSHLogs$', views.getRecentSSHLogs, name='getRecentSSHLogs'),
re_path(r'^getUserSessionInfo$', views.getUserSessionInfo, name='getUserSessionInfo'),
re_path(r'^getSSHUserActivity$', views.getSSHUserActivity, name='getSSHUserActivity'),
]

View File

@@ -628,7 +628,10 @@ def getRecentSSHLogs(request):
@csrf_exempt
@require_POST
def getUserSessionInfo(request):
def getSSHUserActivity(request):
import json
from plogical.ACLManager import ACLManager
from plogical.processUtilities import ProcessUtilities
try:
user_id = request.session.get('userID')
if not user_id:
@@ -636,26 +639,41 @@ def getUserSessionInfo(request):
currentACL = ACLManager.loadedACL(user_id)
if not currentACL.get('admin', 0):
return HttpResponse(json.dumps({'error': 'Admin only'}), content_type='application/json', status=403)
from plogical.processUtilities import ProcessUtilities
data = json.loads(request.body.decode('utf-8'))
user = data.get('user')
tty = data.get('tty')
if not user:
return HttpResponse(json.dumps({'error': 'Missing user'}), content_type='application/json', status=400)
result = {}
# Get processes for the user
ps_cmd = f"ps -u {user} -o pid,tty,time,cmd --no-headers"
try:
result['processes'] = ProcessUtilities.outputExecutioner(f'ps -u {user}')
ps_output = ProcessUtilities.outputExecutioner(ps_cmd)
except Exception as e:
result['processes'] = f'Error: {str(e)}'
if tty:
ps_output = ''
processes = []
if ps_output:
for line in ps_output.strip().split('\n'):
parts = line.split(None, 3)
if len(parts) == 4:
pid, tty_val, time_val, cmd = parts
if tty and tty not in tty_val:
continue
processes.append({
'pid': pid,
'tty': tty_val,
'time': time_val,
'cmd': cmd
})
# Optionally, get 'w' output for more info
w_cmd = f"w -h {user}"
try:
result['tty_processes'] = ProcessUtilities.outputExecutioner(f'ps -ft {tty}')
w_output = ProcessUtilities.outputExecutioner(w_cmd)
except Exception as e:
result['tty_processes'] = f'Error: {str(e)}'
try:
result['w_output'] = ProcessUtilities.outputExecutioner(f'w -h {user}')
except Exception as e:
result['w_output'] = f'Error: {str(e)}'
return HttpResponse(json.dumps(result), content_type='application/json')
w_output = ''
w_lines = []
if w_output:
for line in w_output.strip().split('\n'):
w_lines.append(line)
return HttpResponse(json.dumps({'processes': processes, 'w': w_lines}), content_type='application/json')
except Exception as e:
return HttpResponse(json.dumps({'error': str(e)}), content_type='application/json', status=500)