Skip to content

Commit

Permalink
First release
Browse files Browse the repository at this point in the history
  • Loading branch information
edwardneal committed Oct 31, 2019
1 parent 64889a1 commit 1c057cb
Show file tree
Hide file tree
Showing 23 changed files with 1,170 additions and 0 deletions.
31 changes: 31 additions & 0 deletions StatusPageClient.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29424.173
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatusPageClient", "StatusPageClient\StatusPageClient.csproj", "{7AB12D4C-5EB3-4B7C-AF8B-BDCF2B20DF48}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testbed", "Testbed\Testbed.csproj", "{62D7AAAB-4674-456A-A919-25FA235EB54E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7AB12D4C-5EB3-4B7C-AF8B-BDCF2B20DF48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7AB12D4C-5EB3-4B7C-AF8B-BDCF2B20DF48}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7AB12D4C-5EB3-4B7C-AF8B-BDCF2B20DF48}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7AB12D4C-5EB3-4B7C-AF8B-BDCF2B20DF48}.Release|Any CPU.Build.0 = Release|Any CPU
{62D7AAAB-4674-456A-A919-25FA235EB54E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{62D7AAAB-4674-456A-A919-25FA235EB54E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{62D7AAAB-4674-456A-A919-25FA235EB54E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{62D7AAAB-4674-456A-A919-25FA235EB54E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D81DD7B4-4172-4406-ACA9-744E608812E6}
EndGlobalSection
EndGlobal
19 changes: 19 additions & 0 deletions StatusPageClient/Constants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace StatusPageClient
{
public static class Constants
{
/// <summary>
/// The version of the Statuspage.io API to use.
/// </summary>
public const string ApiVersion = "v2";

/// <summary>
/// The user agent to be used by request to the Statuspage.io API.
/// </summary>
public const string UserAgent = "StatusPageClient programmatic access";
}
}
106 changes: 106 additions & 0 deletions StatusPageClient/Models/Component.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace StatusPageClient.Models
{
/// <summary>
/// A single component of the <see cref="StatusPage"/> which can have its own dependencies and status.
/// </summary>
public class Component : IEquatable<Component>
{
private IEnumerable<string> _rawSubcomponents;

/// <summary>
/// The unique identifier for this <see cref="Component"/>.
/// </summary>
public string Id { get; private set; }

/// <summary>
/// The friendly name of this <see cref="Component"/>.
/// </summary>
public string Name { get; private set; }

/// <summary>
/// A human-readable description of this <see cref="Component"/>.
/// </summary>
public string Description { get; private set; }

/// <summary>
/// The order that this <see cref="Component"/> should appear in.
/// </summary>
public int DisplayPosition { get; private set; }

/// <summary>
/// Current status of this <see cref="Component"/>
/// </summary>
/// <remarks>
/// Only the <see cref="StatusDescription.Indicator"/> property will be populated.
/// </remarks>
public StatusDescription Status { get; private set; }

/// <summary>
/// All child components of this <see cref="Component"/>.
/// </summary>
public IEnumerable<Component> Subcomponents { get; private set; }

internal Component(ResponseObjects.Component respComponent)
{
_rawSubcomponents = respComponent.SubcomponentIds ?? Enumerable.Empty<string>();

Id = respComponent.Id;
Name = respComponent.Name;
Description = respComponent.Description;
DisplayPosition = respComponent.Position;
Status = new StatusDescription(respComponent.Status, null);
}

internal void ProcessSubcomponents(IEnumerable<Component> processedComponents)
{
var componentDictionary = processedComponents.ToDictionary(pc => pc.Id);

Subcomponents = (from id in _rawSubcomponents
where componentDictionary.ContainsKey(id)
select componentDictionary[id]).ToArray();
}

/// <summary>
/// Returns true if the other <see cref="Component"/> instance has the same <see cref="Id"/> as this one.
/// </summary>
/// <param name="other">The other <see cref="Component"/> to compare.</param>
/// <returns>True if the two objects match, false otherwise</returns>
public bool Equals(Component other)
{
return other != null && string.Equals(Id, other.Id, StringComparison.InvariantCultureIgnoreCase);
}

/// <summary>
/// Returns a string that represents the current object.
/// </summary>
/// <returns>A string that represents the current object.</returns>
public override string ToString()
{
return $"{Name} ({Id})";
}

/// <summary>
/// Determines whether the specified object is equal to the current object.
/// </summary>
/// <param name="obj">The object to compare with the current object.</param>
/// <returns>true if the specified object is equal to the current object; otherwise, false.</returns>
public override bool Equals(object obj)
{
return Equals(obj as Component);
}

/// <summary>
/// Serves as the default hash function.
/// </summary>
/// <returns>A hash code for the current object.</returns>
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
}
80 changes: 80 additions & 0 deletions StatusPageClient/Models/ComponentStatusChange.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;

namespace StatusPageClient.Models
{
/// <summary>
/// A change in state for a <see cref="Component"/> associated with an <see cref="IncidentUpdate"/>.
/// </summary>
public class ComponentStatusChange : IEquatable<ComponentStatusChange>
{
/// <summary>
/// The <see cref="Component"/> whose status is changing.
/// </summary>
public Component Component { get; private set; }

/// <summary>
/// The friendly name of this status change.
/// </summary>
public string Name { get; private set; }

/// <summary>
/// The former status of this <see cref="Component"/>.
/// </summary>
public StatusDescription OldStatus { get; private set; }

/// <summary>
/// The status which this <see cref="Component"/> has transitioned to.
/// </summary>
public StatusDescription NewStatus { get; private set; }

internal ComponentStatusChange(ResponseObjects.ComponentImpact respComponentImpact, IEnumerable<Component> componentsLookup)
{
Name = respComponentImpact.Name;
OldStatus = new StatusDescription(respComponentImpact.OldStatus, null);
NewStatus = new StatusDescription(respComponentImpact.NewStatus, null);

Component = componentsLookup.FirstOrDefault(c => string.Equals(c.Id, respComponentImpact.ComponentId, StringComparison.InvariantCultureIgnoreCase));
}

/// <summary>
/// Returns a string that represents the current object.
/// </summary>
/// <returns>A string that represents the current object.</returns>
public override string ToString()
{
return $"{Component}: {OldStatus} -> {NewStatus}";
}

/// <summary>
/// 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.
/// </summary>
/// <param name="other">The other <see cref="ComponentStatusChange"/> to compare.</param>
/// <returns>True if the two objects match, false otherwise</returns>
public bool Equals(ComponentStatusChange other)
{
return other != null && other.Component == Component && other.OldStatus == OldStatus && other.NewStatus == NewStatus;
}

/// <summary>
/// Determines whether the specified object is equal to the current object.
/// </summary>
/// <param name="obj">The object to compare with the current object.</param>
/// <returns>true if the specified object is equal to the current object; otherwise, false.</returns>
public override bool Equals(object obj)
{
return Equals(obj as ComponentStatusChange);
}

/// <summary>
/// Serves as the default hash function.
/// </summary>
/// <returns>A hash code for the current object.</returns>
public override int GetHashCode()
{
return ToString().GetHashCode();
}
}
}
142 changes: 142 additions & 0 deletions StatusPageClient/Models/Incident.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;

namespace StatusPageClient.Models
{
/// <summary>
/// An event relating to a status page and/or its subcomponents.
/// </summary>
public class Incident : IEquatable<Incident>
{
/// <summary>
/// The unique identifier of this incident.
/// </summary>
public string Id { get; private set; }

/// <summary>
/// A friendly name for this incident.
/// </summary>
public string Name { get; private set; }

/// <summary>
/// The URL for this incident.
/// </summary>
public string Shortlink { get; private set; }

/// <summary>
/// The impact this incident had upon <see cref="ImpactedComponents"/>.
/// </summary>
public string Impact { get; private set; }

/// <summary>
/// UTC date that this incident was created.
/// </summary>
public DateTime CreatedOn { get; private set; }

/// <summary>
/// UTC date that this incident was last updated.
/// </summary>
public DateTime UpdatedOn { get; private set; }

/// <summary>
/// If present, the UTC date that this incident began to impact <see cref="ImpactedComponents"/>.
/// </summary>
public DateTime? StartedOn { get; private set; }

/// <summary>
/// If present, the UTC date that this incident was resolved.
/// </summary>
public DateTime? ResolvedOn { get; private set; }

/// <summary>
/// Current status of this incident.
/// </summary>
public StatusDescription Status { get; private set; }

/// <summary>
/// All updates/changes of status for this incident.
/// </summary>
public IEnumerable<IncidentUpdate> Updates { get; private set; }

/// <summary>
/// All components impacted by this incident.
/// </summary>
public IEnumerable<Component> ImpactedComponents { get; private set; }

internal Incident(ResponseObjects.Incident respIncident, IEnumerable<Component> componentsLookup)
{
Id = respIncident.Id;
Name = respIncident.Name;
Shortlink = respIncident.Shortlink;
Impact = respIncident.Impact;

CreatedOn = respIncident.CreatedOn.UtcDateTime;
UpdatedOn = respIncident.UpdatedOn.UtcDateTime;

if (respIncident.StartedOn.HasValue)
{
StartedOn = respIncident.StartedOn.Value.UtcDateTime;
}
if (respIncident.ResolvedOn.HasValue)
{
ResolvedOn = respIncident.ResolvedOn.Value.UtcDateTime;
}

Status = new StatusDescription(respIncident.Status, null);

if (respIncident.ComponentImpacts != null)
{
var componentDictionary = componentsLookup.ToDictionary(c => c.Id);

ImpactedComponents = (from ic in respIncident.ComponentImpacts
where componentDictionary.ContainsKey(ic.Id)
select componentDictionary[ic.Id]).ToArray();
}

if (respIncident.Updates != null)
{
Updates = respIncident.Updates.Select(iu => new IncidentUpdate(iu, componentsLookup)).ToArray();
}
}

/// <summary>
/// Returns a string that represents the current object.
/// </summary>
/// <returns>A string that represents the current object.</returns>
public override string ToString()
{
return $"{Name} ({Id})";
}

/// <summary>
/// Returns true if the other <see cref="Incident"/> instance has the same <see cref="Id"/> as this one.
/// </summary>
/// <param name="other">The other <see cref="Incident"/> to compare.</param>
/// <returns>True if the two objects match, false otherwise</returns>
public bool Equals(Incident other)
{
return other != null && string.Equals(Id, other.Id, StringComparison.InvariantCultureIgnoreCase);
}

/// <summary>
/// Determines whether the specified object is equal to the current object.
/// </summary>
/// <param name="obj">The object to compare with the current object.</param>
/// <returns>true if the specified object is equal to the current object; otherwise, false.</returns>
public override bool Equals(object obj)
{
return Equals(obj as Incident);
}

/// <summary>
/// Serves as the default hash function.
/// </summary>
/// <returns>A hash code for the current object.</returns>
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
}
Loading

0 comments on commit 1c057cb

Please sign in to comment.