Centralize credentials and make migration idempotent

- Move all DB credentials to config.asp with DSN/ODBC toggle
- Add Zabbix API URL and token to centralized config
- Update sql.asp, api.asp, apiusb.asp, zabbix.asp to use config
- Add GetConnectionString() and GetEmployeeConnectionString() functions
- Make migration SQL idempotent (safe to run multiple times)
- Add duplicate index cleanup (appname_2) to migration
- Document employee DB access limitation in CLAUDE.md

🤖 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 08:11:28 -05:00
parent e0d89f9957
commit 131aaaddbf
9 changed files with 150 additions and 77 deletions

View File

@@ -24,6 +24,7 @@ ShopDB is a Classic ASP/VBScript web application for managing manufacturing shop
- Production IIS logs - Production IIS logs
- Production MySQL database - Production MySQL database
- Zabbix server (10.48.130.113) - Zabbix server (10.48.130.113)
- Employee database (wjf_employees) - used by displayprofile.asp (can update code, cannot test)
For production tasks, user must: For production tasks, user must:
- Relay production data/logs to Claude - Relay production data/logs to Claude

18
api.asp
View File

@@ -1,21 +1,13 @@
<%@ Language=VBScript %> <%@ Language=VBScript %>
<!--#include file="includes/config.asp"-->
<% <%
' ============================================================================ ' ============================================================================
' DATABASE CONNECTION - Created directly in api.asp to avoid scoping issues ' DATABASE CONNECTION - Uses centralized config.asp
' ============================================================================ ' ============================================================================
Dim objConn, rs, DB_CONN_STRING Dim objConn, rs
' Use direct MySQL ODBC driver connection (same as sql.asp) instead of DSN Session.Timeout = APP_SESSION_TIMEOUT
DB_CONN_STRING = "Driver={MySQL ODBC 9.4 Unicode Driver};" & _
"Server=192.168.122.1;" & _
"Port=3306;" & _
"Database=shopdb;" & _
"User=570005354;" & _
"Password=570005354;" & _
"Option=3;" & _
"Pooling=True;Max Pool Size=100;"
Session.Timeout = 15
Set objConn = Server.CreateObject("ADODB.Connection") Set objConn = Server.CreateObject("ADODB.Connection")
objConn.ConnectionString = DB_CONN_STRING objConn.ConnectionString = GetConnectionString()
objConn.Open objConn.Open
Set rs = Server.CreateObject("ADODB.Recordset") Set rs = Server.CreateObject("ADODB.Recordset")

View File

@@ -1,30 +1,25 @@
<%@ Language="VBScript" %> <%@ Language="VBScript" %>
<% <%
Option Explicit
%>
<!--#include file="includes/config.asp"-->
<%
'============================================================================= '=============================================================================
' FILE: apiusb.asp ' FILE: apiusb.asp
' PURPOSE: API endpoints for USB device operations ' PURPOSE: API endpoints for USB device operations
' SECURITY: Parameterized queries, JSON output ' SECURITY: Parameterized queries, JSON output
' CREATED: 2025-12-07 ' CREATED: 2025-12-07
'============================================================================= '=============================================================================
Option Explicit
Response.ContentType = "application/json" Response.ContentType = "application/json"
Response.Charset = "utf-8" Response.Charset = "utf-8"
Response.Buffer = True Response.Buffer = True
' Create database connection directly (avoid sql.asp scoping issues) ' Database connection using centralized config
Dim objConn, DB_CONN_STRING Dim objConn
DB_CONN_STRING = "Driver={MySQL ODBC 9.4 Unicode Driver};" & _
"Server=192.168.122.1;" & _
"Port=3306;" & _
"Database=shopdb;" & _
"User=570005354;" & _
"Password=570005354;" & _
"Option=3;" & _
"Pooling=True;Max Pool Size=100;"
On Error Resume Next On Error Resume Next
Set objConn = Server.CreateObject("ADODB.Connection") Set objConn = Server.CreateObject("ADODB.Connection")
objConn.ConnectionString = DB_CONN_STRING objConn.ConnectionString = GetConnectionString()
objConn.Open objConn.Open
If Err.Number <> 0 Then If Err.Number <> 0 Then

View File

@@ -7,6 +7,7 @@ Option Explicit
<head> <head>
<!--#include file="./includes/header.asp"--> <!--#include file="./includes/header.asp"-->
<!--#include file="./includes/wjf_employees-sql.asp"--> <!--#include file="./includes/wjf_employees-sql.asp"-->
<!-- Note: config.asp is included via wjf_employees-sql.asp -->
<!-- DataTables CSS --> <!-- DataTables CSS -->
<link rel="stylesheet" href="assets/plugins/datatables/dataTables.bootstrap4.min.css"> <link rel="stylesheet" href="assets/plugins/datatables/dataTables.bootstrap4.min.css">
</head> </head>
@@ -280,15 +281,13 @@ END IF
<div class="tab-pane" id="usbhistory"> <div class="tab-pane" id="usbhistory">
<h5 class="mb-3"><i class="zmdi zmdi-usb"></i> USB Checkout History</h5> <h5 class="mb-3"><i class="zmdi zmdi-usb"></i> USB Checkout History</h5>
<% <%
' Connect to shopdb for USB history ' Connect to shopdb for USB history (uses centralized config)
Dim objConnShopdb, shopdbAvailable Dim objConnShopdb, shopdbAvailable
shopdbAvailable = False shopdbAvailable = False
On Error Resume Next On Error Resume Next
Set objConnShopdb = Server.CreateObject("ADODB.Connection") Set objConnShopdb = Server.CreateObject("ADODB.Connection")
objConnShopdb.ConnectionString = "Driver={MySQL ODBC 9.4 Unicode Driver};" & _ objConnShopdb.ConnectionString = GetConnectionString()
"Server=192.168.122.1;Port=3306;Database=shopdb;" & _
"User=570005354;Password=570005354;Option=3;"
objConnShopdb.Open objConnShopdb.Open
If Err.Number = 0 Then If Err.Number = 0 Then
shopdbAvailable = True shopdbAvailable = True

View File

@@ -10,8 +10,17 @@
'============================================================================= '=============================================================================
'----------------------------------------------------------------------------- '-----------------------------------------------------------------------------
' Database Configuration ' Database Configuration - ShopDB (primary)
'----------------------------------------------------------------------------- '-----------------------------------------------------------------------------
' Set USE_DSN = True for production (DSN-based), False for dev (direct ODBC)
Const USE_DSN = False
' DSN configuration (production)
Const DB_DSN = "shopdb"
Const DB_DSN_USER = "570005354"
Const DB_DSN_PASSWORD = "570005354"
' Direct ODBC configuration (development)
Const DB_DRIVER = "MySQL ODBC 9.4 Unicode Driver" Const DB_DRIVER = "MySQL ODBC 9.4 Unicode Driver"
Const DB_SERVER = "192.168.122.1" Const DB_SERVER = "192.168.122.1"
Const DB_PORT = "3306" Const DB_PORT = "3306"
@@ -19,6 +28,25 @@ Const DB_NAME = "shopdb"
Const DB_USER = "570005354" Const DB_USER = "570005354"
Const DB_PASSWORD = "570005354" Const DB_PASSWORD = "570005354"
'-----------------------------------------------------------------------------
' Database Configuration - Employee Database
'-----------------------------------------------------------------------------
' Set USE_EMP_DSN = True for production (DSN-based), False for dev (direct ODBC)
Const USE_EMP_DSN = True
' DSN configuration (production)
Const EMP_DB_DSN = "wjf_employees"
Const EMP_DB_DSN_USER = "root"
Const EMP_DB_DSN_PASSWORD = "WJF11sql"
' Direct ODBC configuration (development) - configure if needed
Const EMP_DB_DRIVER = "MySQL ODBC 9.4 Unicode Driver"
Const EMP_DB_SERVER = "localhost"
Const EMP_DB_PORT = "3306"
Const EMP_DB_NAME = "wjf_employees"
Const EMP_DB_USER = "root"
Const EMP_DB_PASSWORD = "WJF11sql"
'----------------------------------------------------------------------------- '-----------------------------------------------------------------------------
' Application Settings ' Application Settings
'----------------------------------------------------------------------------- '-----------------------------------------------------------------------------
@@ -42,11 +70,17 @@ Const DEFAULT_MODEL_ID = 1 ' Default model
Const DEFAULT_OS_ID = 1 ' Default operating system Const DEFAULT_OS_ID = 1 ' Default operating system
'----------------------------------------------------------------------------- '-----------------------------------------------------------------------------
' External Services ' External Services - ServiceNow
'----------------------------------------------------------------------------- '-----------------------------------------------------------------------------
Const SNOW_BASE_URL = "https://geit.service-now.com/now/nav/ui/search/" Const SNOW_BASE_URL = "https://geit.service-now.com/now/nav/ui/search/"
Const SNOW_TICKET_PREFIXES = "geinc,gechg,gerit,gesct" ' Valid ServiceNow ticket prefixes Const SNOW_TICKET_PREFIXES = "geinc,gechg,gerit,gesct" ' Valid ServiceNow ticket prefixes
'-----------------------------------------------------------------------------
' External Services - Zabbix API
'-----------------------------------------------------------------------------
Const ZABBIX_URL = "http://10.48.130.113:8080/api_jsonrpc.php"
Const ZABBIX_API_TOKEN = "9e60b0544ec77131d94825eaa2f3f1645335539361fd33644aeb8326697aa48d"
'----------------------------------------------------------------------------- '-----------------------------------------------------------------------------
' File Upload ' File Upload
'----------------------------------------------------------------------------- '-----------------------------------------------------------------------------
@@ -59,10 +93,15 @@ Const ALLOWED_EXTENSIONS = "jpg,jpeg,png,gif,pdf"
'----------------------------------------------------------------------------- '-----------------------------------------------------------------------------
' FUNCTION: GetConnectionString ' FUNCTION: GetConnectionString
' PURPOSE: Returns the database connection string with all parameters ' PURPOSE: Returns the database connection string based on USE_DSN setting
' RETURNS: Complete ODBC connection string ' RETURNS: DSN connection string (production) or direct ODBC string (dev)
'----------------------------------------------------------------------------- '-----------------------------------------------------------------------------
Function GetConnectionString() Function GetConnectionString()
If USE_DSN Then
' Production: DSN-based connection with pooling
GetConnectionString = "DSN=" & DB_DSN & ";Uid=" & DB_DSN_USER & ";Pwd=" & DB_DSN_PASSWORD & ";Option=3;Pooling=True;Max Pool Size=100;"
Else
' Development: Direct ODBC driver connection
GetConnectionString = "Driver={" & DB_DRIVER & "};" & _ GetConnectionString = "Driver={" & DB_DRIVER & "};" & _
"Server=" & DB_SERVER & ";" & _ "Server=" & DB_SERVER & ";" & _
"Port=" & DB_PORT & ";" & _ "Port=" & DB_PORT & ";" & _
@@ -71,6 +110,28 @@ Function GetConnectionString()
"Password=" & DB_PASSWORD & ";" & _ "Password=" & DB_PASSWORD & ";" & _
"Option=3;" & _ "Option=3;" & _
"Pooling=True;Max Pool Size=100;" "Pooling=True;Max Pool Size=100;"
End If
End Function
'-----------------------------------------------------------------------------
' FUNCTION: GetEmployeeConnectionString
' PURPOSE: Returns the employee database connection string based on USE_EMP_DSN
' RETURNS: DSN connection string (production) or direct ODBC string (dev)
'-----------------------------------------------------------------------------
Function GetEmployeeConnectionString()
If USE_EMP_DSN Then
' Production: DSN-based connection
GetEmployeeConnectionString = "DSN=" & EMP_DB_DSN & ";Uid=" & EMP_DB_DSN_USER & ";Pwd=" & EMP_DB_DSN_PASSWORD
Else
' Development: Direct ODBC driver connection
GetEmployeeConnectionString = "Driver={" & EMP_DB_DRIVER & "};" & _
"Server=" & EMP_DB_SERVER & ";" & _
"Port=" & EMP_DB_PORT & ";" & _
"Database=" & EMP_DB_NAME & ";" & _
"User=" & EMP_DB_USER & ";" & _
"Password=" & EMP_DB_PASSWORD & ";" & _
"Option=3;"
End If
End Function End Function
'----------------------------------------------------------------------------- '-----------------------------------------------------------------------------

View File

@@ -1,18 +1,9 @@
<!--#include file="config.asp"-->
<% <%
' objConn - script-global connection object (no Dim for global scope) ' objConn - script-global connection object (no Dim for global scope)
Session.Timeout=15 Session.Timeout = APP_SESSION_TIMEOUT
Set objConn = Server.CreateObject("ADODB.Connection") Set objConn = Server.CreateObject("ADODB.Connection")
' Old DSN connection: objConn.ConnectionString = GetConnectionString()
' objConn.ConnectionString="DSN=shopdb;Uid=root;Pwd=WJF11sql"
' Direct MySQL ODBC connection with pooling enabled:
objConn.ConnectionString="Driver={MySQL ODBC 9.4 Unicode Driver};" & _
"Server=192.168.122.1;" & _
"Port=3306;" & _
"Database=shopdb;" & _
"User=570005354;" & _
"Password=570005354;" & _
"Option=3;" & _
"Pooling=True;Max Pool Size=100;"
objConn.Open objConn.Open
set rs = server.createobject("ADODB.Recordset") Set rs = Server.CreateObject("ADODB.Recordset")
%> %>

View File

@@ -1,8 +1,10 @@
<!--#include file="config.asp"-->
<% <%
' Employee database connection - uses centralized config
Dim objConn Dim objConn
Session.Timeout=15 Session.Timeout = APP_SESSION_TIMEOUT
Set objConn = Server.CreateObject("ADODB.Connection") Set objConn = Server.CreateObject("ADODB.Connection")
objConn.ConnectionString="DSN=wjf_employees;Uid=root;Pwd=WJF11sql" objConn.ConnectionString = GetEmployeeConnectionString()
objConn.Open objConn.Open
set rs = server.createobject("ADODB.Recordset") Set rs = Server.CreateObject("ADODB.Recordset")
%> %>

View File

@@ -1,7 +1,6 @@
<!--#include file="config.asp"-->
<% <%
' Zabbix API Configuration ' Zabbix API Configuration - uses ZABBIX_URL and ZABBIX_API_TOKEN from config.asp
Const ZABBIX_URL = "http://10.48.130.113:8080/api_jsonrpc.php"
Const ZABBIX_API_TOKEN = "9e60b0544ec77131d94825eaa2f3f1645335539361fd33644aeb8326697aa48d"
' Function to make HTTP POST request to Zabbix API with Bearer token ' Function to make HTTP POST request to Zabbix API with Bearer token
Function ZabbixAPICall(jsonRequest) Function ZabbixAPICall(jsonRequest)

View File

@@ -5,10 +5,13 @@
-- ============================================================================ -- ============================================================================
-- --
-- CHANGES: -- CHANGES:
-- 1. Add primary key to installedapps table -- 1. Drop duplicate appname_2 index on applications table
-- 2. Migrate machines using PC-specific machinetypes to generic PC (33) + pctypeid -- 2. Add primary key to installedapps table (if not exists)
-- 3. Update models to use generic PC machinetype -- 3. Migrate machines using PC-specific machinetypes to generic PC (33) + pctypeid
-- 4. Remove unused PC machinetypes (34-43, 45-46), keep USB Device (44) -- 4. Update models to use generic PC machinetype
-- 5. Remove unused PC machinetypes (34-43, 45-46), keep USB Device (44)
--
-- NOTE: This migration is IDEMPOTENT - safe to run multiple times
-- --
-- RUN ON: Production database -- RUN ON: Production database
-- BACKUP FIRST: mysqldump -u root -p shopdb > shopdb_backup_$(date +%Y%m%d).sql -- BACKUP FIRST: mysqldump -u root -p shopdb > shopdb_backup_$(date +%Y%m%d).sql
@@ -18,16 +21,42 @@
START TRANSACTION; START TRANSACTION;
-- ============================================================================ -- ============================================================================
-- 1. ADD PRIMARY KEY TO INSTALLEDAPPS TABLE -- 1. DROP DUPLICATE INDEX ON APPLICATIONS
-- ============================================================================ -- ============================================================================
ALTER TABLE installedapps -- Check if appname_2 index exists before dropping
ADD COLUMN installedappid INT AUTO_INCREMENT PRIMARY KEY FIRST; SET @index_exists = (SELECT COUNT(*) FROM information_schema.STATISTICS
WHERE table_schema = DATABASE()
AND table_name = 'applications'
AND index_name = 'appname_2');
SELECT 'Added PK to installedapps' AS status; SET @sql = IF(@index_exists > 0, 'DROP INDEX appname_2 ON applications', 'SELECT "Index appname_2 does not exist" AS status');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SELECT IF(@index_exists > 0, 'Dropped duplicate appname_2 index', 'Index appname_2 already removed') AS status;
-- ============================================================================ -- ============================================================================
-- 2. MIGRATE MACHINES FROM PC-SPECIFIC TYPES TO GENERIC PC (33) + PCTYPEID -- 2. ADD PRIMARY KEY TO INSTALLEDAPPS TABLE (if not exists)
-- ============================================================================ -- ============================================================================
SET @col_exists = (SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE table_schema = DATABASE()
AND table_name = 'installedapps'
AND column_name = 'installedappid');
SET @sql = IF(@col_exists = 0,
'ALTER TABLE installedapps ADD COLUMN installedappid INT AUTO_INCREMENT PRIMARY KEY FIRST',
'SELECT "Column installedappid already exists" AS status');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SELECT IF(@col_exists = 0, 'Added PK to installedapps', 'PK installedappid already exists') AS status;
-- ============================================================================
-- 3. MIGRATE MACHINES FROM PC-SPECIFIC TYPES TO GENERIC PC (33) + PCTYPEID
-- ============================================================================
-- These UPDATEs are already idempotent (won't change rows that don't match)
-- PC - Standard (36) → machinetypeid=33, pctypeid=1 (Standard) -- PC - Standard (36) → machinetypeid=33, pctypeid=1 (Standard)
UPDATE machines UPDATE machines
@@ -64,11 +93,11 @@ UPDATE machines
SET machinetypeid = 33, pctypeid = 4 SET machinetypeid = 33, pctypeid = 4
WHERE machinetypeid BETWEEN 34 AND 46 AND pctypeid IS NULL; WHERE machinetypeid BETWEEN 34 AND 46 AND pctypeid IS NULL;
SELECT CONCAT('Total machines now using machinetypeid 34-46: ', SELECT CONCAT('Total machines still using machinetypeid 34-46: ',
(SELECT COUNT(*) FROM machines WHERE machinetypeid BETWEEN 34 AND 46)) AS status; (SELECT COUNT(*) FROM machines WHERE machinetypeid BETWEEN 34 AND 46)) AS status;
-- ============================================================================ -- ============================================================================
-- 3. UPDATE MODELS TO USE GENERIC PC MACHINETYPE (33) -- 4. UPDATE MODELS TO USE GENERIC PC MACHINETYPE (33)
-- ============================================================================ -- ============================================================================
UPDATE models UPDATE models
SET machinetypeid = 33 SET machinetypeid = 33
@@ -77,9 +106,10 @@ WHERE machinetypeid BETWEEN 34 AND 46;
SELECT CONCAT('Updated ', ROW_COUNT(), ' models to generic PC type') AS status; SELECT CONCAT('Updated ', ROW_COUNT(), ' models to generic PC type') AS status;
-- ============================================================================ -- ============================================================================
-- 4. DELETE REDUNDANT MACHINETYPES -- 5. DELETE REDUNDANT MACHINETYPES
-- ============================================================================ -- ============================================================================
-- Keep 33 (PC) and 44 (USB Device), remove 34-43 and 45-46 -- Keep 33 (PC) and 44 (USB Device), remove 34-43 and 45-46
-- These DELETEs are already idempotent (won't delete if rows don't exist)
DELETE FROM machinetypes WHERE machinetypeid BETWEEN 34 AND 43; DELETE FROM machinetypes WHERE machinetypeid BETWEEN 34 AND 43;
SELECT CONCAT('Deleted ', ROW_COUNT(), ' machinetypes (34-43)') AS status; SELECT CONCAT('Deleted ', ROW_COUNT(), ' machinetypes (34-43)') AS status;
@@ -101,10 +131,13 @@ WHERE m.pctypeid IS NOT NULL
GROUP BY m.pctypeid GROUP BY m.pctypeid
ORDER BY count DESC; ORDER BY count DESC;
SELECT 'VERIFICATION - Applications indexes:' AS info;
SELECT index_name, column_name FROM information_schema.STATISTICS
WHERE table_schema = DATABASE() AND table_name = 'applications';
-- ============================================================================ -- ============================================================================
-- COMMIT (uncomment when ready to apply) -- COMMIT
-- ============================================================================ -- ============================================================================
COMMIT; COMMIT;
-- ROLLBACK; -- Use this instead if something looks wrong
SELECT 'Migration completed successfully!' AS status; SELECT 'Migration completed successfully!' AS status;