-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Uses MEF v.1 and adds User Behaviour.
- Loading branch information
Showing
14 changed files
with
399 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 1,15 @@ | ||
namespace RoyalLondon.IntermediaryManagement.Api.FeatureFlagger.Behaviours | ||
{ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.ComponentModel.Composition; | ||
|
||
[Export(typeof(IBehaviour))] | ||
public class EnabledBehaviour : IBehaviour | ||
{ | ||
public Func<Dictionary<string, string>, bool> Behaviour() | ||
{ | ||
return x => Convert.ToBoolean(x["enabled"]); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 1,10 @@ | ||
namespace RoyalLondon.IntermediaryManagement.Api.FeatureFlagger.Features | ||
{ | ||
/* | ||
* SSO (Single Sign On) will gradually become available so | ||
* this flag is to manage the roll-out. | ||
*/ | ||
public class ExampleFeatureFlagger : IFeatureFlagger | ||
{ | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 1,31 @@ | ||
namespace RoyalLondon.IntermediaryManagement.Api.FeatureFlagger | ||
{ | ||
using System.Collections.Generic; | ||
|
||
public class Feature | ||
{ | ||
public Feature(string name) | ||
{ | ||
this.Flags = new List<Flag>(); | ||
this.Name = name; | ||
} | ||
|
||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1002:DoNotExposeGenericLists", Justification = "Not inherited")] | ||
public Feature(string name, List<Flag> flags) | ||
{ | ||
this.Flags = flags; | ||
this.Name = name; | ||
} | ||
|
||
public string Name { get; private set; } | ||
|
||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1002:DoNotExposeGenericLists", Justification = "Not inherited")] | ||
public List<Flag> Flags { get; } | ||
|
||
public Feature Add(Flag flag) | ||
{ | ||
this.Flags.Add(flag); | ||
return this; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 1,63 @@ | ||
namespace RoyalLondon.IntermediaryManagement.Api.FeatureFlagger | ||
{ | ||
using System.Collections.Generic; | ||
using System.ComponentModel.Composition; | ||
using System.ComponentModel.Composition.Hosting; | ||
using System.Configuration; | ||
using System.Reflection; | ||
|
||
using RoyalLondon.IntermediaryManagement.Api.FeatureFlagger.Behaviours; | ||
|
||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1724:TypeNamesShouldNotMatchNamespaces", Justification = "Naming is hard")] | ||
public sealed class FeatureFlagger | ||
{ | ||
static FeatureFlagger() | ||
{ | ||
// ReSharper disable once ObjectCreationAsStatement | ||
new FeatureFlagger(); | ||
} | ||
|
||
private FeatureFlagger() | ||
{ | ||
SetBehaviours(); | ||
SetFeatures(); | ||
} | ||
|
||
[ImportMany] | ||
public static IEnumerable<IBehaviour> Behaviours { get; private set; } | ||
|
||
public static IEnumerable<Feature> Features { get; private set; } | ||
|
||
private static void SetFeatures() | ||
{ | ||
Features = | ||
(List<Feature>)ConfigurationManager.GetSection("features"); | ||
} | ||
|
||
private void SetBehaviours() | ||
{ | ||
// wouldn't it be nice if Microsoft.Composition was available? | ||
var catalog = new AggregateCatalog(); | ||
try | ||
{ | ||
catalog.Catalogs.Add( | ||
new AssemblyCatalog( | ||
typeof(IBehaviour).GetTypeInfo().Assembly)); | ||
var container = new CompositionContainer(catalog); | ||
try | ||
{ | ||
container.SatisfyImportsOnce(this); | ||
Behaviours = container.GetExportedValues<IBehaviour>(); | ||
} | ||
finally | ||
{ | ||
container.Dispose(); | ||
} | ||
} | ||
finally | ||
{ | ||
catalog.Dispose(); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 1,45 @@ | ||
namespace RoyalLondon.IntermediaryManagement.Api.FeatureFlagger | ||
{ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
|
||
public static class FeatureFlaggerExtensions | ||
{ | ||
public static bool IsEnabled(this IFeatureFlagger featureFlagger) | ||
{ | ||
var behaviours = FeatureFlagger.Behaviours.ToList(); | ||
var flags = GetFlags(featureFlagger); | ||
|
||
return !(from flag in flags | ||
let behaviour = | ||
behaviours.FirstOrDefault( | ||
b => | ||
b.GetType() | ||
.Name.ToUpperInvariant() | ||
.Contains(flag.Name.ToUpperInvariant())) | ||
let func = behaviour.Behaviour() | ||
where func(flag.Properties) == false | ||
select flag).Any(); | ||
} | ||
|
||
private static IEnumerable<Flag> GetFlags(IFeatureFlagger featureFlagger) | ||
{ | ||
var featureName = | ||
featureFlagger.GetType().Name | ||
.Replace("FeatureFlagger", string.Empty); | ||
var feature = | ||
FeatureFlagger.Features.ToList() | ||
.Find( | ||
f => | ||
f.Name.Equals( | ||
featureName, | ||
StringComparison.OrdinalIgnoreCase)); | ||
|
||
// always add the feature name to each flag as a property. | ||
feature.Flags.ForEach(f => f.Add("feature", feature.Name)); | ||
|
||
return feature.Flags; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 1,75 @@ | ||
namespace RoyalLondon.IntermediaryManagement.Api.FeatureFlagger | ||
{ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Configuration; | ||
using System.Globalization; | ||
using System.Linq; | ||
using System.Xml; | ||
|
||
public class FeaturesSection : IConfigurationSectionHandler | ||
{ | ||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes", MessageId = "System.Xml.XmlNode", Justification = "Standard method")] | ||
public object Create( | ||
object parent, | ||
object configContext, | ||
XmlNode section) | ||
{ | ||
var features = new List<Feature>(); | ||
|
||
foreach (XmlNode childNode in section.ChildNodes) | ||
{ | ||
var flag = EnabledFlag(childNode.Attributes); | ||
var feature = | ||
new Feature( | ||
childNode.Attributes?.GetNamedItem("name").InnerText); | ||
feature.Flags.Add(flag); | ||
|
||
foreach (XmlNode node in childNode.ChildNodes) | ||
{ | ||
if (node.Attributes == null) | ||
{ | ||
continue; | ||
} | ||
|
||
var attrs = | ||
node.Attributes.Cast<XmlAttribute>() | ||
.ToDictionary( | ||
attr => attr.Name, | ||
attr => attr.InnerText); | ||
|
||
// title case is required when looking up Behaviours. | ||
var info = new CultureInfo("en-US").TextInfo; | ||
var name = info.ToLower(node.Name); | ||
|
||
feature.Flags.Add(new Flag(name, attrs)); | ||
} | ||
|
||
features.Add(feature); | ||
} | ||
|
||
return features; | ||
} | ||
|
||
private static Flag EnabledFlag(XmlAttributeCollection attributes) | ||
{ | ||
string enabled = null; | ||
if (attributes != null) | ||
{ | ||
enabled = attributes.GetNamedItem("enabled").InnerText; | ||
} | ||
|
||
if (string.IsNullOrWhiteSpace(enabled)) | ||
{ | ||
throw new ArgumentException("enabled attribute is required"); | ||
} | ||
|
||
var flag = | ||
new Flag( | ||
"Enabled", | ||
new Dictionary<string, string> { { "enabled", enabled } }); | ||
|
||
return flag; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 1,29 @@ | ||
namespace RoyalLondon.IntermediaryManagement.Api.FeatureFlagger | ||
{ | ||
using System.Collections.Generic; | ||
|
||
public class Flag | ||
{ | ||
public Flag(string name) | ||
{ | ||
this.Properties = new Dictionary<string, string>(); | ||
this.Name = name; | ||
} | ||
|
||
public Flag(string name, Dictionary<string, string> properties) | ||
{ | ||
this.Properties = properties; | ||
this.Name = name; | ||
} | ||
|
||
public string Name { get; private set; } | ||
|
||
public Dictionary<string, string> Properties { get; } | ||
|
||
public Flag Add(string key, string value) | ||
{ | ||
this.Properties.Add(key, value); | ||
return this; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 1,15 @@ | ||
namespace RoyalLondon.IntermediaryManagement.Api.FeatureFlagger.Behaviours | ||
{ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.ComponentModel.Composition; | ||
|
||
[Export(typeof(IBehaviour))] | ||
public class FromBehaviour : IBehaviour | ||
{ | ||
public Func<Dictionary<string, string>, bool> Behaviour() | ||
{ | ||
return x => DateTime.UtcNow.Date >= DateTime.Parse(x["date"]).Date; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 1,10 @@ | ||
namespace RoyalLondon.IntermediaryManagement.Api.FeatureFlagger.Behaviours | ||
{ | ||
using System; | ||
using System.Collections.Generic; | ||
|
||
public interface IBehaviour | ||
{ | ||
Func<Dictionary<string, string>, bool> Behaviour(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 1,6 @@ | ||
namespace RoyalLondon.IntermediaryManagement.Api.FeatureFlagger | ||
{ | ||
public interface IFeatureFlagger | ||
{ | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 1,9 @@ | ||
namespace RoyalLondon.IntermediaryManagement.Api.FeatureFlagger.Behaviours | ||
{ | ||
public interface IUser | ||
{ | ||
string UserName(); | ||
|
||
bool UserHasFeature(string userName, string featureName); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 1,45 @@ | ||
namespace RoyalLondon.IntermediaryManagement.Api.FeatureFlagger.Behaviours | ||
{ | ||
using System; | ||
using System.ComponentModel.Composition; | ||
using System.Linq; | ||
|
||
using RoyalLondon.IntermediaryManagement.Api.Entities; | ||
|
||
[Export(typeof(IUser))] | ||
public class User : IUser | ||
{ | ||
public bool UserHasFeature(string userName, string featureName) | ||
{ | ||
IntermediaryManagement_DB context = null; | ||
try | ||
{ | ||
context = IntermediariesContainerFactory.Create(); | ||
var user = | ||
context.Users.FirstOrDefault( | ||
u => | ||
u.Name.Equals( | ||
userName, | ||
StringComparison.OrdinalIgnoreCase)); | ||
var hasFeature = | ||
user?.Features.Any( | ||
f => | ||
f.Name.Equals( | ||
featureName, | ||
StringComparison.OrdinalIgnoreCase)); | ||
|
||
return hasFeature == true; | ||
} | ||
finally | ||
{ | ||
context?.Dispose(); | ||
} | ||
} | ||
|
||
public string UserName() | ||
{ | ||
// TODO: get the authorised user from SSO. | ||
return "dummy"; | ||
} | ||
} | ||
} |
Oops, something went wrong.