New Features: - USB Device checkout/check-in system with barcode scanning - displayusb.asp: List all USB devices with status - addusb.asp: Add new USB devices via barcode scan - checkout_usb.asp/savecheckout_usb.asp: Check out USB to SSO - checkin_usb.asp/savecheckin_usb.asp: Check in with wipe confirmation - usb_history.asp: Full checkout history with filters - api_usb.asp: JSON API for AJAX lookups - displayprofile.asp: SSO profile page showing user info and USB history - Date/time format changed to 12-hour (MM/DD/YYYY h:mm AM/PM) - SSO links in USB history now link to profile page via search Database: - New machinetypeid 44 for USB devices - New usb_checkouts table for tracking checkouts Cleanup: - Removed v2 folder (duplicate/old files) - Removed old debug/test files - Removed completed migration documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
404 lines
13 KiB
Plaintext
404 lines
13 KiB
Plaintext
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<!--#include file="./includes/header.asp"-->
|
|
<!--#include file="./includes/sql.asp"-->
|
|
<!-- DataTables CSS -->
|
|
<link rel="stylesheet" href="assets/plugins/datatables/dataTables.bootstrap4.min.css">
|
|
</head>
|
|
|
|
<%
|
|
theme = Request.Cookies("theme")
|
|
IF theme = "" THEN
|
|
theme="bg-theme1"
|
|
END IF
|
|
|
|
' Get SSO parameter
|
|
Dim ssoParam
|
|
ssoParam = Trim(Request.QueryString("sso"))
|
|
|
|
' Validate SSO - must be 9 digits
|
|
Dim validSSO
|
|
validSSO = False
|
|
If ssoParam <> "" And Len(ssoParam) = 9 And IsNumeric(ssoParam) Then
|
|
validSSO = True
|
|
End If
|
|
%>
|
|
|
|
<body class="bg-theme <%Response.Write(theme)%>">
|
|
|
|
<!-- start loader -->
|
|
<div id="pageloader-overlay" class="visible incoming"><div class="loader-wrapper-outer"><div class="loader-wrapper-inner" ><div class="loader"></div></div></div></div>
|
|
<!-- end loader -->
|
|
<!-- Start wrapper-->
|
|
<div id="wrapper">
|
|
<!--#include file="./includes/leftsidebar.asp"-->
|
|
<!--Start topbar header-->
|
|
<!--#include file="./includes/topbarheader.asp"-->
|
|
<!--End topbar header-->
|
|
<div class="clearfix"></div>
|
|
|
|
<div class="content-wrapper">
|
|
<div class="container-fluid">
|
|
|
|
<%
|
|
If Not validSSO Then
|
|
%>
|
|
<div class="row mt-3">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-body text-center">
|
|
<i class="zmdi zmdi-alert-circle zmdi-hc-4x text-warning"></i>
|
|
<h4 class="mt-3">Invalid SSO</h4>
|
|
<p class="text-muted">Please provide a valid 9-digit SSO number.</p>
|
|
<a href="./default.asp" class="btn btn-primary">Go to Dashboard</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<%
|
|
Else
|
|
' Look up person in appowners table
|
|
Dim cmdOwner, rsOwner, personName
|
|
Dim ownerSQL
|
|
ownerSQL = "SELECT appowner FROM appowners WHERE sso = ? AND isactive = 1"
|
|
|
|
Set cmdOwner = Server.CreateObject("ADODB.Command")
|
|
cmdOwner.ActiveConnection = objConn
|
|
cmdOwner.CommandText = ownerSQL
|
|
cmdOwner.CommandType = 1
|
|
cmdOwner.Parameters.Append cmdOwner.CreateParameter("@sso", 200, 1, 20, ssoParam)
|
|
|
|
Set rsOwner = cmdOwner.Execute
|
|
|
|
If Not rsOwner.EOF Then
|
|
personName = rsOwner("appowner") & ""
|
|
Else
|
|
personName = ""
|
|
End If
|
|
|
|
rsOwner.Close
|
|
Set rsOwner = Nothing
|
|
Set cmdOwner = Nothing
|
|
|
|
' Get USB checkout statistics
|
|
Dim cmdStats, rsStats
|
|
Dim totalCheckouts, activeCheckouts, avgDuration
|
|
Dim statsSQL
|
|
statsSQL = "SELECT " & _
|
|
"COUNT(*) AS total_checkouts, " & _
|
|
"SUM(CASE WHEN checkin_time IS NULL THEN 1 ELSE 0 END) AS active_checkouts, " & _
|
|
"AVG(TIMESTAMPDIFF(MINUTE, checkout_time, COALESCE(checkin_time, NOW()))) AS avg_duration " & _
|
|
"FROM usb_checkouts WHERE sso = ?"
|
|
|
|
Set cmdStats = Server.CreateObject("ADODB.Command")
|
|
cmdStats.ActiveConnection = objConn
|
|
cmdStats.CommandText = statsSQL
|
|
cmdStats.CommandType = 1
|
|
cmdStats.Parameters.Append cmdStats.CreateParameter("@sso", 200, 1, 20, ssoParam)
|
|
|
|
Set rsStats = cmdStats.Execute
|
|
|
|
If Not rsStats.EOF Then
|
|
If IsNull(rsStats("total_checkouts")) Or rsStats("total_checkouts") = "" Then
|
|
totalCheckouts = 0
|
|
Else
|
|
totalCheckouts = CLng(rsStats("total_checkouts"))
|
|
End If
|
|
|
|
If IsNull(rsStats("active_checkouts")) Or rsStats("active_checkouts") = "" Then
|
|
activeCheckouts = 0
|
|
Else
|
|
activeCheckouts = CLng(rsStats("active_checkouts"))
|
|
End If
|
|
|
|
If IsNull(rsStats("avg_duration")) Or rsStats("avg_duration") = "" Then
|
|
avgDuration = 0
|
|
Else
|
|
avgDuration = CLng(rsStats("avg_duration"))
|
|
End If
|
|
Else
|
|
totalCheckouts = 0
|
|
activeCheckouts = 0
|
|
avgDuration = 0
|
|
End If
|
|
|
|
rsStats.Close
|
|
Set rsStats = Nothing
|
|
Set cmdStats = Nothing
|
|
|
|
' Format average duration
|
|
Dim avgDurationText
|
|
If avgDuration < 60 Then
|
|
avgDurationText = avgDuration & " min"
|
|
ElseIf avgDuration < 1440 Then
|
|
avgDurationText = Int(avgDuration / 60) & "h " & (avgDuration Mod 60) & "m"
|
|
Else
|
|
avgDurationText = Int(avgDuration / 1440) & "d " & Int((avgDuration Mod 1440) / 60) & "h"
|
|
End If
|
|
%>
|
|
|
|
<div class="row mt-3">
|
|
<div class="col-12">
|
|
<!-- Profile Header -->
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div style="display: flex; align-items: center;">
|
|
<div style="width: 80px; height: 80px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 50%; display: flex; align-items: center; justify-content: center; margin-right: 20px;">
|
|
<i class="zmdi zmdi-account zmdi-hc-3x" style="color: white;"></i>
|
|
</div>
|
|
<div>
|
|
<% If personName <> "" Then %>
|
|
<h3 style="margin: 0;"><%=Server.HTMLEncode(personName)%></h3>
|
|
<p class="text-muted" style="margin: 5px 0 0 0;">SSO: <code><%=Server.HTMLEncode(ssoParam)%></code></p>
|
|
<% Else %>
|
|
<h3 style="margin: 0;">SSO: <code><%=Server.HTMLEncode(ssoParam)%></code></h3>
|
|
<p class="text-muted" style="margin: 5px 0 0 0;">User not found in directory</p>
|
|
<% End If %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mt-3">
|
|
<!-- USB Stats Cards -->
|
|
<div class="col-md-4">
|
|
<div class="card">
|
|
<div class="card-body text-center">
|
|
<i class="zmdi zmdi-usb zmdi-hc-3x text-primary"></i>
|
|
<h2 class="mt-2"><%=totalCheckouts%></h2>
|
|
<p class="text-muted">Total USB Checkouts</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="card">
|
|
<div class="card-body text-center">
|
|
<% If activeCheckouts > 0 Then %>
|
|
<i class="zmdi zmdi-time zmdi-hc-3x text-warning"></i>
|
|
<% Else %>
|
|
<i class="zmdi zmdi-check-circle zmdi-hc-3x text-success"></i>
|
|
<% End If %>
|
|
<h2 class="mt-2"><%=activeCheckouts%></h2>
|
|
<p class="text-muted">Currently Checked Out</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="card">
|
|
<div class="card-body text-center">
|
|
<i class="zmdi zmdi-timer zmdi-hc-3x text-info"></i>
|
|
<h2 class="mt-2"><%=avgDurationText%></h2>
|
|
<p class="text-muted">Avg Checkout Duration</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mt-3">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<h5 class="card-title">
|
|
<i class="zmdi zmdi-time"></i> USB Checkout History
|
|
</h5>
|
|
|
|
<div class="table-responsive">
|
|
<table id="historyTable" class="table table-hover table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th scope="col">USB Serial</th>
|
|
<th scope="col">USB Name</th>
|
|
<th scope="col">Checkout Time</th>
|
|
<th scope="col">Check-in Time</th>
|
|
<th scope="col">Duration</th>
|
|
<th scope="col">Wiped</th>
|
|
<th scope="col">Reason</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
|
|
<%
|
|
' Get USB checkout history for this SSO
|
|
Dim cmdHistory, rsHistory
|
|
Dim historySQL
|
|
historySQL = "SELECT uc.*, m.serialnumber, m.alias, " & _
|
|
"TIMESTAMPDIFF(MINUTE, uc.checkout_time, COALESCE(uc.checkin_time, NOW())) AS duration_minutes " & _
|
|
"FROM usb_checkouts uc " & _
|
|
"JOIN machines m ON uc.machineid = m.machineid " & _
|
|
"WHERE uc.sso = ? " & _
|
|
"ORDER BY uc.checkout_time DESC"
|
|
|
|
Set cmdHistory = Server.CreateObject("ADODB.Command")
|
|
cmdHistory.ActiveConnection = objConn
|
|
cmdHistory.CommandText = historySQL
|
|
cmdHistory.CommandType = 1
|
|
cmdHistory.Parameters.Append cmdHistory.CreateParameter("@sso", 200, 1, 20, ssoParam)
|
|
|
|
Set rsHistory = cmdHistory.Execute
|
|
|
|
Dim rowCount
|
|
rowCount = 0
|
|
|
|
While Not rsHistory.EOF
|
|
rowCount = rowCount + 1
|
|
Dim serialNum, usbAlias, checkoutTime, checkinTime, durationMinutes, reason
|
|
Dim durationText, wipedText, statusClass
|
|
|
|
serialNum = rsHistory("serialnumber") & ""
|
|
usbAlias = rsHistory("alias") & ""
|
|
reason = rsHistory("checkout_reason") & ""
|
|
|
|
If IsNull(rsHistory("duration_minutes")) Or rsHistory("duration_minutes") = "" Then
|
|
durationMinutes = 0
|
|
Else
|
|
durationMinutes = CLng(rsHistory("duration_minutes"))
|
|
End If
|
|
|
|
' Format checkout time (MM/DD/YYYY h:mm AM/PM)
|
|
If Not IsNull(rsHistory("checkout_time")) Then
|
|
checkoutTime = Month(rsHistory("checkout_time")) & "/" & Day(rsHistory("checkout_time")) & "/" & Year(rsHistory("checkout_time")) & " " & FormatDateTime(rsHistory("checkout_time"), 3)
|
|
Else
|
|
checkoutTime = "-"
|
|
End If
|
|
|
|
' Format check-in time and determine status (MM/DD/YYYY h:mm AM/PM)
|
|
If Not IsNull(rsHistory("checkin_time")) Then
|
|
checkinTime = Month(rsHistory("checkin_time")) & "/" & Day(rsHistory("checkin_time")) & "/" & Year(rsHistory("checkin_time")) & " " & FormatDateTime(rsHistory("checkin_time"), 3)
|
|
statusClass = ""
|
|
Else
|
|
checkinTime = "<span class='badge badge-warning'>Still Out</span>"
|
|
statusClass = "table-warning"
|
|
End If
|
|
|
|
' Format duration
|
|
If durationMinutes < 60 Then
|
|
durationText = durationMinutes & " min"
|
|
ElseIf durationMinutes < 1440 Then
|
|
durationText = Int(durationMinutes / 60) & "h " & (durationMinutes Mod 60) & "m"
|
|
Else
|
|
durationText = Int(durationMinutes / 1440) & "d " & Int((durationMinutes Mod 1440) / 60) & "h"
|
|
End If
|
|
|
|
' Format wiped status
|
|
If IsNull(rsHistory("was_wiped")) Then
|
|
wipedText = "-"
|
|
ElseIf rsHistory("was_wiped") = 1 Then
|
|
wipedText = "<span class='badge badge-success'>Yes</span>"
|
|
Else
|
|
wipedText = "<span class='badge badge-danger'>No</span>"
|
|
End If
|
|
%>
|
|
<tr class="<%=statusClass%>">
|
|
<td>
|
|
<a href="./usb_history.asp?machineid=<%=rsHistory("machineid")%>" title="View all checkouts for this device">
|
|
<code><%=Server.HTMLEncode(serialNum)%></code>
|
|
</a>
|
|
</td>
|
|
<td><%=Server.HTMLEncode(usbAlias)%></td>
|
|
<td><%=checkoutTime%></td>
|
|
<td><%=checkinTime%></td>
|
|
<td><%=durationText%></td>
|
|
<td><%=wipedText%></td>
|
|
<td>
|
|
<% If reason <> "" Then %>
|
|
<span title="<%=Server.HTMLEncode(reason)%>"><%=Server.HTMLEncode(Left(reason, 40))%><% If Len(reason) > 40 Then Response.Write("...") End If %></span>
|
|
<% Else %>
|
|
<span class="text-muted">-</span>
|
|
<% End If %>
|
|
</td>
|
|
</tr>
|
|
<%
|
|
rsHistory.MoveNext
|
|
Wend
|
|
|
|
rsHistory.Close
|
|
Set rsHistory = Nothing
|
|
Set cmdHistory = Nothing
|
|
|
|
If rowCount = 0 Then
|
|
%>
|
|
<tr>
|
|
<td colspan="7" class="text-center text-muted">
|
|
<i class="zmdi zmdi-info zmdi-hc-2x"></i><br>
|
|
No USB checkout history for this SSO.
|
|
</td>
|
|
</tr>
|
|
<%
|
|
End If
|
|
%>
|
|
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="mt-3">
|
|
<a href="./usb_history.asp?sso=<%=Server.URLEncode(ssoParam)%>" class="btn btn-outline-primary btn-sm">
|
|
<i class="zmdi zmdi-open-in-new"></i> View in Full History
|
|
</a>
|
|
<a href="./displayusb.asp" class="btn btn-outline-secondary btn-sm">
|
|
<i class="zmdi zmdi-usb"></i> USB Devices
|
|
</a>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<%
|
|
End If ' validSSO
|
|
%>
|
|
|
|
</div>
|
|
<!-- End container-fluid-->
|
|
</div><!--End content-wrapper-->
|
|
|
|
<!--Start Back To Top Button-->
|
|
<a href="javaScript:void();" class="back-to-top"><i class="fa fa-angle-double-up"></i> </a>
|
|
<!--End Back To Top Button-->
|
|
|
|
<!--Start footer-->
|
|
<footer class="footer">
|
|
<div class="container">
|
|
<div class="text-center">
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
<!--End footer-->
|
|
</div><!--End wrapper-->
|
|
|
|
<!-- Bootstrap core JavaScript-->
|
|
<script src="assets/js/jquery.min.js"></script>
|
|
<script src="assets/js/popper.min.js"></script>
|
|
<script src="assets/js/bootstrap.min.js"></script>
|
|
|
|
<!-- simplebar js -->
|
|
<script src="assets/plugins/simplebar/js/simplebar.js"></script>
|
|
<!-- sidebar-menu js -->
|
|
<script src="assets/js/sidebar-menu.js"></script>
|
|
|
|
<!-- DataTables js -->
|
|
<script src="assets/plugins/datatables/jquery.dataTables.min.js"></script>
|
|
<script src="assets/plugins/datatables/dataTables.bootstrap4.min.js"></script>
|
|
|
|
<!-- Custom scripts -->
|
|
<script src="assets/js/app-script.js"></script>
|
|
|
|
<script>
|
|
$(document).ready(function() {
|
|
$('#historyTable').DataTable({
|
|
"order": [[2, "desc"]], // Sort by checkout time descending
|
|
"pageLength": 25,
|
|
"language": {
|
|
"emptyTable": "No checkout history found"
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|