From f8083be4677402f33b6e7edc94464af19150a049 Mon Sep 17 00:00:00 2001 From: cproudlock Date: Wed, 10 Dec 2025 20:04:01 -0500 Subject: [PATCH] Add automatic controller propagation for dualpath machines When a PC is assigned to control equipment that has a dualpath relationship, the controller is now automatically propagated to the dualpath partner machine. Changes: - includes/db_helpers.asp: Add PropagateControllerToDualpathMachines() and PropagateControllerFromDualpathMachine() helper functions - savemachine_direct.asp: Call propagation on new equipment creation - savemachineedit.asp: Call propagation when editing equipment relationships - api.asp: Add PropagateControllerToDualpathMachinesAPI() for PowerShell API Also includes one-time fix script (sql/fix_dualpath_controller_relationships.sql) that fixes 140 backwards relationships (Equipment->PC to PC->Equipment) and propagates controllers to 30 dualpath machines that were missing them. Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- api.asp | 70 ++++++++ includes/db_helpers.asp | 168 ++++++++++++++++++ savemachine_direct.asp | 7 + savemachineedit.asp | 9 + sql/fix_dualpath_controller_relationships.sql | 153 ++++++++++++++++ 5 files changed, 407 insertions(+) create mode 100644 sql/fix_dualpath_controller_relationships.sql diff --git a/api.asp b/api.asp index f8298fd..f981ecd 100644 --- a/api.asp +++ b/api.asp @@ -1609,10 +1609,80 @@ Function CreatePCMachineRelationship(pcMachineid, machineNumber) CreatePCMachineRelationship = False Else LogToFile "Created Controls relationship: Equipment " & equipmentMachineid & " controlled by PC " & pcMachineid + + ' Propagate controller to any dualpath machines + Dim dualpathCount + dualpathCount = PropagateControllerToDualpathMachinesAPI(CLng(equipmentMachineid), CLng(pcMachineid)) + If dualpathCount > 0 Then + LogToFile "Propagated controller to " & dualpathCount & " dualpath machine(s)" + End If + CreatePCMachineRelationship = True End If End Function +' ============================================================================ +' FUNCTION: PropagateControllerToDualpathMachinesAPI +' PURPOSE: When a PC controls a machine, also assign it to dualpath'd machines +' ============================================================================ +Function PropagateControllerToDualpathMachinesAPI(equipmentMachineid, pcMachineid) + On Error Resume Next + + Dim rsDP, rsDPCheck, controlsTypeID, dualpathMachineId, cnt + cnt = 0 + + ' Get Controls relationship type ID + Set rsDP = objConn.Execute("SELECT relationshiptypeid FROM relationshiptypes WHERE relationshiptype = 'Controls'") + If rsDP.EOF Then + PropagateControllerToDualpathMachinesAPI = 0 + rsDP.Close + Set rsDP = Nothing + Exit Function + End If + controlsTypeID = CLng(rsDP("relationshiptypeid")) + rsDP.Close + Set rsDP = Nothing + + ' Find all machines with dualpath relationship to this equipment + Set rsDP = objConn.Execute("SELECT related_machineid FROM machinerelationships mr " & _ + "JOIN relationshiptypes rt ON mr.relationshiptypeid = rt.relationshiptypeid " & _ + "WHERE mr.machineid = " & CLng(equipmentMachineid) & " " & _ + "AND rt.relationshiptype = 'Dualpath' AND mr.isactive = 1") + + Do While Not rsDP.EOF + dualpathMachineId = CLng(rsDP("related_machineid")) + + ' Check if this dualpath machine already has a Controls relationship with this PC + Set rsDPCheck = objConn.Execute("SELECT relationshipid FROM machinerelationships " & _ + "WHERE machineid = " & CLng(pcMachineid) & " " & _ + "AND related_machineid = " & dualpathMachineId & " " & _ + "AND relationshiptypeid = " & controlsTypeID & " AND isactive = 1") + + If rsDPCheck.EOF Then + ' Create Controls relationship: PC -> Dualpath Machine + Dim cmdDPAPI + Set cmdDPAPI = Server.CreateObject("ADODB.Command") + cmdDPAPI.ActiveConnection = objConn + cmdDPAPI.CommandText = "INSERT INTO machinerelationships (machineid, related_machineid, relationshiptypeid, isactive) VALUES (?, ?, ?, 1)" + cmdDPAPI.Parameters.Append cmdDPAPI.CreateParameter("@pcid", 3, 1, , CLng(pcMachineid)) + cmdDPAPI.Parameters.Append cmdDPAPI.CreateParameter("@equipid", 3, 1, , dualpathMachineId) + cmdDPAPI.Parameters.Append cmdDPAPI.CreateParameter("@reltypeid", 3, 1, , controlsTypeID) + cmdDPAPI.Execute + Set cmdDPAPI = Nothing + cnt = cnt + 1 + LogToFile "Created dualpath Controls relationship: Equipment " & dualpathMachineId & " controlled by PC " & pcMachineid + End If + rsDPCheck.Close + Set rsDPCheck = Nothing + + rsDP.MoveNext + Loop + rsDP.Close + Set rsDP = Nothing + + PropagateControllerToDualpathMachinesAPI = cnt +End Function + Sub UpdateWarrantyData(machineid, warrantyEndDate, warrantyStatus, warrantyServiceLevel, warrantyDaysRemaining) On Error Resume Next diff --git a/includes/db_helpers.asp b/includes/db_helpers.asp index 57840fe..c836e09 100644 --- a/includes/db_helpers.asp +++ b/includes/db_helpers.asp @@ -263,4 +263,172 @@ Function GetRecordCount(conn, tableName, whereClause, params) GetRecordCount = 0 End If End Function + +'----------------------------------------------------------------------------- +' FUNCTION: PropagateControllerToDualpathMachines +' PURPOSE: When a PC controls a machine, also assign it to dualpath'd machines +' PARAMETERS: +' conn (ADODB.Connection) - Database connection object +' equipmentMachineid (Integer) - The equipment machine being controlled +' pcMachineid (Integer) - The PC that controls the equipment +' RETURNS: Integer - Number of relationships created +' USAGE: Call after creating a "Controls" relationship +'----------------------------------------------------------------------------- +Function PropagateControllerToDualpathMachines(conn, equipmentMachineid, pcMachineid) + On Error Resume Next + + Dim rsDP, rsDPCheck, controlsTypeID, dualpathMachineId, cnt + cnt = 0 + + ' Get Controls relationship type ID + Set rsDP = conn.Execute("SELECT relationshiptypeid FROM relationshiptypes WHERE relationshiptype = 'Controls'") + If rsDP.EOF Then + PropagateControllerToDualpathMachines = 0 + rsDP.Close + Set rsDP = Nothing + Exit Function + End If + controlsTypeID = CLng(rsDP("relationshiptypeid")) + rsDP.Close + Set rsDP = Nothing + + ' Find all machines with dualpath relationship to this equipment + Set rsDP = conn.Execute("SELECT related_machineid FROM machinerelationships mr " & _ + "JOIN relationshiptypes rt ON mr.relationshiptypeid = rt.relationshiptypeid " & _ + "WHERE mr.machineid = " & CLng(equipmentMachineid) & " " & _ + "AND rt.relationshiptype = 'Dualpath' AND mr.isactive = 1") + + Do While Not rsDP.EOF + dualpathMachineId = CLng(rsDP("related_machineid")) + + ' Check if this dualpath machine already has a Controls relationship with this PC + Set rsDPCheck = conn.Execute("SELECT relationshipid FROM machinerelationships " & _ + "WHERE machineid = " & CLng(pcMachineid) & " " & _ + "AND related_machineid = " & dualpathMachineId & " " & _ + "AND relationshiptypeid = " & controlsTypeID & " AND isactive = 1") + + If rsDPCheck.EOF Then + ' Create Controls relationship: PC -> Dualpath Machine + Dim cmdDP + Set cmdDP = Server.CreateObject("ADODB.Command") + cmdDP.ActiveConnection = conn + cmdDP.CommandText = "INSERT INTO machinerelationships (machineid, related_machineid, relationshiptypeid, isactive) VALUES (?, ?, ?, 1)" + cmdDP.Parameters.Append cmdDP.CreateParameter("@pcid", 3, 1, , CLng(pcMachineid)) + cmdDP.Parameters.Append cmdDP.CreateParameter("@equipid", 3, 1, , dualpathMachineId) + cmdDP.Parameters.Append cmdDP.CreateParameter("@reltypeid", 3, 1, , controlsTypeID) + cmdDP.Execute + Set cmdDP = Nothing + cnt = cnt + 1 + End If + rsDPCheck.Close + Set rsDPCheck = Nothing + + rsDP.MoveNext + Loop + rsDP.Close + Set rsDP = Nothing + + PropagateControllerToDualpathMachines = cnt +End Function + +'----------------------------------------------------------------------------- +' FUNCTION: PropagateControllerFromDualpathMachine +' PURPOSE: When creating a dualpath relationship, copy controller from partner +' PARAMETERS: +' conn (ADODB.Connection) - Database connection object +' machineId1 (Integer) - First machine in dualpath +' machineId2 (Integer) - Second machine in dualpath +' RETURNS: Integer - Number of relationships created +' USAGE: Call after creating a dualpath relationship +'----------------------------------------------------------------------------- +Function PropagateControllerFromDualpathMachine(conn, machineId1, machineId2) + On Error Resume Next + + Dim rsCtrl, rsCheck, controlsTypeID, pcMachineid, cnt + cnt = 0 + + ' Get Controls relationship type ID + Set rsCtrl = conn.Execute("SELECT relationshiptypeid FROM relationshiptypes WHERE relationshiptype = 'Controls'") + If rsCtrl.EOF Then + PropagateControllerFromDualpathMachine = 0 + rsCtrl.Close + Set rsCtrl = Nothing + Exit Function + End If + controlsTypeID = CLng(rsCtrl("relationshiptypeid")) + rsCtrl.Close + Set rsCtrl = Nothing + + ' Check if machine1 has a controller, copy to machine2 if machine2 doesn't have one + Set rsCtrl = conn.Execute("SELECT machineid FROM machinerelationships " & _ + "WHERE related_machineid = " & CLng(machineId1) & " " & _ + "AND relationshiptypeid = " & controlsTypeID & " AND isactive = 1") + + If Not rsCtrl.EOF Then + pcMachineid = CLng(rsCtrl("machineid")) + rsCtrl.Close + Set rsCtrl = Nothing + + ' Check if machine2 already has this controller + Set rsCheck = conn.Execute("SELECT relationshipid FROM machinerelationships " & _ + "WHERE machineid = " & pcMachineid & " AND related_machineid = " & CLng(machineId2) & " " & _ + "AND relationshiptypeid = " & controlsTypeID & " AND isactive = 1") + + If rsCheck.EOF Then + ' Create: PC -> Controls -> machine2 + Dim cmdCtrl + Set cmdCtrl = Server.CreateObject("ADODB.Command") + cmdCtrl.ActiveConnection = conn + cmdCtrl.CommandText = "INSERT INTO machinerelationships (machineid, related_machineid, relationshiptypeid, isactive) VALUES (?, ?, ?, 1)" + cmdCtrl.Parameters.Append cmdCtrl.CreateParameter("@pcid", 3, 1, , pcMachineid) + cmdCtrl.Parameters.Append cmdCtrl.CreateParameter("@equipid", 3, 1, , CLng(machineId2)) + cmdCtrl.Parameters.Append cmdCtrl.CreateParameter("@reltypeid", 3, 1, , controlsTypeID) + cmdCtrl.Execute + Set cmdCtrl = Nothing + cnt = cnt + 1 + End If + rsCheck.Close + Set rsCheck = Nothing + Else + rsCtrl.Close + Set rsCtrl = Nothing + End If + + ' Now check if machine2 has a controller, copy to machine1 if machine1 doesn't have one + Set rsCtrl = conn.Execute("SELECT machineid FROM machinerelationships " & _ + "WHERE related_machineid = " & CLng(machineId2) & " " & _ + "AND relationshiptypeid = " & controlsTypeID & " AND isactive = 1") + + If Not rsCtrl.EOF Then + pcMachineid = CLng(rsCtrl("machineid")) + rsCtrl.Close + Set rsCtrl = Nothing + + ' Check if machine1 already has this controller + Set rsCheck = conn.Execute("SELECT relationshipid FROM machinerelationships " & _ + "WHERE machineid = " & pcMachineid & " AND related_machineid = " & CLng(machineId1) & " " & _ + "AND relationshiptypeid = " & controlsTypeID & " AND isactive = 1") + + If rsCheck.EOF Then + ' Create: PC -> Controls -> machine1 + Dim cmdCtrl2 + Set cmdCtrl2 = Server.CreateObject("ADODB.Command") + cmdCtrl2.ActiveConnection = conn + cmdCtrl2.CommandText = "INSERT INTO machinerelationships (machineid, related_machineid, relationshiptypeid, isactive) VALUES (?, ?, ?, 1)" + cmdCtrl2.Parameters.Append cmdCtrl2.CreateParameter("@pcid", 3, 1, , pcMachineid) + cmdCtrl2.Parameters.Append cmdCtrl2.CreateParameter("@equipid", 3, 1, , CLng(machineId1)) + cmdCtrl2.Parameters.Append cmdCtrl2.CreateParameter("@reltypeid", 3, 1, , controlsTypeID) + cmdCtrl2.Execute + Set cmdCtrl2 = Nothing + cnt = cnt + 1 + End If + rsCheck.Close + Set rsCheck = Nothing + Else + rsCtrl.Close + Set rsCtrl = Nothing + End If + + PropagateControllerFromDualpathMachine = cnt +End Function %> diff --git a/savemachine_direct.asp b/savemachine_direct.asp index 851c5b3..b947da3 100644 --- a/savemachine_direct.asp +++ b/savemachine_direct.asp @@ -10,6 +10,7 @@ %> + <% ' Get and validate all inputs Dim machinenumber, modelid, businessunitid, alias, machinenotes, mapleft, maptop @@ -568,6 +569,9 @@ cmdRelPC.Execute Set cmdRelPC = Nothing On Error Goto 0 + + ' Propagate controller to any dualpath machines + Call PropagateControllerToDualpathMachines(objConn, newMachineId, controllingpcVal) End If End If @@ -601,6 +605,9 @@ cmdRelDual2.Execute Set cmdRelDual2 = Nothing On Error Goto 0 + + ' Propagate controller from dualpath partner if exists + Call PropagateControllerFromDualpathMachine(objConn, newMachineId, dualpathidVal) End If End If diff --git a/savemachineedit.asp b/savemachineedit.asp index bdfddf4..5a1c305 100644 --- a/savemachineedit.asp +++ b/savemachineedit.asp @@ -9,6 +9,7 @@ %> + <% ' Get and validate all inputs Dim machineid, modelid, businessunitid, alias, machinenotes, mapleft, maptop, fqdn @@ -597,6 +598,11 @@ cmdRelPC.Execute Set cmdRelPC = Nothing On Error Goto 0 + + ' Propagate controller to dualpath machines (only for equipment, not PC) + If Not isPC Then + Call PropagateControllerToDualpathMachines(objConn, CLng(machineid), tempControllingPC) + End If End If ' Create Dualpath relationship (bidirectional) @@ -637,6 +643,9 @@ cmdRelDual2.Execute Set cmdRelDual2 = Nothing On Error Goto 0 + + ' Propagate controller from dualpath partner if exists + Call PropagateControllerFromDualpathMachine(objConn, CLng(machineid), tempDualpathID) End If '============================================================================= diff --git a/sql/fix_dualpath_controller_relationships.sql b/sql/fix_dualpath_controller_relationships.sql new file mode 100644 index 0000000..1c9868e --- /dev/null +++ b/sql/fix_dualpath_controller_relationships.sql @@ -0,0 +1,153 @@ +-- ============================================================================ +-- Script: fix_dualpath_controller_relationships.sql +-- Purpose: Fix existing relationship issues and propagate controllers to dualpath machines +-- Target: MySQL 5.6 (dev and production) +-- +-- Issues Fixed: +-- 1. Incorrect direction: Equipment -> Controls -> PC (should be PC -> Controls -> Equipment) +-- 2. Missing controller relationships on dualpath machines +-- ============================================================================ + +-- ============================================================================ +-- STEP 1: FIX INCORRECTLY DIRECTED RELATIONSHIPS +-- Equipment should NOT "Control" a PC - flip these to PC -> Controls -> Equipment +-- ============================================================================ + +-- First, identify the bad relationships (Equipment -> Controls -> PC) +SELECT + 'BAD RELATIONSHIP' AS issue, + mr.relationshipid, + m1.machinenumber AS equipment_number, + m1.hostname AS equipment_hostname, + rt.relationshiptype, + m2.hostname AS pc_hostname, + m2.machinenumber AS pc_machinenumber +FROM machinerelationships mr +JOIN machines m1 ON mr.machineid = m1.machineid +JOIN machines m2 ON mr.related_machineid = m2.machineid +JOIN relationshiptypes rt ON mr.relationshiptypeid = rt.relationshiptypeid +WHERE rt.relationshiptype = 'Controls' +AND m1.pctypeid IS NULL -- m1 is Equipment (not a PC) +AND m2.pctypeid IS NOT NULL -- m2 IS a PC +AND mr.isactive = 1; + +-- Fix: Delete the bad relationships and recreate them correctly +-- First, save the IDs we need to fix +CREATE TEMPORARY TABLE IF NOT EXISTS temp_bad_controls AS +SELECT + mr.relationshipid, + mr.machineid AS equipment_machineid, + mr.related_machineid AS pc_machineid, + mr.relationshiptypeid +FROM machinerelationships mr +JOIN machines m1 ON mr.machineid = m1.machineid +JOIN machines m2 ON mr.related_machineid = m2.machineid +WHERE mr.relationshiptypeid = (SELECT relationshiptypeid FROM relationshiptypes WHERE relationshiptype = 'Controls') +AND m1.pctypeid IS NULL +AND m2.pctypeid IS NOT NULL +AND mr.isactive = 1; + +-- Show what will be fixed +SELECT 'Will fix these relationships:' AS status; +SELECT * FROM temp_bad_controls; + +-- Delete the bad relationships +DELETE mr FROM machinerelationships mr +INNER JOIN temp_bad_controls t ON mr.relationshipid = t.relationshipid; + +-- Create the correct relationships (PC -> Controls -> Equipment) +INSERT INTO machinerelationships (machineid, related_machineid, relationshiptypeid, isactive) +SELECT + pc_machineid AS machineid, + equipment_machineid AS related_machineid, + relationshiptypeid, + 1 AS isactive +FROM temp_bad_controls t +WHERE NOT EXISTS ( + SELECT 1 FROM machinerelationships mr2 + WHERE mr2.machineid = t.pc_machineid + AND mr2.related_machineid = t.equipment_machineid + AND mr2.relationshiptypeid = t.relationshiptypeid + AND mr2.isactive = 1 +); + +DROP TEMPORARY TABLE IF EXISTS temp_bad_controls; + +-- ============================================================================ +-- STEP 2: PROPAGATE CONTROLLERS TO DUALPATH MACHINES +-- If Machine A is controlled by PC, and Machine A has dualpath to Machine B, +-- then Machine B should also be controlled by PC +-- ============================================================================ + +-- Find dualpath machines missing controller relationships +SELECT + 'MISSING CONTROLLER' AS issue, + m1.machinenumber AS machine_with_controller, + pc.hostname AS controller_pc, + m2.machinenumber AS dualpath_machine_missing_controller +FROM machinerelationships ctrl +JOIN machines m1 ON ctrl.related_machineid = m1.machineid +JOIN machines pc ON ctrl.machineid = pc.machineid +JOIN machinerelationships dp ON m1.machineid = dp.machineid +JOIN machines m2 ON dp.related_machineid = m2.machineid +JOIN relationshiptypes rt_ctrl ON ctrl.relationshiptypeid = rt_ctrl.relationshiptypeid +JOIN relationshiptypes rt_dp ON dp.relationshiptypeid = rt_dp.relationshiptypeid +WHERE rt_ctrl.relationshiptype = 'Controls' +AND rt_dp.relationshiptype = 'Dualpath' +AND ctrl.isactive = 1 +AND dp.isactive = 1 +AND NOT EXISTS ( + SELECT 1 FROM machinerelationships ctrl2 + WHERE ctrl2.machineid = pc.machineid + AND ctrl2.related_machineid = m2.machineid + AND ctrl2.relationshiptypeid = ctrl.relationshiptypeid + AND ctrl2.isactive = 1 +); + +-- Create the missing controller relationships +INSERT INTO machinerelationships (machineid, related_machineid, relationshiptypeid, isactive) +SELECT DISTINCT + pc.machineid AS machineid, + m2.machineid AS related_machineid, + ctrl.relationshiptypeid, + 1 AS isactive +FROM machinerelationships ctrl +JOIN machines m1 ON ctrl.related_machineid = m1.machineid +JOIN machines pc ON ctrl.machineid = pc.machineid +JOIN machinerelationships dp ON m1.machineid = dp.machineid +JOIN machines m2 ON dp.related_machineid = m2.machineid +JOIN relationshiptypes rt_ctrl ON ctrl.relationshiptypeid = rt_ctrl.relationshiptypeid +JOIN relationshiptypes rt_dp ON dp.relationshiptypeid = rt_dp.relationshiptypeid +WHERE rt_ctrl.relationshiptype = 'Controls' +AND rt_dp.relationshiptype = 'Dualpath' +AND ctrl.isactive = 1 +AND dp.isactive = 1 +AND NOT EXISTS ( + SELECT 1 FROM machinerelationships ctrl2 + WHERE ctrl2.machineid = pc.machineid + AND ctrl2.related_machineid = m2.machineid + AND ctrl2.relationshiptypeid = ctrl.relationshiptypeid + AND ctrl2.isactive = 1 +); + +-- ============================================================================ +-- VERIFICATION +-- ============================================================================ + +-- Show all Controls relationships (should be PC -> Equipment) +SELECT + 'CONTROLS RELATIONSHIPS' AS type, + pc.hostname AS pc_hostname, + pc.machinenumber AS pc_machinenumber, + '-> Controls ->' AS direction, + equip.machinenumber AS equipment_number, + equip.hostname AS equipment_hostname +FROM machinerelationships mr +JOIN machines pc ON mr.machineid = pc.machineid +JOIN machines equip ON mr.related_machineid = equip.machineid +JOIN relationshiptypes rt ON mr.relationshiptypeid = rt.relationshiptypeid +WHERE rt.relationshiptype = 'Controls' +AND mr.isactive = 1 +ORDER BY pc.hostname, equip.machinenumber; + +SELECT 'Fix complete!' AS status;