eDNC: Use machineid instead of hostname for proper FK relationship

- ednclogs table now uses machineid to link to machines table
- Removed redundant hostname storage (derive from machines table)
- Updated LogDNCEvent to look up and insert machineid
- Updated GetDNCStats to join machines table for hostname
- Updated displaypc.asp queries to use machineid directly
- sql/ednc_tables.sql is now a migration script for existing production

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
cproudlock
2025-12-12 09:33:27 -05:00
parent 4441dde2e8
commit a1a10a51d2
3 changed files with 92 additions and 132 deletions

117
api.asp
View File

@@ -2553,15 +2553,13 @@ Sub LogDNCEvent()
On Error Resume Next
' Get parameters
Dim hostname, filename, eventAction, bytesRemoved, version, message, watchFolder, fileFilter
Dim hostname, filename, eventAction, bytesRemoved, version, message
hostname = Trim(Request.Form("hostname") & "")
filename = Trim(Request.Form("filename") & "")
eventAction = Trim(Request.Form("eventType") & "")
bytesRemoved = Request.Form("bytesRemoved")
version = Trim(Request.Form("version") & "")
message = Trim(Request.Form("message") & "")
watchFolder = Trim(Request.Form("watchFolder") & "")
fileFilter = Trim(Request.Form("fileFilter") & "")
' Validate required fields
If hostname = "" Or eventAction = "" Then
@@ -2569,23 +2567,36 @@ Sub LogDNCEvent()
Exit Sub
End If
' Sanitize inputs
Dim safeHostname, safeFilename, safeAction, safeVersion, safeMessage, safeWatchFolder, safeFileFilter
' Default bytesRemoved to 0 if not numeric
If Not IsNumeric(bytesRemoved) Or bytesRemoved = "" Then bytesRemoved = 0
' Get machineid from hostname (required for logging)
Dim safeHostname, machineid, rsLookup
safeHostname = Replace(hostname, "'", "''")
Set rsLookup = objConn.Execute("SELECT machineid FROM machines WHERE UPPER(hostname) = UPPER('" & safeHostname & "') AND pctypeid IS NOT NULL LIMIT 1")
If rsLookup.EOF Then
rsLookup.Close
Set rsLookup = Nothing
SendError "Unknown hostname: " & hostname
Exit Sub
End If
machineid = CLng(rsLookup("machineid"))
rsLookup.Close
Set rsLookup = Nothing
' Sanitize remaining inputs
Dim safeFilename, safeAction, safeVersion, safeMessage
safeFilename = Replace(filename, "'", "''")
safeAction = Replace(eventAction, "'", "''")
safeVersion = Replace(version, "'", "''")
safeMessage = Replace(message, "'", "''")
safeWatchFolder = Replace(watchFolder, "'", "''")
safeFileFilter = Replace(fileFilter, "'", "''")
' Default bytesRemoved to 0 if not numeric
If Not IsNumeric(bytesRemoved) Or bytesRemoved = "" Then bytesRemoved = 0
' Insert log entry
' Insert log entry using machineid
Dim insertSQL
insertSQL = "INSERT INTO ednc_logs (hostname, filename, action, bytes_removed, version, message) " & _
"VALUES ('" & safeHostname & "', '" & safeFilename & "', '" & safeAction & "', " & _
insertSQL = "INSERT INTO ednclogs (machineid, filename, action, bytes_removed, version, message) " & _
"VALUES (" & machineid & ", '" & safeFilename & "', '" & safeAction & "', " & _
CLng(bytesRemoved) & ", '" & safeVersion & "', '" & safeMessage & "')"
objConn.Execute insertSQL
@@ -2594,52 +2605,18 @@ Sub LogDNCEvent()
Exit Sub
End If
' Update or insert installation record
Dim checkSQL, rsCheck
checkSQL = "SELECT installid, total_cleaned, total_failed FROM ednc_installations WHERE hostname = '" & safeHostname & "'"
Set rsCheck = objConn.Execute(checkSQL)
' Track in installedapps (appid 79 = eDNC Special Character Fix)
Dim edncAppId, rsApp
edncAppId = 79
If rsCheck.EOF Then
' New installation - INSERT
Dim installSQL
installSQL = "INSERT INTO ednc_installations (hostname, version, watch_folder, file_filter, total_cleaned, total_failed) " & _
"VALUES ('" & safeHostname & "', '" & safeVersion & "', '" & safeWatchFolder & "', '" & safeFileFilter & "', "
If eventAction = "cleaned" Then
installSQL = installSQL & "1, 0)"
ElseIf eventAction = "failed" Or eventAction = "error" Then
installSQL = installSQL & "0, 1)"
Else
installSQL = installSQL & "0, 0)"
' Check if already in installedapps
Set rsApp = objConn.Execute("SELECT installedappid FROM installedapps WHERE machineid = " & machineid & " AND appid = " & edncAppId)
If rsApp.EOF Then
' Insert new record
objConn.Execute "INSERT INTO installedapps (appid, machineid, isactive) VALUES (" & edncAppId & ", " & machineid & ", 1)"
End If
objConn.Execute installSQL
Else
' Existing installation - UPDATE
Dim totalCleaned, totalFailed, updateSQL
totalCleaned = CLng(rsCheck("total_cleaned"))
totalFailed = CLng(rsCheck("total_failed"))
If eventAction = "cleaned" Then
totalCleaned = totalCleaned + 1
ElseIf eventAction = "failed" Or eventAction = "error" Then
totalFailed = totalFailed + 1
End If
updateSQL = "UPDATE ednc_installations SET " & _
"version = '" & safeVersion & "', " & _
"last_seen = NOW(), " & _
"total_cleaned = " & totalCleaned & ", " & _
"total_failed = " & totalFailed
If safeWatchFolder <> "" Then
updateSQL = updateSQL & ", watch_folder = '" & safeWatchFolder & "'"
End If
If safeFileFilter <> "" Then
updateSQL = updateSQL & ", file_filter = '" & safeFileFilter & "'"
End If
updateSQL = updateSQL & " WHERE hostname = '" & safeHostname & "'"
objConn.Execute updateSQL
End If
rsCheck.Close
Set rsCheck = Nothing
rsApp.Close
Set rsApp = Nothing
' Send success response
Response.Write "{""success"":true,""message"":""Event logged""}"
@@ -2648,12 +2625,19 @@ End Sub
Sub GetDNCStats()
On Error Resume Next
' Get installations with recent activity
' Get stats derived from ednclogs, joined to machines for hostname
Dim sql, rs
sql = "SELECT i.hostname, i.version, i.watch_folder, i.file_filter, " & _
"i.first_seen, i.last_seen, i.is_active, i.total_cleaned, i.total_failed, " & _
"(SELECT COUNT(*) FROM ednc_logs l WHERE l.hostname = i.hostname AND l.created > DATE_SUB(NOW(), INTERVAL 24 HOUR)) AS events_24h " & _
"FROM ednc_installations i ORDER BY i.last_seen DESC"
sql = "SELECT m.hostname, " & _
"(SELECT version FROM ednclogs WHERE machineid = l.machineid ORDER BY created DESC LIMIT 1) AS version, " & _
"MIN(l.created) AS first_seen, " & _
"MAX(l.created) AS last_seen, " & _
"SUM(CASE WHEN l.action = 'cleaned' THEN 1 ELSE 0 END) AS total_cleaned, " & _
"SUM(CASE WHEN l.action = 'failed' THEN 1 ELSE 0 END) AS total_failed, " & _
"(SELECT COUNT(*) FROM ednclogs WHERE machineid = l.machineid AND created > DATE_SUB(NOW(), INTERVAL 24 HOUR)) AS events_24h " & _
"FROM ednclogs l " & _
"INNER JOIN machines m ON l.machineid = m.machineid " & _
"GROUP BY l.machineid, m.hostname " & _
"ORDER BY last_seen DESC"
Set rs = objConn.Execute(sql)
@@ -2674,14 +2658,11 @@ Sub GetDNCStats()
json = json & "{" & _
"""hostname"":""" & (rs("hostname") & "") & """," & _
"""version"":""" & (rs("version") & "") & """," & _
"""watchFolder"":""" & Replace(rs("watch_folder") & "", "\", "\\") & """," & _
"""fileFilter"":""" & (rs("file_filter") & "") & """," & _
"""firstSeen"":""" & (rs("first_seen") & "") & """," & _
"""lastSeen"":""" & (rs("last_seen") & "") & """," & _
"""isActive"":" & rs("is_active") & "," & _
"""totalCleaned"":" & rs("total_cleaned") & "," & _
"""totalFailed"":" & rs("total_failed") & "," & _
"""events24h"":" & rs("events_24h") & _
"""totalCleaned"":" & (rs("total_cleaned") + 0) & "," & _
"""totalFailed"":" & (rs("total_failed") + 0) & "," & _
"""events24h"":" & (rs("events_24h") + 0) & _
"}"
rs.MoveNext
Loop

View File

@@ -737,19 +737,21 @@ End If
<!-- eDNC Special Character Fix Stats -->
<%
'=============================================================================
' eDNC-Fix Installation Stats for this PC
' eDNC-Fix Installation Stats for this PC (derived from ednclogs)
'=============================================================================
Dim edncSQL, rsEdnc, hasEdnc
hasEdnc = False
edncSQL = "SELECT i.version, i.watch_folder, i.file_filter, i.first_seen, i.last_seen, " & _
"i.total_cleaned, i.total_failed, " & _
"(SELECT COUNT(*) FROM ednc_logs l WHERE l.hostname = i.hostname AND l.created > DATE_SUB(NOW(), INTERVAL 24 HOUR)) AS events_24h, " & _
"(SELECT MAX(created) FROM ednc_logs l WHERE l.hostname = i.hostname AND l.action = 'cleaned') AS last_cleaned " & _
"FROM ednc_installations i " & _
"INNER JOIN machines m ON UPPER(i.hostname) = UPPER(m.hostname) " & _
"WHERE m.machineid = ?"
Set rsEdnc = ExecuteParameterizedQuery(objConn, edncSQL, Array(machineid))
If Not rsEdnc.EOF Then
edncSQL = "SELECT " & _
"(SELECT version FROM ednclogs WHERE machineid = ? ORDER BY created DESC LIMIT 1) AS version, " & _
"(SELECT MIN(created) FROM ednclogs WHERE machineid = ?) AS first_seen, " & _
"(SELECT MAX(created) FROM ednclogs WHERE machineid = ?) AS last_seen, " & _
"(SELECT COUNT(*) FROM ednclogs WHERE machineid = ? AND action = 'cleaned') AS total_cleaned, " & _
"(SELECT COUNT(*) FROM ednclogs WHERE machineid = ? AND action IN ('failed', 'error')) AS total_failed, " & _
"(SELECT COUNT(*) FROM ednclogs WHERE machineid = ? AND created > DATE_SUB(NOW(), INTERVAL 24 HOUR)) AS events_24h, " & _
"(SELECT MAX(created) FROM ednclogs WHERE machineid = ? AND action = 'cleaned') AS last_cleaned"
Set rsEdnc = ExecuteParameterizedQuery(objConn, edncSQL, Array(machineid, machineid, machineid, machineid, machineid, machineid, machineid))
If Not rsEdnc.EOF And Not IsNull(rsEdnc("first_seen")) Then
hasEdnc = True
%>
<h6 class="mt-4 mb-3"><i class="zmdi zmdi-settings"></i> eDNC Special Character Fix</h6>
@@ -760,14 +762,6 @@ End If
<td class="font-weight-bold" width="35%">Version</td>
<td><%= Server.HTMLEncode(rsEdnc("version") & "") %></td>
</tr>
<tr>
<td class="font-weight-bold">Watch Folder</td>
<td><code><%= Server.HTMLEncode(rsEdnc("watch_folder") & "") %></code></td>
</tr>
<tr>
<td class="font-weight-bold">File Filter</td>
<td><code><%= Server.HTMLEncode(rsEdnc("file_filter") & "") %></code></td>
</tr>
<tr>
<td class="font-weight-bold">First Seen</td>
<td><%= rsEdnc("first_seen") %></td>
@@ -777,19 +771,19 @@ End If
<td><%= rsEdnc("last_seen") %></td>
</tr>
<tr>
<td class="font-weight-bold">Files Cleaned (Total)</td>
<td class="font-weight-bold">Files Cleaned</td>
<td><span class="badge badge-success"><%= rsEdnc("total_cleaned") %></span></td>
</tr>
<tr>
<td class="font-weight-bold">Files Failed (Total)</td>
<td class="font-weight-bold">Files Failed</td>
<td><span class="badge badge-<%= IIf(CLng(rsEdnc("total_failed") & "0") > 0, "danger", "secondary") %>"><%= rsEdnc("total_failed") %></span></td>
</tr>
<tr>
<td class="font-weight-bold">Events (Last 24h)</td>
<td class="font-weight-bold">Events (24h)</td>
<td><%= rsEdnc("events_24h") %></td>
</tr>
<tr>
<td class="font-weight-bold">Last File Cleaned</td>
<td class="font-weight-bold">Last Cleaned</td>
<td><%= rsEdnc("last_cleaned") & "" %></td>
</tr>
</tbody>
@@ -798,10 +792,10 @@ End If
<%
' Show recent log entries
Dim logSQL, rsLog
logSQL = "SELECT filename, action, bytes_removed, created FROM ednc_logs " & _
"WHERE UPPER(hostname) = UPPER(?) AND action IN ('cleaned', 'ok', 'failed', 'error') " & _
logSQL = "SELECT filename, action, bytes_removed, created FROM ednclogs " & _
"WHERE machineid = ? AND action IN ('cleaned', 'ok', 'failed', 'error') " & _
"ORDER BY created DESC LIMIT 10"
Set rsLog = ExecuteParameterizedQuery(objConn, logSQL, Array(rsEdnc("hostname") & ""))
Set rsLog = ExecuteParameterizedQuery(objConn, logSQL, Array(machineid))
%>
<h6 class="mt-4 mb-2">Recent Activity</h6>
<div class="table-responsive" style="max-height: 300px; overflow-y: auto;">
@@ -854,6 +848,7 @@ End If
End If
rsEdnc.Close
Set rsEdnc = Nothing
End If
%>
</div>
</div>

View File

@@ -1,41 +1,25 @@
-- ============================================================================
-- eDNC Special Character Fix - Database Tables
-- Run on PRODUCTION database to enable eDNC logging
-- Created: 2025-12-12
-- eDNC Special Character Fix - Database Migration
-- Migrates ednclogs from hostname to machineid (FK to machines table)
-- Run on PRODUCTION after initial setup
-- Updated: 2025-12-12
-- ============================================================================
-- Log individual events (cleaned, failed, started, stopped, etc.)
CREATE TABLE IF NOT EXISTS ednc_logs (
logid INT AUTO_INCREMENT PRIMARY KEY,
hostname VARCHAR(50) NOT NULL,
filename VARCHAR(255) NOT NULL,
action ENUM('cleaned', 'ok', 'failed', 'error', 'started', 'stopped') NOT NULL,
bytes_removed INT DEFAULT 0,
version VARCHAR(20),
message VARCHAR(500),
created DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_hostname (hostname),
INDEX idx_created (created),
INDEX idx_action (action)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Step 1: Add machineid column to ednclogs
ALTER TABLE ednclogs
ADD COLUMN machineid INT NOT NULL AFTER logid,
ADD INDEX idx_machineid (machineid);
-- Track installations per PC
CREATE TABLE IF NOT EXISTS ednc_installations (
installid INT AUTO_INCREMENT PRIMARY KEY,
hostname VARCHAR(50) NOT NULL UNIQUE,
version VARCHAR(20),
watch_folder VARCHAR(255),
file_filter VARCHAR(50),
first_seen DATETIME DEFAULT CURRENT_TIMESTAMP,
last_seen DATETIME DEFAULT CURRENT_TIMESTAMP,
is_active TINYINT(1) DEFAULT 1,
total_cleaned INT DEFAULT 0,
total_failed INT DEFAULT 0,
INDEX idx_hostname (hostname),
INDEX idx_active (is_active)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Step 2: Populate machineid from hostname (match existing PCs)
UPDATE ednclogs l
INNER JOIN machines m ON UPPER(m.hostname) = UPPER(l.hostname)
SET l.machineid = m.machineid
WHERE m.pctypeid IS NOT NULL;
-- Verify tables created
SELECT 'ednc_logs' AS table_name, COUNT(*) AS row_count FROM ednc_logs
UNION ALL
SELECT 'ednc_installations', COUNT(*) FROM ednc_installations;
-- Step 3: Remove hostname column and index
ALTER TABLE ednclogs DROP INDEX idx_hostname;
ALTER TABLE ednclogs DROP COLUMN hostname;
-- Verify migration
SELECT 'Migration complete' AS status;
DESCRIBE ednclogs;