-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathConfigurationDtos.cs
More file actions
169 lines (135 loc) · 4.68 KB
/
ConfigurationDtos.cs
File metadata and controls
169 lines (135 loc) · 4.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;
using ThingConnect.Pulse.Server.Data;
namespace ThingConnect.Pulse.Server.Models;
/// <summary>
/// Custom validation attribute that allows null values but validates non-null values against a regex pattern.
/// </summary>
public sealed class OptionalRegularExpressionAttribute : ValidationAttribute
{
private readonly Regex _regex;
public OptionalRegularExpressionAttribute(string pattern)
{
_regex = new Regex(pattern, RegexOptions.Compiled);
}
public override bool IsValid(object? value)
{
// Allow null values (optional field)
if (value == null)
return true;
// Allow empty strings (optional field)
if (value is string str && string.IsNullOrEmpty(str))
return true;
// Validate non-empty strings against the pattern
return value is string stringValue && _regex.IsMatch(stringValue);
}
}
public class ConfigurationValidationException : Exception
{
public ValidationErrorsDto ValidationErrors { get; }
public ConfigurationValidationException(ValidationErrorsDto validationErrors)
: base(validationErrors.Message)
{
ValidationErrors = validationErrors;
}
}
public sealed class ConfigurationVersionDto
{
public string Id { get; set; } = default!;
public DateTimeOffset AppliedTs { get; set; }
public string FileHash { get; set; } = default!;
public string FilePath { get; set; } = default!;
public string? Actor { get; set; }
public string? Note { get; set; }
}
public sealed class ApplyResultDto
{
public string ConfigVersionId { get; set; } = default!;
public int Added { get; set; }
public int Updated { get; set; }
public int Removed { get; set; }
public List<string> Warnings { get; set; } = new();
}
public sealed class ValidationErrorsDto
{
public string Message { get; set; } = default!;
public List<ValidationError> Errors { get; set; } = new();
}
public sealed class ValidationError
{
public string Path { get; set; } = default!;
public string Message { get; set; } = default!;
public object? Value { get; set; }
public int? Line { get; set; }
public int? Column { get; set; }
}
public sealed class ConfigurationYaml
{
public int Version { get; set; } = 1;
public DefaultsSection Defaults { get; set; } = default!;
public List<GroupSection> Groups { get; set; } = new();
public List<TargetSection> Targets { get; set; } = new();
}
public sealed class DefaultsSection
{
[Required]
[Range(1, int.MaxValue)]
public int IntervalSeconds { get; set; } = 10;
[Required]
[Range(100, int.MaxValue)]
public int TimeoutMs { get; set; } = 1500;
[Required]
[Range(0, int.MaxValue)]
public int Retries { get; set; } = 1;
public HttpSection? Http { get; set; }
}
public sealed class HttpSection
{
public string UserAgent { get; set; } = "ThingConnectPulse/1.0";
public string ExpectText { get; set; } = string.Empty;
}
public sealed class GroupSection
{
[Required]
[RegularExpression("^[a-z0-9][a-z0-9-]{1,62}[a-z0-9]$", ErrorMessage = "ID must be lowercase alphanumeric with hyphens, 3-64 characters")]
public string Id { get; set; } = default!;
[Required]
[MinLength(1)]
public string Name { get; set; } = default!;
public string? ParentId { get; set; }
[OptionalRegularExpression("^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$", ErrorMessage = "Color must be a valid hex color code")]
public string? Color { get; set; }
public int? SortOrder { get; set; }
}
public sealed class TargetSection
{
public string? Name { get; set; }
// Location properties (oneOf: host, cidr, wildcard)
public string? Host { get; set; }
public string? Cidr { get; set; }
public string? Wildcard { get; set; }
// Required properties
[Required]
public ProbeType Type { get; set; }
[Required]
public string Group { get; set; } = default!;
// Optional timing properties
[Range(1, int.MaxValue)]
public int? IntervalSeconds { get; set; }
[Range(100, int.MaxValue)]
public int? TimeoutMs { get; set; }
[Range(0, int.MaxValue)]
public int? Retries { get; set; }
[Range(1, int.MaxValue)]
public int? ExpectedRttMs { get; set; }
// TCP/HTTP properties
[Range(1, 65535)]
public int? Port { get; set; }
// HTTP-specific properties (renamed from Path to HttpPath)
public string? HttpPath { get; set; } = "/";
public string? HttpMatch { get; set; }
public string? UserAgent { get; set; }
// Additional properties
public bool? Enabled { get; set; } = true;
public string? Notes { get; set; }
}