1eb6e972b0
Bulk CommentChecker pass: fills in <param>/<inheritdoc> tags on public APIs across all 23 src/ projects so the doc-coverage gate is green. Also adds a Sister Projects section to CLAUDE.md pointing at the MxAccess Gateway and OtOpcUa sibling repos, and gitignores local credential captures (*login*.txt) and the wonder-app-vd03 deploy/ artifacts.
119 lines
4.2 KiB
C#
119 lines
4.2 KiB
C#
using ScadaLink.Commons.Entities.Templates;
|
|
|
|
namespace ScadaLink.TemplateEngine;
|
|
|
|
/// <summary>
|
|
/// Enforces locking rules for template member overrides.
|
|
///
|
|
/// Locking rules:
|
|
/// - Locked members cannot be overridden downstream (child templates or compositions).
|
|
/// - Any level can lock an unlocked member (intermediate locking).
|
|
/// - Once locked, a member stays locked — it cannot be unlocked downstream.
|
|
///
|
|
/// Override granularity:
|
|
/// - Attributes: Value and Description overridable; DataType and DataSourceReference fixed.
|
|
/// - Alarms: Priority, TriggerConfiguration, Description, OnTriggerScript overridable; Name and TriggerType fixed.
|
|
/// - Scripts: Code, TriggerConfiguration, MinTimeBetweenRuns, params/return overridable; Name fixed.
|
|
/// - Lock flag applies to the entire member (attribute/alarm/script).
|
|
/// </summary>
|
|
public static class LockEnforcer
|
|
{
|
|
/// <summary>
|
|
/// Validates that an attribute override does not violate lock or granularity rules.
|
|
/// </summary>
|
|
/// <param name="original">The parent template's attribute definition.</param>
|
|
/// <param name="proposed">The child template's proposed override.</param>
|
|
public static string? ValidateAttributeOverride(
|
|
TemplateAttribute original,
|
|
TemplateAttribute proposed)
|
|
{
|
|
if (original.IsLocked)
|
|
{
|
|
return $"Attribute '{original.Name}' is locked and cannot be overridden.";
|
|
}
|
|
|
|
// DataType is fixed — cannot change
|
|
if (proposed.DataType != original.DataType)
|
|
{
|
|
return $"Attribute '{original.Name}': DataType cannot be overridden (fixed).";
|
|
}
|
|
|
|
// DataSourceReference is fixed — cannot change
|
|
if (proposed.DataSourceReference != original.DataSourceReference)
|
|
{
|
|
return $"Attribute '{original.Name}': DataSourceReference cannot be overridden (fixed).";
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validates that an alarm override does not violate lock or granularity rules.
|
|
/// </summary>
|
|
/// <param name="original">The parent template's alarm definition.</param>
|
|
/// <param name="proposed">The child template's proposed override.</param>
|
|
public static string? ValidateAlarmOverride(
|
|
TemplateAlarm original,
|
|
TemplateAlarm proposed)
|
|
{
|
|
if (original.IsLocked)
|
|
{
|
|
return $"Alarm '{original.Name}' is locked and cannot be overridden.";
|
|
}
|
|
|
|
// Name is fixed
|
|
if (proposed.Name != original.Name)
|
|
{
|
|
return $"Alarm '{original.Name}': Name cannot be overridden (fixed).";
|
|
}
|
|
|
|
// TriggerType is fixed
|
|
if (proposed.TriggerType != original.TriggerType)
|
|
{
|
|
return $"Alarm '{original.Name}': TriggerType cannot be overridden (fixed).";
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validates that a script override does not violate lock or granularity rules.
|
|
/// </summary>
|
|
/// <param name="original">The parent template's script definition.</param>
|
|
/// <param name="proposed">The child template's proposed override.</param>
|
|
public static string? ValidateScriptOverride(
|
|
TemplateScript original,
|
|
TemplateScript proposed)
|
|
{
|
|
if (original.IsLocked)
|
|
{
|
|
return $"Script '{original.Name}' is locked and cannot be overridden.";
|
|
}
|
|
|
|
// Name is fixed
|
|
if (proposed.Name != original.Name)
|
|
{
|
|
return $"Script '{original.Name}': Name cannot be overridden (fixed).";
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validates that a lock flag change is legal.
|
|
/// Locking is allowed on unlocked members. Unlocking is never allowed.
|
|
/// </summary>
|
|
/// <param name="originalIsLocked">The current lock state of the member.</param>
|
|
/// <param name="proposedIsLocked">The proposed lock state.</param>
|
|
/// <param name="memberName">Name of the member being changed, for error messages.</param>
|
|
public static string? ValidateLockChange(bool originalIsLocked, bool proposedIsLocked, string memberName)
|
|
{
|
|
if (originalIsLocked && !proposedIsLocked)
|
|
{
|
|
return $"Member '{memberName}' is locked and cannot be unlocked.";
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|