Skip to content

Commit 1c057cb

Browse files
committed
First release
1 parent 64889a1 commit 1c057cb

23 files changed

Lines changed: 1170 additions & 0 deletions

StatusPageClient.sln

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 16
4+
VisualStudioVersion = 16.0.29424.173
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatusPageClient", "StatusPageClient\StatusPageClient.csproj", "{7AB12D4C-5EB3-4B7C-AF8B-BDCF2B20DF48}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testbed", "Testbed\Testbed.csproj", "{62D7AAAB-4674-456A-A919-25FA235EB54E}"
9+
EndProject
10+
Global
11+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
12+
Debug|Any CPU = Debug|Any CPU
13+
Release|Any CPU = Release|Any CPU
14+
EndGlobalSection
15+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
16+
{7AB12D4C-5EB3-4B7C-AF8B-BDCF2B20DF48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17+
{7AB12D4C-5EB3-4B7C-AF8B-BDCF2B20DF48}.Debug|Any CPU.Build.0 = Debug|Any CPU
18+
{7AB12D4C-5EB3-4B7C-AF8B-BDCF2B20DF48}.Release|Any CPU.ActiveCfg = Release|Any CPU
19+
{7AB12D4C-5EB3-4B7C-AF8B-BDCF2B20DF48}.Release|Any CPU.Build.0 = Release|Any CPU
20+
{62D7AAAB-4674-456A-A919-25FA235EB54E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21+
{62D7AAAB-4674-456A-A919-25FA235EB54E}.Debug|Any CPU.Build.0 = Debug|Any CPU
22+
{62D7AAAB-4674-456A-A919-25FA235EB54E}.Release|Any CPU.ActiveCfg = Release|Any CPU
23+
{62D7AAAB-4674-456A-A919-25FA235EB54E}.Release|Any CPU.Build.0 = Release|Any CPU
24+
EndGlobalSection
25+
GlobalSection(SolutionProperties) = preSolution
26+
HideSolutionNode = FALSE
27+
EndGlobalSection
28+
GlobalSection(ExtensibilityGlobals) = postSolution
29+
SolutionGuid = {D81DD7B4-4172-4406-ACA9-744E608812E6}
30+
EndGlobalSection
31+
EndGlobal

StatusPageClient/Constants.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace StatusPageClient
6+
{
7+
public static class Constants
8+
{
9+
/// <summary>
10+
/// The version of the Statuspage.io API to use.
11+
/// </summary>
12+
public const string ApiVersion = "v2";
13+
14+
/// <summary>
15+
/// The user agent to be used by request to the Statuspage.io API.
16+
/// </summary>
17+
public const string UserAgent = "StatusPageClient programmatic access";
18+
}
19+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
6+
namespace StatusPageClient.Models
7+
{
8+
/// <summary>
9+
/// A single component of the <see cref="StatusPage"/> which can have its own dependencies and status.
10+
/// </summary>
11+
public class Component : IEquatable<Component>
12+
{
13+
private IEnumerable<string> _rawSubcomponents;
14+
15+
/// <summary>
16+
/// The unique identifier for this <see cref="Component"/>.
17+
/// </summary>
18+
public string Id { get; private set; }
19+
20+
/// <summary>
21+
/// The friendly name of this <see cref="Component"/>.
22+
/// </summary>
23+
public string Name { get; private set; }
24+
25+
/// <summary>
26+
/// A human-readable description of this <see cref="Component"/>.
27+
/// </summary>
28+
public string Description { get; private set; }
29+
30+
/// <summary>
31+
/// The order that this <see cref="Component"/> should appear in.
32+
/// </summary>
33+
public int DisplayPosition { get; private set; }
34+
35+
/// <summary>
36+
/// Current status of this <see cref="Component"/>
37+
/// </summary>
38+
/// <remarks>
39+
/// Only the <see cref="StatusDescription.Indicator"/> property will be populated.
40+
/// </remarks>
41+
public StatusDescription Status { get; private set; }
42+
43+
/// <summary>
44+
/// All child components of this <see cref="Component"/>.
45+
/// </summary>
46+
public IEnumerable<Component> Subcomponents { get; private set; }
47+
48+
internal Component(ResponseObjects.Component respComponent)
49+
{
50+
_rawSubcomponents = respComponent.SubcomponentIds ?? Enumerable.Empty<string>();
51+
52+
Id = respComponent.Id;
53+
Name = respComponent.Name;
54+
Description = respComponent.Description;
55+
DisplayPosition = respComponent.Position;
56+
Status = new StatusDescription(respComponent.Status, null);
57+
}
58+
59+
internal void ProcessSubcomponents(IEnumerable<Component> processedComponents)
60+
{
61+
var componentDictionary = processedComponents.ToDictionary(pc => pc.Id);
62+
63+
Subcomponents = (from id in _rawSubcomponents
64+
where componentDictionary.ContainsKey(id)
65+
select componentDictionary[id]).ToArray();
66+
}
67+
68+
/// <summary>
69+
/// Returns true if the other <see cref="Component"/> instance has the same <see cref="Id"/> as this one.
70+
/// </summary>
71+
/// <param name="other">The other <see cref="Component"/> to compare.</param>
72+
/// <returns>True if the two objects match, false otherwise</returns>
73+
public bool Equals(Component other)
74+
{
75+
return other != null && string.Equals(Id, other.Id, StringComparison.InvariantCultureIgnoreCase);
76+
}
77+
78+
/// <summary>
79+
/// Returns a string that represents the current object.
80+
/// </summary>
81+
/// <returns>A string that represents the current object.</returns>
82+
public override string ToString()
83+
{
84+
return $"{Name} ({Id})";
85+
}
86+
87+
/// <summary>
88+
/// Determines whether the specified object is equal to the current object.
89+
/// </summary>
90+
/// <param name="obj">The object to compare with the current object.</param>
91+
/// <returns>true if the specified object is equal to the current object; otherwise, false.</returns>
92+
public override bool Equals(object obj)
93+
{
94+
return Equals(obj as Component);
95+
}
96+
97+
/// <summary>
98+
/// Serves as the default hash function.
99+
/// </summary>
100+
/// <returns>A hash code for the current object.</returns>
101+
public override int GetHashCode()
102+
{
103+
return Id.GetHashCode();
104+
}
105+
}
106+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using System.Linq;
5+
6+
namespace StatusPageClient.Models
7+
{
8+
/// <summary>
9+
/// A change in state for a <see cref="Component"/> associated with an <see cref="IncidentUpdate"/>.
10+
/// </summary>
11+
public class ComponentStatusChange : IEquatable<ComponentStatusChange>
12+
{
13+
/// <summary>
14+
/// The <see cref="Component"/> whose status is changing.
15+
/// </summary>
16+
public Component Component { get; private set; }
17+
18+
/// <summary>
19+
/// The friendly name of this status change.
20+
/// </summary>
21+
public string Name { get; private set; }
22+
23+
/// <summary>
24+
/// The former status of this <see cref="Component"/>.
25+
/// </summary>
26+
public StatusDescription OldStatus { get; private set; }
27+
28+
/// <summary>
29+
/// The status which this <see cref="Component"/> has transitioned to.
30+
/// </summary>
31+
public StatusDescription NewStatus { get; private set; }
32+
33+
internal ComponentStatusChange(ResponseObjects.ComponentImpact respComponentImpact, IEnumerable<Component> componentsLookup)
34+
{
35+
Name = respComponentImpact.Name;
36+
OldStatus = new StatusDescription(respComponentImpact.OldStatus, null);
37+
NewStatus = new StatusDescription(respComponentImpact.NewStatus, null);
38+
39+
Component = componentsLookup.FirstOrDefault(c => string.Equals(c.Id, respComponentImpact.ComponentId, StringComparison.InvariantCultureIgnoreCase));
40+
}
41+
42+
/// <summary>
43+
/// Returns a string that represents the current object.
44+
/// </summary>
45+
/// <returns>A string that represents the current object.</returns>
46+
public override string ToString()
47+
{
48+
return $"{Component}: {OldStatus} -> {NewStatus}";
49+
}
50+
51+
/// <summary>
52+
/// Returns true if the other <see cref="ComponentStatusChange"/> instance has the same <see cref="Component"/>, <see cref="OldStatus"/> and <see cref="NewStatus"/> as this one.
53+
/// </summary>
54+
/// <param name="other">The other <see cref="ComponentStatusChange"/> to compare.</param>
55+
/// <returns>True if the two objects match, false otherwise</returns>
56+
public bool Equals(ComponentStatusChange other)
57+
{
58+
return other != null && other.Component == Component && other.OldStatus == OldStatus && other.NewStatus == NewStatus;
59+
}
60+
61+
/// <summary>
62+
/// Determines whether the specified object is equal to the current object.
63+
/// </summary>
64+
/// <param name="obj">The object to compare with the current object.</param>
65+
/// <returns>true if the specified object is equal to the current object; otherwise, false.</returns>
66+
public override bool Equals(object obj)
67+
{
68+
return Equals(obj as ComponentStatusChange);
69+
}
70+
71+
/// <summary>
72+
/// Serves as the default hash function.
73+
/// </summary>
74+
/// <returns>A hash code for the current object.</returns>
75+
public override int GetHashCode()
76+
{
77+
return ToString().GetHashCode();
78+
}
79+
}
80+
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using System.Linq;
5+
6+
namespace StatusPageClient.Models
7+
{
8+
/// <summary>
9+
/// An event relating to a status page and/or its subcomponents.
10+
/// </summary>
11+
public class Incident : IEquatable<Incident>
12+
{
13+
/// <summary>
14+
/// The unique identifier of this incident.
15+
/// </summary>
16+
public string Id { get; private set; }
17+
18+
/// <summary>
19+
/// A friendly name for this incident.
20+
/// </summary>
21+
public string Name { get; private set; }
22+
23+
/// <summary>
24+
/// The URL for this incident.
25+
/// </summary>
26+
public string Shortlink { get; private set; }
27+
28+
/// <summary>
29+
/// The impact this incident had upon <see cref="ImpactedComponents"/>.
30+
/// </summary>
31+
public string Impact { get; private set; }
32+
33+
/// <summary>
34+
/// UTC date that this incident was created.
35+
/// </summary>
36+
public DateTime CreatedOn { get; private set; }
37+
38+
/// <summary>
39+
/// UTC date that this incident was last updated.
40+
/// </summary>
41+
public DateTime UpdatedOn { get; private set; }
42+
43+
/// <summary>
44+
/// If present, the UTC date that this incident began to impact <see cref="ImpactedComponents"/>.
45+
/// </summary>
46+
public DateTime? StartedOn { get; private set; }
47+
48+
/// <summary>
49+
/// If present, the UTC date that this incident was resolved.
50+
/// </summary>
51+
public DateTime? ResolvedOn { get; private set; }
52+
53+
/// <summary>
54+
/// Current status of this incident.
55+
/// </summary>
56+
public StatusDescription Status { get; private set; }
57+
58+
/// <summary>
59+
/// All updates/changes of status for this incident.
60+
/// </summary>
61+
public IEnumerable<IncidentUpdate> Updates { get; private set; }
62+
63+
/// <summary>
64+
/// All components impacted by this incident.
65+
/// </summary>
66+
public IEnumerable<Component> ImpactedComponents { get; private set; }
67+
68+
internal Incident(ResponseObjects.Incident respIncident, IEnumerable<Component> componentsLookup)
69+
{
70+
Id = respIncident.Id;
71+
Name = respIncident.Name;
72+
Shortlink = respIncident.Shortlink;
73+
Impact = respIncident.Impact;
74+
75+
CreatedOn = respIncident.CreatedOn.UtcDateTime;
76+
UpdatedOn = respIncident.UpdatedOn.UtcDateTime;
77+
78+
if (respIncident.StartedOn.HasValue)
79+
{
80+
StartedOn = respIncident.StartedOn.Value.UtcDateTime;
81+
}
82+
if (respIncident.ResolvedOn.HasValue)
83+
{
84+
ResolvedOn = respIncident.ResolvedOn.Value.UtcDateTime;
85+
}
86+
87+
Status = new StatusDescription(respIncident.Status, null);
88+
89+
if (respIncident.ComponentImpacts != null)
90+
{
91+
var componentDictionary = componentsLookup.ToDictionary(c => c.Id);
92+
93+
ImpactedComponents = (from ic in respIncident.ComponentImpacts
94+
where componentDictionary.ContainsKey(ic.Id)
95+
select componentDictionary[ic.Id]).ToArray();
96+
}
97+
98+
if (respIncident.Updates != null)
99+
{
100+
Updates = respIncident.Updates.Select(iu => new IncidentUpdate(iu, componentsLookup)).ToArray();
101+
}
102+
}
103+
104+
/// <summary>
105+
/// Returns a string that represents the current object.
106+
/// </summary>
107+
/// <returns>A string that represents the current object.</returns>
108+
public override string ToString()
109+
{
110+
return $"{Name} ({Id})";
111+
}
112+
113+
/// <summary>
114+
/// Returns true if the other <see cref="Incident"/> instance has the same <see cref="Id"/> as this one.
115+
/// </summary>
116+
/// <param name="other">The other <see cref="Incident"/> to compare.</param>
117+
/// <returns>True if the two objects match, false otherwise</returns>
118+
public bool Equals(Incident other)
119+
{
120+
return other != null && string.Equals(Id, other.Id, StringComparison.InvariantCultureIgnoreCase);
121+
}
122+
123+
/// <summary>
124+
/// Determines whether the specified object is equal to the current object.
125+
/// </summary>
126+
/// <param name="obj">The object to compare with the current object.</param>
127+
/// <returns>true if the specified object is equal to the current object; otherwise, false.</returns>
128+
public override bool Equals(object obj)
129+
{
130+
return Equals(obj as Incident);
131+
}
132+
133+
/// <summary>
134+
/// Serves as the default hash function.
135+
/// </summary>
136+
/// <returns>A hash code for the current object.</returns>
137+
public override int GetHashCode()
138+
{
139+
return Id.GetHashCode();
140+
}
141+
}
142+
}

0 commit comments

Comments
 (0)