Browse Source

Add project files.

pull/1/head
Sebastian Stehle 9 years ago
parent
commit
33517f8d9e
  1. 5
      .nuget/nuget.config
  2. 29
      .vscode/settings.json
  3. 82
      PinkParrot.sln
  4. 84
      PinkParrot.sln.DotSettings
  5. 6
      global.json
  6. 25
      src/PinkParrot/PinkParrot.xproj
  7. 28
      src/PinkParrot/Program.cs
  8. 187
      src/PinkParrot/Project_Readme.html
  9. 27
      src/PinkParrot/Properties/launchSettings.json
  10. 41
      src/PinkParrot/Startup.cs
  11. 48
      src/PinkParrot/project.json
  12. 14
      src/PinkParrot/web.config
  13. 19
      src/pinkparrot_core/PinkParrot.Core.Tests/PinkParrot.Core.Tests.xproj
  14. 29
      src/pinkparrot_core/PinkParrot.Core.Tests/project.json
  15. 5
      src/pinkparrot_core/PinkParrot.Core.Tests/xunit.runner.json
  16. 19
      src/pinkparrot_core/PinkParrot.Core/PinkParrot.Core.xproj
  17. 200
      src/pinkparrot_core/PinkParrot.Core/Schema/ModelField.cs
  18. 21
      src/pinkparrot_core/PinkParrot.Core/Schema/ModelFieldFactory.cs
  19. 177
      src/pinkparrot_core/PinkParrot.Core/Schema/ModelSchema.cs
  20. 81
      src/pinkparrot_core/PinkParrot.Core/Schema/ModelSchemaMetadata.cs
  21. 95
      src/pinkparrot_core/PinkParrot.Core/Schema/NumberField.cs
  22. 26
      src/pinkparrot_core/PinkParrot.Core/project.json
  23. 234
      src/pinkparrot_events/PinkParrot.Events/.gitignore
  24. 19
      src/pinkparrot_events/PinkParrot.Events/PinkParrot.Events.xproj
  25. 22
      src/pinkparrot_events/PinkParrot.Events/Schema/ModelFieldAdded.cs
  26. 18
      src/pinkparrot_events/PinkParrot.Events/Schema/ModelFieldDeleted.cs
  27. 18
      src/pinkparrot_events/PinkParrot.Events/Schema/ModelFieldDisabled.cs
  28. 18
      src/pinkparrot_events/PinkParrot.Events/Schema/ModelFieldEnabled.cs
  29. 18
      src/pinkparrot_events/PinkParrot.Events/Schema/ModelFieldHidden.cs
  30. 18
      src/pinkparrot_events/PinkParrot.Events/Schema/ModelFieldShown.cs
  31. 21
      src/pinkparrot_events/PinkParrot.Events/Schema/ModelFieldUpdated.cs
  32. 17
      src/pinkparrot_events/PinkParrot.Events/Schema/ModelSchemaCreated.cs
  33. 16
      src/pinkparrot_events/PinkParrot.Events/Schema/ModelSchemaDeleted.cs
  34. 20
      src/pinkparrot_events/PinkParrot.Events/Schema/ModelSchemaUpdated.cs
  35. 24
      src/pinkparrot_events/PinkParrot.Events/project.json
  36. 169
      src/pinkparrot_infrastructure/PinkParrot.Infrastructure.Tests/CollectionExtensionsTest.cs
  37. 29
      src/pinkparrot_infrastructure/PinkParrot.Infrastructure.Tests/EnumExtensionsTest.cs
  38. 128
      src/pinkparrot_infrastructure/PinkParrot.Infrastructure.Tests/GuardTests.cs
  39. 19
      src/pinkparrot_infrastructure/PinkParrot.Infrastructure.Tests/PinkParrot.Infrastructure.Tests.xproj
  40. 281
      src/pinkparrot_infrastructure/PinkParrot.Infrastructure.Tests/PropertiesBagTests.cs
  41. 29
      src/pinkparrot_infrastructure/PinkParrot.Infrastructure.Tests/project.json
  42. 5
      src/pinkparrot_infrastructure/PinkParrot.Infrastructure.Tests/xunit.runner.json
  43. 19
      src/pinkparrot_infrastructure/PinkParrot.Infrastructure/CQRS/CommonHeaders.cs
  44. 105
      src/pinkparrot_infrastructure/PinkParrot.Infrastructure/CQRS/DomainObject.cs
  45. 54
      src/pinkparrot_infrastructure/PinkParrot.Infrastructure/CQRS/Envelope.cs
  46. 77
      src/pinkparrot_infrastructure/PinkParrot.Infrastructure/CQRS/EnvelopeExtensions.cs
  47. 24
      src/pinkparrot_infrastructure/PinkParrot.Infrastructure/CQRS/EnvelopeFactory.cs
  48. 24
      src/pinkparrot_infrastructure/PinkParrot.Infrastructure/CQRS/EnvelopeHeaders.cs
  49. 28
      src/pinkparrot_infrastructure/PinkParrot.Infrastructure/CQRS/IAggregate.cs
  50. 13
      src/pinkparrot_infrastructure/PinkParrot.Infrastructure/CQRS/IEvent.cs
  51. 110
      src/pinkparrot_infrastructure/PinkParrot.Infrastructure/CollectionExtensions.cs
  52. 48
      src/pinkparrot_infrastructure/PinkParrot.Infrastructure/DomainValidationException.cs
  53. 27
      src/pinkparrot_infrastructure/PinkParrot.Infrastructure/EnumExtensions.cs
  54. 29
      src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Extensions.cs
  55. 240
      src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Guard.cs
  56. 21
      src/pinkparrot_infrastructure/PinkParrot.Infrastructure/PinkParrot.Infrastructure.xproj
  57. 94
      src/pinkparrot_infrastructure/PinkParrot.Infrastructure/PropertiesBag.cs
  58. 211
      src/pinkparrot_infrastructure/PinkParrot.Infrastructure/PropertyValue.cs
  59. 19
      src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Tasks/TaskExtensions.cs
  60. 26
      src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Tasks/TaskHelper.cs
  61. 20
      src/pinkparrot_infrastructure/PinkParrot.Infrastructure/project.json
  62. 234
      src/pinkparrot_write/PinkParrot.Write/.gitignore
  63. 19
      src/pinkparrot_write/PinkParrot.Write/PinkParrot.Write.xproj
  64. 21
      src/pinkparrot_write/PinkParrot.Write/Schema/Commands/AddModelField.cs
  65. 19
      src/pinkparrot_write/PinkParrot.Write/Schema/Commands/CreateModelSchema.cs
  66. 19
      src/pinkparrot_write/PinkParrot.Write/Schema/Commands/DeleteModelField.cs
  67. 17
      src/pinkparrot_write/PinkParrot.Write/Schema/Commands/DeleteModelSchema.cs
  68. 19
      src/pinkparrot_write/PinkParrot.Write/Schema/Commands/DisableModelField.cs
  69. 19
      src/pinkparrot_write/PinkParrot.Write/Schema/Commands/EnableModelField.cs
  70. 19
      src/pinkparrot_write/PinkParrot.Write/Schema/Commands/HideModelField.cs
  71. 19
      src/pinkparrot_write/PinkParrot.Write/Schema/Commands/ShowModelField.cs
  72. 22
      src/pinkparrot_write/PinkParrot.Write/Schema/Commands/UpdateModelField.cs
  73. 22
      src/pinkparrot_write/PinkParrot.Write/Schema/Commands/UpdateModelSchema.cs
  74. 196
      src/pinkparrot_write/PinkParrot.Write/Schema/ModelSchemaDomainObject.cs
  75. 26
      src/pinkparrot_write/PinkParrot.Write/project.json

5
.nuget/nuget.config

@ -0,0 +1,5 @@
<configuration>
<packageSources>
<add key="Qooroo" value="https://www.myget.org/F/qooroo/api/v2" />
</packageSources>
</configuration>

29
.vscode/settings.json

@ -0,0 +1,29 @@
{
// Controls if the editor shows reference information for the modes that support it
"editor.referenceInfos": false,
// When opening a file, `editor.tabSize` and `editor.insertSpaces` will be detected based on the file contents.
"editor.detectIndentation": false,
// Typescript version from local package to be consistent
"typescript.tsdk": "node_modules/typescript/lib",
// Configure glob patterns for excluding files and folders.
"files.exclude": {
"_test-output": true,
"**/node_modules": true,
"**/artifacts": true,
"**/build": true,
"**/out": true,
"**/obj": true,
"**/bin": true,
"**/*.lock.json": true,
"**/*.bat": true,
"**/*.sln": true,
"**/*.sln.DotSettings": true,
"**/*.user": true,
"**/*.xproj": true,
"**/*.gitattributes": true,
".vs:": true
}
}

82
PinkParrot.sln

@ -0,0 +1,82 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{24A3171D-2905-49C9-8A49-A473799014E8}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4B5539DB-F68E-4DBA-B22A-72B9FE7FE2D8}"
ProjectSection(SolutionItems) = preProject
global.json = global.json
EndProjectSection
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "PinkParrot", "src\PinkParrot\PinkParrot.xproj", "{61F6BBCE-A080-4400-B194-70E2F5D2096E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "pinkparrot_infrastructure", "pinkparrot_infrastructure", "{8CF53B92-5EB1-461D-98F8-70DA9B603FBF}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "pinkparrot_core", "pinkparrot_core", "{4C6B06C2-6D77-4E0E-AE32-D7050236433A}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "PinkParrot.Core.Tests", "src\pinkparrot_core\PinkParrot.Core.Tests\PinkParrot.Core.Tests.xproj", "{4A27B9DE-F553-4A82-B866-A29EF8A5A0AF}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "PinkParrot.Core", "src\pinkparrot_core\PinkParrot.Core\PinkParrot.Core.xproj", "{47F3C27E-698B-4EDF-A7E8-D7F4232AFBB0}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "PinkParrot.Infrastructure.Tests", "src\pinkparrot_infrastructure\PinkParrot.Infrastructure.Tests\PinkParrot.Infrastructure.Tests.xproj", "{840C02B1-48F8-4C8A-8862-8A3FDEFDE8D5}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "PinkParrot.Infrastructure", "src\pinkparrot_infrastructure\PinkParrot.Infrastructure\PinkParrot.Infrastructure.xproj", "{BD1C30A8-8FFA-4A92-A9BD-B67B1CDDD84C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "pinkparrot_events", "pinkparrot_events", "{6AE39761-FD74-45CD-99CF-73D3D2E5D064}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "PinkParrot.Events", "src\pinkparrot_events\PinkParrot.Events\PinkParrot.Events.xproj", "{25F66C64-058A-4D44-BC0C-F12A054F9A91}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "pinkparrot_write", "pinkparrot_write", "{4AED438F-684F-4FAE-B016-21CF2EAEA79F}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "PinkParrot.Write", "src\pinkparrot_write\PinkParrot.Write\PinkParrot.Write.xproj", "{A85201C6-6AF8-4B63-8365-08F741050438}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{61F6BBCE-A080-4400-B194-70E2F5D2096E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{61F6BBCE-A080-4400-B194-70E2F5D2096E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{61F6BBCE-A080-4400-B194-70E2F5D2096E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{61F6BBCE-A080-4400-B194-70E2F5D2096E}.Release|Any CPU.Build.0 = Release|Any CPU
{4A27B9DE-F553-4A82-B866-A29EF8A5A0AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4A27B9DE-F553-4A82-B866-A29EF8A5A0AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4A27B9DE-F553-4A82-B866-A29EF8A5A0AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4A27B9DE-F553-4A82-B866-A29EF8A5A0AF}.Release|Any CPU.Build.0 = Release|Any CPU
{47F3C27E-698B-4EDF-A7E8-D7F4232AFBB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{47F3C27E-698B-4EDF-A7E8-D7F4232AFBB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{47F3C27E-698B-4EDF-A7E8-D7F4232AFBB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{47F3C27E-698B-4EDF-A7E8-D7F4232AFBB0}.Release|Any CPU.Build.0 = Release|Any CPU
{840C02B1-48F8-4C8A-8862-8A3FDEFDE8D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{840C02B1-48F8-4C8A-8862-8A3FDEFDE8D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{840C02B1-48F8-4C8A-8862-8A3FDEFDE8D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{840C02B1-48F8-4C8A-8862-8A3FDEFDE8D5}.Release|Any CPU.Build.0 = Release|Any CPU
{BD1C30A8-8FFA-4A92-A9BD-B67B1CDDD84C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BD1C30A8-8FFA-4A92-A9BD-B67B1CDDD84C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BD1C30A8-8FFA-4A92-A9BD-B67B1CDDD84C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BD1C30A8-8FFA-4A92-A9BD-B67B1CDDD84C}.Release|Any CPU.Build.0 = Release|Any CPU
{25F66C64-058A-4D44-BC0C-F12A054F9A91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{25F66C64-058A-4D44-BC0C-F12A054F9A91}.Debug|Any CPU.Build.0 = Debug|Any CPU
{25F66C64-058A-4D44-BC0C-F12A054F9A91}.Release|Any CPU.ActiveCfg = Release|Any CPU
{25F66C64-058A-4D44-BC0C-F12A054F9A91}.Release|Any CPU.Build.0 = Release|Any CPU
{A85201C6-6AF8-4B63-8365-08F741050438}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A85201C6-6AF8-4B63-8365-08F741050438}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A85201C6-6AF8-4B63-8365-08F741050438}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A85201C6-6AF8-4B63-8365-08F741050438}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{61F6BBCE-A080-4400-B194-70E2F5D2096E} = {24A3171D-2905-49C9-8A49-A473799014E8}
{4A27B9DE-F553-4A82-B866-A29EF8A5A0AF} = {4C6B06C2-6D77-4E0E-AE32-D7050236433A}
{47F3C27E-698B-4EDF-A7E8-D7F4232AFBB0} = {4C6B06C2-6D77-4E0E-AE32-D7050236433A}
{840C02B1-48F8-4C8A-8862-8A3FDEFDE8D5} = {8CF53B92-5EB1-461D-98F8-70DA9B603FBF}
{BD1C30A8-8FFA-4A92-A9BD-B67B1CDDD84C} = {8CF53B92-5EB1-461D-98F8-70DA9B603FBF}
{25F66C64-058A-4D44-BC0C-F12A054F9A91} = {6AE39761-FD74-45CD-99CF-73D3D2E5D064}
{A85201C6-6AF8-4B63-8365-08F741050438} = {4AED438F-684F-4FAE-B016-21CF2EAEA79F}
EndGlobalSection
EndGlobal

84
PinkParrot.sln.DotSettings

@ -0,0 +1,84 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002Aapp_002A_002A_002Ejs/@EntryIndexedValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002Aapp_002A_002A_002Ejs/@EntryIndexRemoved">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002Aapp_002F_002A_002A_002F_002A_002Ejs/@EntryIndexedValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002A_002Fapp_002F_002A_002A_002F_002A_002Ejs/@EntryIndexedValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002A_002Fapp_002F_002A_002A_002F_002A_002Ejs/@EntryIndexRemoved">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Ecshtml/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Ed_002Ets/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Ejs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002Aapp_002F_002A_002A_002F_002A_002Ejs/@EntryIndexRemoved">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Ets/@EntryIndexedValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/ExcludedFiles/FileMasksToSkip/=_002A_002Ets/@EntryIndexRemoved">True</s:Boolean>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=A2569FB7_002D99E7_002D48B4_002DB97F_002DE48B6F57E492_002Fd_003Awwwroot_002Fd_003Anode_005Fmodules/@EntryIndexedValue">ExplicitlyExcluded</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertMethodToExpressionBody/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertPropertyToExpressionBody/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertToAutoProperty/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ConvertToAutoPropertyWhenPossible/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=Html_002ETagNotResolved/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=InconsistentNaming/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=MissingHasOwnPropertyInForeach/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FBuiltInTypes/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FElsewhere/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FSimpleTypes/@EntryIndexedValue">SUGGESTION</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=TsResolvedFromInaccessibleModule/@EntryIndexedValue">DO_NOT_SHOW</s:String>
<s:String x:Key="/Default/CodeInspection/TypeScriptInspections/Level/@EntryValue">TypeScript16</s:String>
<s:String x:Key="/Default/CodeStyle/CodeCleanup/Profiles/=Namespaces/@EntryIndexedValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;Profile name="Namespaces"&gt;&lt;CSOptimizeUsings&gt;&lt;OptimizeUsings&gt;True&lt;/OptimizeUsings&gt;&lt;EmbraceInRegion&gt;False&lt;/EmbraceInRegion&gt;&lt;RegionName&gt;&lt;/RegionName&gt;&lt;/CSOptimizeUsings&gt;&lt;CSUpdateFileHeader&gt;True&lt;/CSUpdateFileHeader&gt;&lt;/Profile&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/CodeCleanup/Profiles/=Typescript/@EntryIndexedValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;Profile name="Typescript"&gt;&lt;JsInsertSemicolon&gt;True&lt;/JsInsertSemicolon&gt;&lt;FormatAttributeQuoteDescriptor&gt;True&lt;/FormatAttributeQuoteDescriptor&gt;&lt;CorrectVariableKindsDescriptor&gt;True&lt;/CorrectVariableKindsDescriptor&gt;&lt;VariablesToInnerScopesDescriptor&gt;True&lt;/VariablesToInnerScopesDescriptor&gt;&lt;StringToTemplatesDescriptor&gt;True&lt;/StringToTemplatesDescriptor&gt;&lt;RemoveRedundantQualifiersTs&gt;True&lt;/RemoveRedundantQualifiersTs&gt;&lt;OptimizeImportsTs&gt;True&lt;/OptimizeImportsTs&gt;&lt;/Profile&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/CodeCleanup/SilentCleanupProfile/@EntryValue"></s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/JavaScriptCodeFormatting/QUOTE_STYLE/@EntryValue">SingleQuoted</s:String>
<s:String x:Key="/Default/CodeStyle/FileHeader/FileHeaderText/@EntryValue">==========================================================================&#xD;
$FILENAME$&#xD;
PinkParrot Headless CMS&#xD;
==========================================================================&#xD;
Copyright (c) PinkParrot Group&#xD;
All rights reserved.&#xD;
==========================================================================</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FCONSTANT/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FFUNCTION/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FVARIABLE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FCLASS/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FCONSTRUCTOR/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FFUNCTION/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FGLOBAL_005FVARIABLE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FLABEL/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FLOCAL_005FCONSTRUCTOR/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FLOCAL_005FVARIABLE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FOBJECT_005FPROPERTY_005FOF_005FFUNCTION/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FPARAMETER/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FCLASS/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FENUM/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FENUM_005FMEMBER/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FINTERFACE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FMODULE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FMODULE_005FEXPORTED/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FMODULE_005FLOCAL/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPRIVATE_005FMEMBER_005FACCESSOR/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPRIVATE_005FSTATIC_005FTYPE_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPRIVATE_005FTYPE_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPRIVATE_005FTYPE_005FMETHOD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPROTECTED_005FMEMBER_005FACCESSOR/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPROTECTED_005FSTATIC_005FTYPE_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPROTECTED_005FTYPE_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPROTECTED_005FTYPE_005FMETHOD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPUBLIC_005FMEMBER_005FACCESSOR/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPUBLIC_005FSTATIC_005FTYPE_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPUBLIC_005FTYPE_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FPUBLIC_005FTYPE_005FMETHOD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=TS_005FTYPE_005FPARAMETER/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/WebNaming/UserRules/=ASP_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/WebNaming/UserRules/=ASP_005FHTML_005FCONTROL/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/WebNaming/UserRules/=ASP_005FTAG_005FNAME/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/WebNaming/UserRules/=ASP_005FTAG_005FPREFIX/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/UserRules/=NAMESPACE_005FALIAS/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/UserRules/=XAML_005FFIELD/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/XamlNaming/UserRules/=XAML_005FRESOURCE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:Boolean x:Key="/Default/CodeStyle/TypeScriptCodeStyle/ExplicitPublicModifier/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002EJavaScript_002ECodeStyle_002ESettingsUpgrade_002EJsWrapperSettingsUpgrader/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

6
global.json

@ -0,0 +1,6 @@
{
"projects": [ "src" ],
"sdk": {
"version": "1.0.0-preview2-003121"
}
}

25
src/PinkParrot/PinkParrot.xproj

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>61f6bbce-a080-4400-b194-70e2f5d2096e</ProjectGuid>
<RootNamespace>PinkParrot</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<ItemGroup>
<DnxInvisibleContent Include="bower.json" />
<DnxInvisibleContent Include=".bowerrc" />
</ItemGroup>
<Import Project="$(VSToolsPath)\DotNet.Web\Microsoft.DotNet.Web.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

28
src/PinkParrot/Program.cs

@ -0,0 +1,28 @@
// ==========================================================================
// Program.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System.IO;
using Microsoft.AspNetCore.Hosting;
namespace PinkParrot
{
public class Program
{
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
host.Run();
}
}
}

187
src/PinkParrot/Project_Readme.html

@ -0,0 +1,187 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Welcome to ASP.NET Core</title>
<style>
html {
background: #f1f1f1;
height: 100%;
}
body {
background: #fff;
color: #505050;
font: 14px 'Segoe UI', tahoma, arial, helvetica, sans-serif;
margin: 1%;
min-height: 95.5%;
border: 1px solid silver;
position: relative;
}
#header {
padding: 0;
}
#header h1 {
font-size: 44px;
font-weight: normal;
margin: 0;
padding: 10px 30px 10px 30px;
}
#header span {
margin: 0;
padding: 0 30px;
display: block;
}
#header p {
font-size: 20px;
color: #fff;
background: #007acc;
padding: 0 30px;
line-height: 50px;
margin-top: 25px;
}
#header p a {
color: #fff;
text-decoration: underline;
font-weight: bold;
padding-right: 35px;
background: no-repeat right bottom url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAAWCAMAAAAcqPc3AAAANlBMVEUAAAAAeswfitI9mthXp91us+KCvuaTx+mjz+2x1u+83PLH4vTR5/ba7Pjj8Pns9fv1+v3////wy3dWAAAAAXRSTlMAQObYZgAAAHxJREFUeNp9kVcSwCAIRMHUYoH7XzaxOxJ9P8oyQ1uIqNPwh3s2aLmIM2YtqrLcQIeQEylhuCeUOlhgve5yoBCfWmlnlgkN4H8ykbpaE7gR03AbUHiwoOxUH9Xp+ubd41p1HF3mBPrfC87BHeTdaB3ceeKL9HGpcvX9zu6+DdMWT9KQPvYAAAAASUVORK5CYII=);
}
#main {
padding: 5px 30px;
clear: both;
}
.section {
width: 21.7%;
float: left;
margin: 0 0 0 4%;
}
.section h2 {
font-size: 13px;
text-transform: uppercase;
margin: 0;
border-bottom: 1px solid silver;
padding-bottom: 12px;
margin-bottom: 8px;
}
.section.first {
margin-left: 0;
}
.section.first h2 {
font-size: 24px;
text-transform: none;
margin-bottom: 25px;
border: none;
}
.section.first li {
border-top: 1px solid silver;
padding: 8px 0;
}
.section.last {
margin-right: 0;
}
ul {
list-style: none;
padding: 0;
margin: 0;
line-height: 20px;
}
li {
padding: 4px 0;
}
a {
color: #267cb2;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
#footer {
clear: both;
padding-top: 50px;
}
#footer p {
position: absolute;
bottom: 10px;
}
</style>
</head>
<body>
<div id="header">
<h1>Welcome to ASP.NET Core</h1>
<span>
We've made some big updates in this release, so it’s <b>important</b> that you spend
a few minutes to learn what’s new.
</span>
<p>You've created a new ASP.NET Core project. <a href="http://go.microsoft.com/fwlink/?LinkId=518016">Learn what's new</a></p>
</div>
<div id="main">
<div class="section first">
<h2>This application consists of:</h2>
<ul>
<li>Sample pages using ASP.NET Core MVC</li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=518004">Bower</a> for managing client-side libraries</li>
<li>Theming using <a href="http://go.microsoft.com/fwlink/?LinkID=398939">Bootstrap</a></li>
</ul>
</div>
<div class="section">
<h2>How to</h2>
<ul>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=398600">Add a Controller and View</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=699562">Add an appsetting in config and access it in app.</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=699315">Manage User Secrets using Secret Manager.</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=699316">Use logging to log a message.</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=699317">Add packages using NuGet.</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=699318">Add client packages using Bower.</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=699319">Target development, staging or production environment.</a></li>
</ul>
</div>
<div class="section">
<h2>Overview</h2>
<ul>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=518008">Conceptual overview of what is ASP.NET Core</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=699320">Fundamentals of ASP.NET Core such as Startup and middleware.</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=398602">Working with Data</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkId=398603">Security</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=699321">Client side development</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=699322">Develop on different platforms</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=699323">Read more on the documentation site</a></li>
</ul>
</div>
<div class="section last">
<h2>Run & Deploy</h2>
<ul>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=517851">Run your app</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=517853">Run tools such as EF migrations and more</a></li>
<li><a href="http://go.microsoft.com/fwlink/?LinkID=398609">Publish to Microsoft Azure Web Apps</a></li>
</ul>
</div>
<div id="footer">
<p>We would love to hear your <a href="http://go.microsoft.com/fwlink/?LinkId=518015">feedback</a></p>
</div>
</div>
</body>
</html>

27
src/PinkParrot/Properties/launchSettings.json

@ -0,0 +1,27 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:65351/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"PinkParrot": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

41
src/PinkParrot/Startup.cs

@ -0,0 +1,41 @@
// ==========================================================================
// Startup.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace PinkParrot
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World!");
});
}
}
}

48
src/PinkParrot/project.json

@ -0,0 +1,48 @@
{
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.0.0",
"type": "platform"
},
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0"
},
"tools": {
"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"
},
"frameworks": {
"netcoreapp1.0": {
"imports": [
"dotnet5.6",
"portable-net45+win8"
]
}
},
"buildOptions": {
"emitEntryPoint": true,
"preserveCompilationContext": true
},
"runtimeOptions": {
"configProperties": {
"System.GC.Server": true
}
},
"publishOptions": {
"include": [
"wwwroot",
"web.config"
]
},
"scripts": {
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
}
}

14
src/PinkParrot/web.config

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!--
Configure your application settings in appsettings.json. Learn more at http://go.microsoft.com/fwlink/?LinkId=786380
-->
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified"/>
</handlers>
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
</system.webServer>
</configuration>

19
src/pinkparrot_core/PinkParrot.Core.Tests/PinkParrot.Core.Tests.xproj

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0.25420" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25420</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>4a27b9de-f553-4a82-b866-a29ef8a5a0af</ProjectGuid>
<RootNamespace>PinkParrot.Core.Tests</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

29
src/pinkparrot_core/PinkParrot.Core.Tests/project.json

@ -0,0 +1,29 @@
{
"version": "1.0.0-*",
"testRunner": "xunit",
"dependencies": {
"dotnet-test-xunit": "2.2.0-preview2-build1029",
"PinkParrot.Core": "1.0.0-*",
"xunit": "2.2.0-beta2-build3300"
},
"frameworks": {
"netcoreapp1.0": {
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.0"
}
}
}
},
"buildOptions": {
"copyToOutput": {
"include": [
"xunit.runner.json"
]
}
},
"tooling": {
"defaultNamespace": "PinkParrot.Core.Tests"
}
}

5
src/pinkparrot_core/PinkParrot.Core.Tests/xunit.runner.json

@ -0,0 +1,5 @@
{
"diagnosticMessages": false,
"methodDisplay": "classAndMethod",
"parallelizeTestCollections": true
}

19
src/pinkparrot_core/PinkParrot.Core/PinkParrot.Core.xproj

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0.25420" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25420</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>47f3c27e-698b-4edf-a7e8-d7f4232afbb0</ProjectGuid>
<RootNamespace>PinkParrot.Core</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

200
src/pinkparrot_core/PinkParrot.Core/Schema/ModelField.cs

@ -0,0 +1,200 @@
// ==========================================================================
// ModelField.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Threading.Tasks;
using PinkParrot.Infrastructure;
using PinkParrot.Infrastructure.Tasks;
// ReSharper disable ConvertIfStatementToReturnStatement
namespace PinkParrot.Core.Schema
{
public abstract class ModelField
{
private readonly Guid id;
private string name;
private string hint;
private string displayName;
private bool isRequired;
private bool isDisabled;
private bool isHidden;
public Guid Id
{
get { return id; }
}
public string Name
{
get { return name; }
}
public string Hint
{
get { return hint; }
}
public string DisplayName
{
get { return displayName; }
}
public bool IsRequired
{
get { return isRequired; }
}
public bool IsHidden
{
get { return isHidden; }
}
public bool IsDisabled
{
get { return isDisabled; }
}
protected ModelField(Guid id, string name)
{
Guard.NotEmpty(id, nameof(id));
Guard.ValidSlug(name, nameof(name));
this.id = id;
this.name = name;
}
public ModelField Configure(PropertiesBag settings, ICollection<string> errors)
{
var clone = Clone();
if (settings.Contains("Name"))
{
clone.name = settings["Name"].ToString();
if (!clone.name.IsSlug())
{
errors.Add("Field name must be a slug");
}
}
if (settings.Contains("Hint"))
{
clone.hint = settings["Hint"].ToString()?.Trim() ?? string.Empty;
}
if (settings.Contains("DisplayName"))
{
clone.displayName = settings["DisplayName"].ToString()?.Trim() ?? string.Empty;
}
if (settings.Contains("IsRequired"))
{
try
{
clone.isRequired = settings["IsRequired"].ToBoolean(CultureInfo.InvariantCulture);
}
catch (InvalidCastException)
{
errors.Add("IsRequired is not a valid boolean");
}
}
clone.ConfigureCore(settings, errors);
return clone;
}
protected virtual void ConfigureCore(PropertiesBag settings, ICollection<string> errors)
{
}
public Task ValidateAsync(PropertyValue property, ICollection<string> errors)
{
Guard.NotNull(property, nameof(property));
if (isRequired && property.RawValue == null)
{
errors.Add("<Field> is required");
}
if (property.RawValue == null)
{
return TaskHelper.Done;
}
return ValidateCoreAsync(property, errors);
}
protected virtual Task ValidateCoreAsync(PropertyValue property, ICollection<string> errors)
{
return TaskHelper.Done;
}
public ModelField Hide()
{
if (isHidden)
{
throw new DomainValidationException($"The field '{name} is already hidden.");
}
var clone = Clone();
clone.isHidden = true;
return Clone();
}
public ModelField Show()
{
if (!isHidden)
{
throw new DomainValidationException($"The field '{name} is already visible.");
}
var clone = Clone();
clone.isHidden = false;
return Clone();
}
public ModelField Disable()
{
if (isDisabled)
{
throw new DomainValidationException($"The field '{name} is already disabled.");
}
var clone = Clone();
clone.isDisabled = true;
return clone;
}
public ModelField Enable()
{
if (!isDisabled)
{
throw new DomainValidationException($"The field '{name} is already enabled.");
}
var clone = Clone();
clone.isDisabled = false;
return clone;
}
protected abstract ModelField Clone();
}
}

21
src/pinkparrot_core/PinkParrot.Core/Schema/ModelFieldFactory.cs

@ -0,0 +1,21 @@
// ==========================================================================
// ModelFieldFactory.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
namespace PinkParrot.Core.Schema
{
public class ModelFieldFactory
{
public virtual ModelField CreateField(Guid id, string type, string fieldName)
{
return new NumberField(id, fieldName);
}
}
}

177
src/pinkparrot_core/PinkParrot.Core/Schema/ModelSchema.cs

@ -0,0 +1,177 @@
// ==========================================================================
// ModelSchema.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;
using PinkParrot.Infrastructure;
namespace PinkParrot.Core.Schema
{
public sealed class ModelSchema
{
private readonly ModelSchemaMetadata metadata;
private readonly ImmutableDictionary<Guid, ModelField> fields;
private readonly Dictionary<string, ModelField> fieldsByName;
public ModelSchema(ModelSchemaMetadata metadata, ImmutableDictionary<Guid, ModelField> fields)
{
Guard.NotNull(fields, nameof(fields));
Guard.NotNull(metadata, nameof(metadata));
this.fields = fields;
this.metadata = metadata;
fieldsByName = fields.Values.ToDictionary(x => x.Name, StringComparer.OrdinalIgnoreCase);
}
public static ModelSchema Create(string name)
{
if (!name.IsSlug())
{
throw new DomainValidationException("Cannot create the schema.", $"'{name}' is not a valid slug.");
}
return new ModelSchema(new ModelSchemaMetadata(name), ImmutableDictionary<Guid, ModelField>.Empty);
}
public IReadOnlyDictionary<Guid, ModelField> Fields
{
get { return fields; }
}
public ModelSchemaMetadata Metadata
{
get { return metadata; }
}
public ModelSchema Update(ModelSchemaMetadata newMetadata)
{
Guard.NotNull(newMetadata, nameof(newMetadata));
return new ModelSchema(newMetadata, fields);
}
public ModelSchema AddField(Guid id, string type, string fieldName, ModelFieldFactory factory)
{
var field = factory.CreateField(id, type, fieldName);
return SetField(field);
}
public ModelSchema SetField(Guid fieldId, PropertiesBag settings)
{
Guard.NotNull(settings, nameof(settings));
return UpdateField(fieldId, field =>
{
var errors = new List<string>();
var newField = field.Configure(settings, errors);
if (errors.Any())
{
throw new DomainValidationException($"Cannot update field with id '{fieldId}', becase the settings are invalid.", errors);
}
return newField;
});
}
public ModelSchema DisableField(Guid fieldId)
{
return UpdateField(fieldId, field => field.Disable());
}
public ModelSchema EnableField(Guid fieldId)
{
return UpdateField(fieldId, field => field.Enable());
}
public ModelSchema HideField(Guid fieldId)
{
return UpdateField(fieldId, field => field.Show());
}
public ModelSchema ShowField(Guid fieldId)
{
return UpdateField(fieldId, field => field.Show());
}
public ModelSchema SetField(ModelField field)
{
Guard.NotNull(field, nameof(field));
if (fields.Values.Any(f => f.Name == field.Name && f.Id != field.Id))
{
throw new DomainValidationException($"A field with name '{field.Name}' already exists.");
}
return new ModelSchema(metadata, fields.SetItem(field.Id, field));
}
public ModelSchema DeleteField(Guid fieldId)
{
Guard.NotEmpty(fieldId, nameof(fieldId));
if (!fields.ContainsKey(fieldId))
{
throw new DomainValidationException($"A field with id {fieldId} does not exist.");
}
return new ModelSchema(metadata, fields.Remove(fieldId));
}
private ModelSchema UpdateField(Guid fieldId, Func<ModelField, ModelField> updater)
{
ModelField field;
if (!fields.TryGetValue(fieldId, out field))
{
throw new DomainValidationException($"Cannot update field with id '{fieldId}'.", "Field does not exist.");
}
var newField = updater(field);
return SetField(newField);
}
public async Task ValidateAsync(PropertiesBag data)
{
Guard.NotNull(data, nameof(data));
var errors = new List<string>();
foreach (var kvp in data.Properties)
{
ModelField field;
if (fieldsByName.TryGetValue(kvp.Key, out field))
{
var newErrors = new List<string>();
await field.ValidateAsync(kvp.Value, newErrors);
errors.AddRange(newErrors.Select(e => e.Replace("<Field>", "'" + field.Name + "'")));
}
else
{
errors.Add($"'{kvp.Key}' is not a known field");
}
}
if (errors.Any())
{
throw new DomainValidationException("The data is not valid.", errors);
}
}
}
}

81
src/pinkparrot_core/PinkParrot.Core/Schema/ModelSchemaMetadata.cs

@ -0,0 +1,81 @@
// ==========================================================================
// ModelSchemaMetadata.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using PinkParrot.Infrastructure;
namespace PinkParrot.Core.Schema
{
public sealed class ModelSchemaMetadata
{
private string name;
private string displayName;
private string hint;
private string itemTitle;
public string Name
{
get { return name; }
}
public string DisplayName
{
get { return displayName; }
}
public string Hint
{
get { return hint; }
}
public string ItemTitle
{
get { return itemTitle; }
}
public ModelSchemaMetadata(string name)
{
Guard.ValidSlug(name, nameof(name));
this.name = name;
}
public ModelSchemaMetadata Configure(string newName, PropertiesBag properties)
{
Guard.NotNull(properties, nameof(properties));
var clone = (ModelSchemaMetadata) MemberwiseClone();
if (newName != null)
{
if (!newName.IsSlug())
{
throw new DomainValidationException("Cannot update the schema.", $"'{newName}' is not a valid slug.");
}
clone.name = newName;
}
if (properties.Contains("Hint"))
{
clone.hint = properties["Hint"].ToString()?.Trim();
}
if (properties.Contains("DisplayName"))
{
clone.displayName = properties["DisplayName"].ToString()?.Trim();
}
if (properties.Contains("ItemTitle"))
{
clone.itemTitle = properties["ItemTitle"].ToString()?.Trim();
}
return clone;
}
}
}

95
src/pinkparrot_core/PinkParrot.Core/Schema/NumberField.cs

@ -0,0 +1,95 @@
// ==========================================================================
// NumberField.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Threading.Tasks;
using PinkParrot.Infrastructure;
using PinkParrot.Infrastructure.Tasks;
namespace PinkParrot.Core.Schema
{
public sealed class NumberField : ModelField
{
private double? maxValue;
private double? minValue;
public double? MaxValue
{
get { return maxValue; }
}
public double? MinValue
{
get { return minValue; }
}
public NumberField(Guid id, string name)
: base(id, name)
{
}
protected override void ConfigureCore(PropertiesBag settings, ICollection<string> errors)
{
maxValue = ParseNumber("MaxValue", settings, errors);
minValue = ParseNumber("MinValue", settings, errors);
if (maxValue.HasValue && minValue.HasValue && minValue.Value > maxValue.Value)
{
errors.Add("MinValue cannot be larger than max value");
}
}
private static double? ParseNumber(string key, PropertiesBag settings, ICollection<string> errors)
{
try
{
if (settings.Contains(key))
{
return settings[key].ToNullableDouble(CultureInfo.InvariantCulture);
}
}
catch (InvalidCastException)
{
errors.Add($"'{key}' is not a valid number");
}
return null;
}
protected override Task ValidateCoreAsync(PropertyValue property, ICollection<string> errors)
{
try
{
var value = property.ToDouble(CultureInfo.InvariantCulture);
if (MinValue.HasValue && value < MinValue.Value)
{
errors.Add($"<Field> must be greater than {MinValue}");
}
if (MaxValue.HasValue && value > MaxValue.Value)
{
errors.Add($"<Field> must be less than {MaxValue}");
}
}
catch (InvalidCastException)
{
errors.Add("<Field> is not a valid number");
}
return TaskHelper.Done;
}
protected override ModelField Clone()
{
return (ModelField)MemberwiseClone();
}
}
}

26
src/pinkparrot_core/PinkParrot.Core/project.json

@ -0,0 +1,26 @@
{
"version": "1.0.0-*",
"dependencies": {
"EventStore.ClientAPI.DotNetCore": "1.0.0",
"NETStandard.Library": "1.6.0",
"NodaTime": "2.0.0-alpha20160729",
"PinkParrot.Infrastructure": "1.0.0-*",
"protobuf-net": "2.1.0"
},
"frameworks": {
"netcoreapp1.0": {
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.0"
}
}
}
},
"tooling": {
"defaultNamespace": "PinkParrot.Core"
}
}

234
src/pinkparrot_events/PinkParrot.Events/.gitignore

@ -0,0 +1,234 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
build/
bld/
[Bb]in/
[Oo]bj/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Microsoft Azure ApplicationInsights config file
ApplicationInsights.config
# Windows Store app package directory
AppPackages/
BundleArtifacts/
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
# FAKE - F# Make
.fake/

19
src/pinkparrot_events/PinkParrot.Events/PinkParrot.Events.xproj

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0.25420" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25420</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>25f66c64-058a-4d44-bc0c-f12a054f9a91</ProjectGuid>
<RootNamespace>PinkParrot.Events</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

22
src/pinkparrot_events/PinkParrot.Events/Schema/ModelFieldAdded.cs

@ -0,0 +1,22 @@
// ==========================================================================
// ModelFieldAdded.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
using PinkParrot.Infrastructure.CQRS;
namespace PinkParrot.Events.Schema
{
public class ModelFieldAdded : IEvent
{
public Guid FieldId { get; set; }
public string FieldType;
public string FieldName { get; set; }
}
}

18
src/pinkparrot_events/PinkParrot.Events/Schema/ModelFieldDeleted.cs

@ -0,0 +1,18 @@
// ==========================================================================
// ModelFieldDeleted.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
using PinkParrot.Infrastructure.CQRS;
namespace PinkParrot.Events.Schema
{
public class ModelFieldDeleted : IEvent
{
public Guid FieldId;
}
}

18
src/pinkparrot_events/PinkParrot.Events/Schema/ModelFieldDisabled.cs

@ -0,0 +1,18 @@
// ==========================================================================
// ModelFieldDisabled.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
using PinkParrot.Infrastructure.CQRS;
namespace PinkParrot.Events.Schema
{
public class ModelFieldDisabled : IEvent
{
public Guid FieldId;
}
}

18
src/pinkparrot_events/PinkParrot.Events/Schema/ModelFieldEnabled.cs

@ -0,0 +1,18 @@
// ==========================================================================
// ModelFieldEnabled.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
using PinkParrot.Infrastructure.CQRS;
namespace PinkParrot.Events.Schema
{
public class ModelFieldEnabled : IEvent
{
public Guid FieldId;
}
}

18
src/pinkparrot_events/PinkParrot.Events/Schema/ModelFieldHidden.cs

@ -0,0 +1,18 @@
// ==========================================================================
// ModelFieldHidden.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
using PinkParrot.Infrastructure.CQRS;
namespace PinkParrot.Events.Schema
{
public class ModelFieldHidden : IEvent
{
public Guid FieldId;
}
}

18
src/pinkparrot_events/PinkParrot.Events/Schema/ModelFieldShown.cs

@ -0,0 +1,18 @@
// ==========================================================================
// ModelFieldShown.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
using PinkParrot.Infrastructure.CQRS;
namespace PinkParrot.Events.Schema
{
public class ModelFieldShown : IEvent
{
public Guid FieldId;
}
}

21
src/pinkparrot_events/PinkParrot.Events/Schema/ModelFieldUpdated.cs

@ -0,0 +1,21 @@
// ==========================================================================
// ModelFieldUpdated.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
using PinkParrot.Infrastructure;
using PinkParrot.Infrastructure.CQRS;
namespace PinkParrot.Events.Schema
{
public class ModelFieldUpdated : IEvent
{
public Guid FieldId { get; set; }
public PropertiesBag Settings { get; set; }
}
}

17
src/pinkparrot_events/PinkParrot.Events/Schema/ModelSchemaCreated.cs

@ -0,0 +1,17 @@
// ==========================================================================
// ModelSchemaCreated.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using PinkParrot.Infrastructure.CQRS;
namespace PinkParrot.Events.Schema
{
public class ModelSchemaCreated : IEvent
{
public string Name;
}
}

16
src/pinkparrot_events/PinkParrot.Events/Schema/ModelSchemaDeleted.cs

@ -0,0 +1,16 @@
// ==========================================================================
// ModelSchemaDeleted.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using PinkParrot.Infrastructure.CQRS;
namespace PinkParrot.Events.Schema
{
public class ModelSchemaDeleted : IEvent
{
}
}

20
src/pinkparrot_events/PinkParrot.Events/Schema/ModelSchemaUpdated.cs

@ -0,0 +1,20 @@
// ==========================================================================
// ModelSchemaUpdated.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using PinkParrot.Infrastructure;
using PinkParrot.Infrastructure.CQRS;
namespace PinkParrot.Events.Schema
{
public class ModelSchemaUpdated : IEvent
{
public string NewName;
public PropertiesBag Settings { get; set; }
}
}

24
src/pinkparrot_events/PinkParrot.Events/project.json

@ -0,0 +1,24 @@
{
"version": "1.0.0-*",
"dependencies": {
"NETStandard.Library": "1.6.0",
"NodaTime": "2.0.0-alpha20160729",
"PinkParrot.Infrastructure": "1.0.0-*"
},
"frameworks": {
"netcoreapp1.0": {
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.0"
}
}
}
},
"tooling": {
"defaultNamespace": "PinkParrot.Events"
}
}

169
src/pinkparrot_infrastructure/PinkParrot.Infrastructure.Tests/CollectionExtensionsTest.cs

@ -0,0 +1,169 @@
// ==========================================================================
// CollectionExtensionsTest.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using Xunit;
namespace PinkParrot.Infrastructure
{
public class CollectionExtensionTest
{
private readonly Dictionary<int, int> valueDictionary = new Dictionary<int, int>();
private readonly Dictionary<int, List<int>> listDictionary = new Dictionary<int, List<int>>();
[Fact]
public void GetOrDefault_should_return_value_if_key_exists()
{
valueDictionary[12] = 34;
Assert.Equal(34, valueDictionary.GetOrDefault(12));
}
[Fact]
public void GetOrDefault_should_return_default_and_not_add_it_if_key_not_exists()
{
Assert.Equal(0, valueDictionary.GetOrDefault(12));
Assert.False(valueDictionary.ContainsKey(12));
}
[Fact]
public void GetOrAddDefault_should_return_value_if_key_exists()
{
valueDictionary[12] = 34;
Assert.Equal(34, valueDictionary.GetOrAddDefault(12));
}
[Fact]
public void GetOrAddDefault_should_return_default_and_add_it_if_key_not_exists()
{
Assert.Equal(0, valueDictionary.GetOrAddDefault(12));
Assert.Equal(0, valueDictionary[12]);
}
[Fact]
public void GetOrCreate_should_return_value_if_key_exists()
{
valueDictionary[12] = 34;
Assert.Equal(34, valueDictionary.GetOrCreate(12, x => 34));
}
[Fact]
public void GetOrCreate_should_return_default_but_not_add_it_if_key_not_exists()
{
Assert.Equal(24, valueDictionary.GetOrCreate(12, x => 24));
Assert.False(valueDictionary.ContainsKey(12));
}
[Fact]
public void GetOrAdd_should_return_value_if_key_exists()
{
valueDictionary[12] = 34;
Assert.Equal(34, valueDictionary.GetOrAdd(12, x => 34));
}
[Fact]
public void GetOrAdd_should_return_default_and_add_it_if_key_not_exists()
{
Assert.Equal(24, valueDictionary.GetOrAdd(12, x => 24));
Assert.Equal(24, valueDictionary[12]);
}
[Fact]
public void GetOrNew_should_return_value_if_key_exists()
{
var list = new List<int>();
listDictionary[12] = list;
Assert.Equal(list, listDictionary.GetOrNew(12));
}
[Fact]
public void GetOrNew_should_return_default_but_not_add_it_if_key_not_exists()
{
var list = new List<int>();
Assert.Equal(list, listDictionary.GetOrNew(12));
Assert.False(listDictionary.ContainsKey(12));
}
[Fact]
public void GetOrAddNew_should_return_value_if_key_exists()
{
var list = new List<int>();
listDictionary[12] = list;
Assert.Equal(list, listDictionary.GetOrAddNew(12));
}
[Fact]
public void GetOrAddNew_should_return_default_but_not_add_it_if_key_not_exists()
{
var list = new List<int>();
Assert.Equal(list, listDictionary.GetOrAddNew(12));
Assert.Equal(list, listDictionary[12]);
}
[Fact]
public void SequentialHashCode_should_return_same_hash_codes_for_list_with_same_order()
{
var collection1 = new[] { 3, 5, 6 };
var collection2 = new[] { 3, 5, 6 };
Assert.Equal(collection2.SequentialHashCode(), collection1.SequentialHashCode());
}
[Fact]
public void SequentialHashCode_should_return_different_hash_codes_for_list_with_different_items()
{
var collection1 = new[] { 3, 5, 6 };
var collection2 = new[] { 3, 4, 1 };
Assert.NotEqual(collection2.SequentialHashCode(), collection1.SequentialHashCode());
}
[Fact]
public void SequentialHashCode_should_return_different_hash_codes_for_list_with_different_order()
{
var collection1 = new[] { 3, 5, 6 };
var collection2 = new[] { 6, 5, 3 };
Assert.NotEqual(collection2.SequentialHashCode(), collection1.SequentialHashCode());
}
[Fact]
public void OrderedHashCode_should_return_same_hash_codes_for_list_with_same_order()
{
var collection1 = new[] { 3, 5, 6 };
var collection2 = new[] { 3, 5, 6 };
Assert.Equal(collection2.OrderedHashCode(), collection1.OrderedHashCode());
}
[Fact]
public void OrderedHashCode_should_return_different_hash_codes_for_list_with_different_items()
{
var collection1 = new[] { 3, 5, 6 };
var collection2 = new[] { 3, 4, 1 };
Assert.NotEqual(collection2.OrderedHashCode(), collection1.OrderedHashCode());
}
[Fact]
public void OrderedHashCode_should_return_same_hash_codes_for_list_with_different_order()
{
var collection1 = new[] { 3, 5, 6 };
var collection2 = new[] { 6, 5, 3 };
Assert.Equal(collection2.OrderedHashCode(), collection1.OrderedHashCode());
}
}
}

29
src/pinkparrot_infrastructure/PinkParrot.Infrastructure.Tests/EnumExtensionsTest.cs

@ -0,0 +1,29 @@
// ==========================================================================
// EnumExtensionsTest.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
using Xunit;
namespace PinkParrot.Infrastructure
{
public sealed class EnumExtensionsTest
{
[Fact]
public void Should_return_true_if_enum_is_valid()
{
Assert.True(DateTimeKind.Local.IsEnumValue());
}
[Fact]
public void Should_return_false_if_enum_is_not_valid()
{
Assert.False(((DateTimeKind)13).IsEnumValue());
Assert.False(123.IsEnumValue());
}
}
}

128
src/pinkparrot_infrastructure/PinkParrot.Infrastructure.Tests/GuardTests.cs

@ -0,0 +1,128 @@
// ==========================================================================
// GuardTests.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
using Xunit;
namespace PinkParrot.Infrastructure
{
public class GuardTest
{
[Theory]
[InlineData("")]
[InlineData(" ")]
public void Should_throw_when_target_is_null_for_empty_string(string invalidString)
{
Assert.Throws<ArgumentException>(() => Guard.NotNullOrEmpty(invalidString, "parameter"));
}
[Fact]
public void Should_do_nothing_if_target_string_is_valid()
{
Guard.NotNullOrEmpty("value", "parameter");
}
[Fact]
public void Should_do_nothing_if_target_is_not_null()
{
Guard.NotNull("value", "parameter");
}
[Fact]
public void Should_do_nothing_if_enum_is_valid()
{
Guard.Enum(DateTimeKind.Local, "Parameter");
}
[Fact]
public void Should_throw_if_enum_is_not_valid()
{
Assert.Throws<ArgumentException>(() => Guard.Enum((DateTimeKind)13, "Parameter"));
}
[Fact]
public void Should_do_nothing_when_guid_is_not_empty()
{
Guard.NotEmpty(Guid.NewGuid(), "parameter");
}
[Fact]
public void Should_throw_when_guid_is_empty()
{
Assert.Throws<ArgumentException>(() => Guard.NotEmpty(Guid.Empty, "parameter"));
}
[Fact]
public void Should_throw_when_target_is_null()
{
Assert.Throws<ArgumentNullException>(() => Guard.NotNull(null, "parameter"));
}
[Fact]
public void Should_throw_when_target_is_null_for_null_string()
{
Assert.Throws<ArgumentNullException>(() => Guard.NotNullOrEmpty(null, "parameter"));
}
[Fact]
public void Should_do_nothing_when_target_has_correct_type()
{
Guard.HasType<int>(123, "parameter");
}
[Fact]
public void Should_throw_when_target_has_wrong_type()
{
Assert.Throws<ArgumentException>(() => Guard.HasType<int>("value", "parameter"));
}
[Fact]
public void Should_throw_when_checking_for_null_and_target_is_null()
{
Assert.Throws<ArgumentNullException>(() => Guard.HasType<int>(null, "parameter"));
}
[Fact]
public void Should_do_nothing_when_target_is_not_default_value()
{
Guard.NotDefault(Guid.NewGuid(), "parameter");
}
[Fact]
public void Should_throw_exception_when_value_has_default()
{
Assert.Throws<ArgumentException>(() => Guard.NotDefault(Guid.Empty, "parameter"));
Assert.Throws<ArgumentException>(() => Guard.NotDefault(0, "parameter"));
Assert.Throws<ArgumentException>(() => Guard.NotDefault((string)null, "parameter"));
Assert.Throws<ArgumentException>(() => Guard.NotDefault(false, "parameter"));
}
[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData(" Not a Slug ")]
[InlineData(" not--a--slug ")]
[InlineData(" not-a-slug ")]
[InlineData("-not-a-slug-")]
[InlineData("not$-a-slug")]
public void Should_throw_exception_for_invalid_slug(string slug)
{
Assert.Throws<ArgumentException>(() => Guard.ValidSlug(slug, "slug"));
}
[Theory]
[InlineData("slug")]
[InlineData("slug23")]
[InlineData("other-slug")]
[InlineData("just-another-slug")]
public void Should_do_nothing_for_valid_slug(string slug)
{
Guard.ValidSlug(slug, "parameter");
}
}
}

19
src/pinkparrot_infrastructure/PinkParrot.Infrastructure.Tests/PinkParrot.Infrastructure.Tests.xproj

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>840c02b1-48f8-4c8a-8862-8a3fdefde8d5</ProjectGuid>
<RootNamespace>PinkParrot.Infrastructure</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

281
src/pinkparrot_infrastructure/PinkParrot.Infrastructure.Tests/PropertiesBagTests.cs

@ -0,0 +1,281 @@
// ==========================================================================
// PropertiesBagTests.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
using System.Globalization;
using System.Linq;
using NodaTime;
using Xunit;
// ReSharper disable PossibleInvalidOperationException
// ReSharper disable UnusedParameter.Local
namespace PinkParrot.Infrastructure
{
public class PropertiesBagTest
{
private readonly CultureInfo c = CultureInfo.InvariantCulture;
private readonly PropertiesBag bag = new PropertiesBag();
[Fact]
public void Should_return_false_when_renaming_unknown_property()
{
Assert.False(bag.Rename("OldKey", "NewKey"));
}
[Fact]
public void Should_throw_when_renaming_to_existing_property()
{
bag.Set("NewKey", 1);
Assert.Throws<ArgumentException>(() => bag.Rename("OldKey", "NewKey"));
}
[Fact]
public void Should_throw_when_renaming_to_same_key()
{
Assert.Throws<ArgumentException>(() => bag.Rename("SameKey", "SameKey"));
}
[Fact]
public void Should_provide_property_with_new_name_after_rename()
{
bag.Set("OldKey", 123);
Assert.True(bag.Rename("OldKey", "NewKey"));
Assert.True(bag.Contains("NewKey"));
Assert.Equal(1, bag.Count);
Assert.Equal(123, bag["NewKey"].ToInt32(c));
Assert.False(bag.Contains("OldKey"));
}
[Fact]
public void Should_calculate_count_correctly()
{
bag.Set("Key1", 1);
bag.Set("Key2", 1);
Assert.Equal(2, bag.Count);
Assert.Equal(new[] { "Key1", "Key2" }, bag.PropertyNames.ToArray());
Assert.Equal(new[] { "Key1", "Key2" }, bag.Properties.Keys.ToArray());
}
[Fact]
public void Should_return_correct_value_when_contains_check()
{
Assert.False(bag.Contains("Key"));
bag.Set("Key", 1);
Assert.True(bag.Contains("Key"));
Assert.True(bag.Contains("KEY"));
}
[Fact]
public void Should_returne_false_when_property_to_rename_does_not_exist()
{
Assert.False(bag.Remove("NOTFOUND"));
}
[Fact]
public void Should_ignore_casing_when_returning()
{
bag.Set("Key", 1);
Assert.True(bag.Remove("KEY"));
Assert.False(bag.Contains("KEY"));
}
[Fact]
public void Should_throw_when_setting_value_with_invalid_type()
{
Assert.Throws<ArgumentException>(() => bag.Set("Key", (byte)1));
}
[Fact]
public void Should_convert_string_to_numbers()
{
bag.Set("Key", 123);
AssertNumber();
}
[Fact]
public void Should_convert_int_to_numbers()
{
bag.Set("Key", 123);
AssertNumber();
}
[Fact]
public void Should_convert_long_to_numbers()
{
bag.Set("Key", 123L);
AssertNumber();
}
[Fact]
public void Should_throw_when_casting_from_large_long()
{
bag.Set("Key", long.MaxValue);
Assert.Throws<InvalidCastException>(() => bag["Key"].ToInt32(c));
}
[Fact]
public void Should_convert_float_to_number()
{
bag.Set("Key", 123f);
AssertNumber();
}
[Fact]
public void Should_convert_double_to_number()
{
bag.Set("Key", 123d);
AssertNumber();
}
[Fact]
public void Should_throw_when_casting_from_large_doule()
{
bag.Set("Key", double.MaxValue);
Assert.Equal(float.PositiveInfinity, bag["Key"].ToSingle(c));
}
[Fact]
public void Should_convert_from_instant_value()
{
var time = SystemClock.Instance.GetCurrentInstant();
bag.Set("Key", time);
AssertInstant(time);
}
[Fact]
public void Should_convert_from_instant_string()
{
var time = SystemClock.Instance.GetCurrentInstant();
bag.Set("Key", time.ToString());
AssertInstant(time);
}
[Fact]
public void Should_convert_from_guid_value()
{
var id = new Guid();
bag.Set("Key", id);
AssertGuid(id);
}
[Fact]
public void Should_convert_from_guid_string()
{
var id = new Guid();
bag.Set("Key", id.ToString());
AssertGuid(id);
}
[Fact]
public void Should_convert_from_boolean_value()
{
bag.Set("Key", true);
AssertBoolean();
}
[Fact]
public void Should_convert_from_boolean_string()
{
bag.Set("Key", "true");
AssertBoolean();
}
[Fact]
public void Should_convert_boolean_from_number()
{
bag.Set("Key", 1);
AssertBoolean();
}
[Fact]
public void Should_throw_when_converting_instant_to_number()
{
bag.Set("Key", SystemClock.Instance.GetCurrentInstant());
Assert.Throws<InvalidCastException>(() => bag["Key"].ToGuid(CultureInfo.InvariantCulture));
}
[Fact]
public void Should_return_default_when_property_value_is_null()
{
bag.Set("Key", null);
Assert.Equal(null, bag["Key"].ToString());
Assert.Equal(0f, bag["Key"].ToSingle(CultureInfo.CurrentCulture));
Assert.Equal(0d, bag["Key"].ToDouble(CultureInfo.CurrentCulture));
Assert.Equal(0L, bag["Key"].ToInt64(CultureInfo.CurrentCulture));
Assert.Equal(0, bag["Key"].ToInt32(CultureInfo.CurrentCulture));
Assert.Equal(false, bag["Key"].ToBoolean(CultureInfo.CurrentCulture));
Assert.Equal(new Guid(), bag["Key"].ToGuid(CultureInfo.CurrentCulture));
Assert.Equal(new Instant(), bag["Key"].ToInstant(CultureInfo.CurrentCulture));
}
private void AssertBoolean()
{
Assert.True(bag["Key"].ToBoolean(c));
Assert.True(bag["Key"].ToNullableBoolean(c));
}
private void AssertInstant(Instant expected)
{
Assert.Equal(expected.ToUnixTimeSeconds(), bag["Key"].ToInstant(c).ToUnixTimeSeconds());
Assert.Equal(expected.ToUnixTimeSeconds(), bag["Key"].ToNullableInstant(c).Value.ToUnixTimeSeconds());
}
private void AssertGuid(Guid expected)
{
Assert.Equal(expected, bag["Key"].ToGuid(c));
Assert.Equal(expected, bag["Key"].ToNullableGuid(c));
}
private void AssertNumber()
{
Assert.Equal(123, bag["Key"].ToInt32(c));
Assert.Equal(123, bag["Key"].ToNullableInt32(c));
Assert.Equal(123L, bag["Key"].ToInt64(c));
Assert.Equal(123L, bag["Key"].ToNullableInt64(c));
Assert.Equal(123f, bag["Key"].ToSingle(c));
Assert.Equal(123f, bag["Key"].ToNullableSingle(c));
Assert.Equal(123d, bag["Key"].ToDouble(c));
Assert.Equal(123d, bag["Key"].ToNullableDouble(c));
Assert.True(bag["Key"].ToBoolean(c));
}
}
}

29
src/pinkparrot_infrastructure/PinkParrot.Infrastructure.Tests/project.json

@ -0,0 +1,29 @@
{
"version": "1.0.0-*",
"testRunner": "xunit",
"dependencies": {
"dotnet-test-xunit": "2.2.0-preview2-build1029",
"PinkParrot.Infrastructure": "1.0.0-*",
"xunit": "2.2.0-beta2-build3300"
},
"frameworks": {
"netcoreapp1.0": {
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.0"
}
}
}
},
"buildOptions": {
"copyToOutput": {
"include": [
"xunit.runner.json"
]
}
},
"tooling": {
"defaultNamespace": "PinkParrot.Core.Tests"
}
}

5
src/pinkparrot_infrastructure/PinkParrot.Infrastructure.Tests/xunit.runner.json

@ -0,0 +1,5 @@
{
"diagnosticMessages": false,
"methodDisplay": "classAndMethod",
"parallelizeTestCollections": true
}

19
src/pinkparrot_infrastructure/PinkParrot.Infrastructure/CQRS/CommonHeaders.cs

@ -0,0 +1,19 @@
// ==========================================================================
// CommonHeaders.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
namespace PinkParrot.Infrastructure.CQRS
{
public sealed class CommonHeaders
{
public const string AggregateId = "AggregateId";
public const string CommitId = "CommitId";
public const string Timestamp = "Timestamp";
public const string EventId = "EventId";
public const string EventType = "EventType";
public const string EventNumber = "EventNumber";
}
}

105
src/pinkparrot_infrastructure/PinkParrot.Infrastructure/CQRS/DomainObject.cs

@ -0,0 +1,105 @@
// ==========================================================================
// DomainObject.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
namespace PinkParrot.Infrastructure.CQRS
{
public abstract class DomainObject : IAggregate, IEquatable<IAggregate>
{
private readonly List<Envelope<IEvent>> uncomittedEvents = new List<Envelope<IEvent>>();
private readonly Guid id;
private int version;
public int Version
{
get { return version; }
}
public Guid Id
{
get { return id; }
}
protected DomainObject(Guid id, int version)
{
Guard.NotEmpty(id, nameof(id));
Guard.GreaterEquals(version, 0, nameof(version));
this.id = id;
this.version = version;
}
protected void RaiseEvent<TEvent>(Envelope<TEvent> envelope, bool disableApply = false) where TEvent : class, IEvent
{
Guard.NotNull(envelope, nameof(envelope));
uncomittedEvents.Add(envelope.To<IEvent>());
if (!disableApply)
{
ApplyEvent(envelope.Payload);
}
}
protected void RaiseEvent(IEvent @event, bool disableApply = false)
{
Guard.NotNull(@event, nameof(@event));
uncomittedEvents.Add(EnvelopeFactory.ForEvent(@event, id));
if (!disableApply)
{
ApplyEvent(@event);
}
}
protected void Apply(object @event)
{
}
private void ApplyEvent(dynamic @event)
{
Apply(@event);
version++;
}
void IAggregate.ApplyEvent(IEvent @event)
{
Apply(@event as dynamic);
version++;
}
void IAggregate.ClearUncommittedEvents()
{
uncomittedEvents.Clear();
}
ICollection<Envelope<IEvent>> IAggregate.GetUncomittedEvents()
{
return uncomittedEvents;
}
public override int GetHashCode()
{
return id.GetHashCode();
}
public override bool Equals(object obj)
{
return Equals(obj as IAggregate);
}
public bool Equals(IAggregate other)
{
return other != null && other.Id.Equals(id);
}
}
}

54
src/pinkparrot_infrastructure/PinkParrot.Infrastructure/CQRS/Envelope.cs

@ -0,0 +1,54 @@
// ==========================================================================
// Envelope.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
namespace PinkParrot.Infrastructure.CQRS
{
public class Envelope<TPayload> where TPayload : class
{
private readonly EnvelopeHeaders headers;
private readonly TPayload payload;
public EnvelopeHeaders Headers
{
get
{
return headers;
}
}
public TPayload Payload
{
get
{
return payload;
}
}
public Envelope(TPayload payload)
{
Guard.NotNull(payload, nameof(payload));
this.payload = payload;
headers = new EnvelopeHeaders();
}
public Envelope(TPayload payload, EnvelopeHeaders headers)
{
Guard.NotNull(payload, nameof(payload));
Guard.NotNull(headers, nameof(headers));
this.payload = payload;
this.headers = headers;
}
public Envelope<TOther> To<TOther>() where TOther : class
{
return new Envelope<TOther>(payload as TOther, headers.Clone());
}
}
}

77
src/pinkparrot_infrastructure/PinkParrot.Infrastructure/CQRS/EnvelopeExtensions.cs

@ -0,0 +1,77 @@
// ==========================================================================
// EnvelopeExtensions.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
using System.Globalization;
using NodaTime;
namespace PinkParrot.Infrastructure.CQRS
{
public static class EnvelopeExtensions
{
public static int EventNumber<T>(this Envelope<T> envelope) where T : class
{
return envelope.Headers[CommonHeaders.EventNumber].ToInt32(CultureInfo.InvariantCulture);
}
public static Envelope<T> SetEventNumber<T>(this Envelope<T> envelope, int value) where T : class
{
envelope.Headers.Set(CommonHeaders.EventNumber, value);
return envelope;
}
public static Guid CommitId<T>(this Envelope<T> envelope) where T : class
{
return envelope.Headers[CommonHeaders.CommitId].ToGuid(CultureInfo.InvariantCulture);
}
public static Envelope<T> SetCommitId<T>(this Envelope<T> envelope, Guid value) where T : class
{
envelope.Headers.Set(CommonHeaders.CommitId, value);
return envelope;
}
public static Guid AggregateId<T>(this Envelope<T> envelope) where T : class
{
return envelope.Headers[CommonHeaders.AggregateId].ToGuid(CultureInfo.InvariantCulture);
}
public static Envelope<T> SetAggregateId<T>(this Envelope<T> envelope, Guid value) where T : class
{
envelope.Headers.Set(CommonHeaders.AggregateId, value);
return envelope;
}
public static Guid EventId<T>(this Envelope<T> envelope) where T : class
{
return envelope.Headers[CommonHeaders.EventId].ToGuid(CultureInfo.InvariantCulture);
}
public static Envelope<T> SetEventId<T>(this Envelope<T> envelope, Guid value) where T : class
{
envelope.Headers.Set(CommonHeaders.EventId, value);
return envelope;
}
public static Instant Timestamp<T>(this Envelope<T> envelope) where T : class
{
return envelope.Headers[CommonHeaders.Timestamp].ToInstant(CultureInfo.InvariantCulture);
}
public static Envelope<T> SetTimestamp<T>(this Envelope<T> envelope, Instant value) where T : class
{
envelope.Headers.Set(CommonHeaders.Timestamp, value);
return envelope;
}
}
}

24
src/pinkparrot_infrastructure/PinkParrot.Infrastructure/CQRS/EnvelopeFactory.cs

@ -0,0 +1,24 @@
// ==========================================================================
// EnvelopeFactory.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
using NodaTime;
namespace PinkParrot.Infrastructure.CQRS
{
public static class EnvelopeFactory
{
public static Envelope<IEvent> ForEvent(IEvent @event, Guid aggregateId)
{
return new Envelope<IEvent>(@event)
.SetAggregateId(aggregateId)
.SetEventId(aggregateId)
.SetTimestamp(SystemClock.Instance.GetCurrentInstant());
}
}
}

24
src/pinkparrot_infrastructure/PinkParrot.Infrastructure/CQRS/EnvelopeHeaders.cs

@ -0,0 +1,24 @@
// ==========================================================================
// EnvelopeHeaders.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
namespace PinkParrot.Infrastructure.CQRS
{
public sealed class EnvelopeHeaders : PropertiesBag
{
public EnvelopeHeaders Clone()
{
var clone = new EnvelopeHeaders();
foreach (var property in Properties)
{
clone.Set(property.Key, property.Value.RawValue);
}
return clone;
}
}
}

28
src/pinkparrot_infrastructure/PinkParrot.Infrastructure/CQRS/IAggregate.cs

@ -0,0 +1,28 @@
// ==========================================================================
// IAggregate.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
namespace PinkParrot.Infrastructure.CQRS
{
public interface IAggregate
{
Guid Id { get; }
int Version { get; }
void ApplyEvent(IEvent @event);
void ClearUncommittedEvents();
ICollection<Envelope<IEvent>> GetUncomittedEvents();
}
}

13
src/pinkparrot_infrastructure/PinkParrot.Infrastructure/CQRS/IEvent.cs

@ -0,0 +1,13 @@
// ==========================================================================
// IEvent.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
namespace PinkParrot.Infrastructure.CQRS
{
public interface IEvent
{
}
}

110
src/pinkparrot_infrastructure/PinkParrot.Infrastructure/CollectionExtensions.cs

@ -0,0 +1,110 @@
// ==========================================================================
// CollectionExtensions.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Linq;
// ReSharper disable InvertIf
// ReSharper disable LoopCanBeConvertedToQuery
namespace PinkParrot.Infrastructure
{
public static class CollectionExtensions
{
public static int SequentialHashCode<T>(this IEnumerable<T> collection)
{
return collection.SequentialHashCode(EqualityComparer<T>.Default);
}
public static int SequentialHashCode<T>(this IEnumerable<T> collection, IEqualityComparer<T> comparer)
{
var hashCode = 17;
foreach (var item in collection)
{
if (item != null)
{
hashCode = hashCode * 23 + item.GetHashCode();
}
}
return hashCode;
}
public static int OrderedHashCode<T>(this IEnumerable<T> collection)
{
return collection.OrderedHashCode(EqualityComparer<T>.Default);
}
public static int OrderedHashCode<T>(this IEnumerable<T> collection, IEqualityComparer<T> comparer)
{
var hashCodes = collection.Where(x => x != null).Select(x => x.GetHashCode()).OrderBy(x => x).ToArray();
var hashCode = 17;
foreach (var code in hashCodes)
{
hashCode = hashCode * 23 + code;
}
return hashCode;
}
public static bool EqualsDictionary<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dictionary, IDictionary<TKey, TValue> other)
{
return Equals(dictionary, other) || (other != null && dictionary.Count == other.Count && !dictionary.Except(other).Any());
}
public static TValue GetOrDefault<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dictionary, TKey key)
{
return dictionary.GetOrCreate(key, _ => default(TValue));
}
public static TValue GetOrAddDefault<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
{
return dictionary.GetOrAdd(key, _ => default(TValue));
}
public static TValue GetOrNew<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dictionary, TKey key) where TValue : class, new()
{
return dictionary.GetOrCreate(key, _ => new TValue());
}
public static TValue GetOrAddNew<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key) where TValue : class, new()
{
return dictionary.GetOrAdd(key, _ => new TValue());
}
public static TValue GetOrCreate<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dictionary, TKey key, Func<TKey, TValue> creator)
{
TValue result;
if (!dictionary.TryGetValue(key, out result))
{
result = creator(key);
}
return result;
}
public static TValue GetOrAdd<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, Func<TKey, TValue> creator)
{
TValue result;
if (!dictionary.TryGetValue(key, out result))
{
result = creator(key);
dictionary.Add(key, result);
}
return result;
}
}
}

48
src/pinkparrot_infrastructure/PinkParrot.Infrastructure/DomainValidationException.cs

@ -0,0 +1,48 @@
// ==========================================================================
// DomainValidationException.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Linq;
namespace PinkParrot.Infrastructure
{
public class DomainValidationException : Exception
{
private readonly IReadOnlyList<string> errors;
public IReadOnlyList<string> Errors
{
get { return errors; }
}
public DomainValidationException(string message, params string[] errors)
: base(message)
{
this.errors = errors != null ? errors.ToList() : new List<string>();
}
public DomainValidationException(string message, IReadOnlyList<string> errors)
: base(message)
{
this.errors = errors ?? new List<string>();
}
public DomainValidationException(string message, Exception inner, params string[] errors)
: base(message, inner)
{
this.errors = errors != null ? errors.ToList() : new List<string>();
}
public DomainValidationException(string message, Exception inner, IReadOnlyList<string> errors)
: base(message, inner)
{
this.errors = errors ?? new List<string>();
}
}
}

27
src/pinkparrot_infrastructure/PinkParrot.Infrastructure/EnumExtensions.cs

@ -0,0 +1,27 @@
// ==========================================================================
// EnumExtensions.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
namespace PinkParrot.Infrastructure
{
public static class EnumExtensions
{
public static bool IsEnumValue<TEnum>(this TEnum value) where TEnum : struct
{
try
{
return Enum.IsDefined(typeof(TEnum), value);
}
catch
{
return false;
}
}
}
}

29
src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Extensions.cs

@ -0,0 +1,29 @@
// ==========================================================================
// Extensions.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace PinkParrot.Infrastructure
{
public static class Extensions
{
private static readonly Regex SlugRegex = new Regex("^[a-z0-9]+(\\-[a-z0-9]+)*$", RegexOptions.Compiled);
public static bool IsSlug(this string value)
{
return value != null && SlugRegex.IsMatch(value);
}
public static bool IsBetween<TValue>(this TValue value, TValue low, TValue high) where TValue : IComparable
{
return Comparer<TValue>.Default.Compare(low, value) <= 0 && Comparer<TValue>.Default.Compare(high, value) >= 0;
}
}
}

240
src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Guard.cs

@ -0,0 +1,240 @@
// ==========================================================================
// Guard.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
// ReSharper disable InvertIf
namespace PinkParrot.Infrastructure
{
public static class Guard
{
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ValidNumber(float target, string parameterName)
{
if (float.IsNaN(target) || float.IsPositiveInfinity(target) || float.IsNegativeInfinity(target))
{
throw new ArgumentException("Value must be a valid number.", parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ValidNumber(double target, string parameterName)
{
if (double.IsNaN(target) || double.IsPositiveInfinity(target) || double.IsNegativeInfinity(target))
{
throw new ArgumentException("Value must be a valid number.", parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ValidSlug(string target, string parameterName)
{
NotNullOrEmpty(target, parameterName);
if (!target.IsSlug())
{
throw new ArgumentException("Target is not a valid slug.", parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void HasType<T>(object target, string parameterName)
{
NotNull(target, "parameterName");
if (target.GetType() != typeof(T))
{
throw new ArgumentException("The parameter must be of type " + typeof(T), parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Between<TValue>(TValue target, TValue lower, TValue upper, string parameterName) where TValue : IComparable
{
if (!target.IsBetween(lower, upper))
{
var message = string.Format(CultureInfo.CurrentCulture, "Value must be between {0} and {1}", lower, upper);
throw new ArgumentException(message, parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Enum<TEnum>(TEnum target, string parameterName) where TEnum : struct
{
if (!target.IsEnumValue())
{
var message = string.Format(CultureInfo.CurrentCulture, "Value must be a valid enum type {0}", typeof(TEnum));
throw new ArgumentException(message, parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void GreaterThan<TValue>(TValue target, TValue lower, string parameterName) where TValue : IComparable
{
if (target.CompareTo(lower) <= 0)
{
var message = string.Format(CultureInfo.CurrentCulture, "Value must be greater than {0}", lower);
throw new ArgumentException(message, parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void GreaterEquals<TValue>(TValue target, TValue lower, string parameterName) where TValue : IComparable
{
if (target.CompareTo(lower) < 0)
{
var message = string.Format(CultureInfo.CurrentCulture, "Value must be greater than {0}", lower);
throw new ArgumentException(message, parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void LessThan<TValue>(TValue target, TValue upper, string parameterName) where TValue : IComparable
{
if (target.CompareTo(upper) >= 0)
{
var message = string.Format(CultureInfo.CurrentCulture, "Value must be less than {0}", upper);
throw new ArgumentException(message, parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void LessEquals<TValue>(TValue target, TValue upper, string parameterName) where TValue : IComparable
{
if (target.CompareTo(upper) > 0)
{
var message = string.Format(CultureInfo.CurrentCulture, "Value must be less than {0}", upper);
throw new ArgumentException(message, parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void NotEmpty<TType>(ICollection<TType> enumerable, string parameterName)
{
if (enumerable == null)
{
throw new ArgumentNullException(nameof(enumerable));
}
if (enumerable.Count == 0)
{
throw new ArgumentException("Collection does not contain an item", parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void NotEmpty(Guid target, string parameterName)
{
if (target == Guid.Empty)
{
throw new ArgumentException("Value cannot be empty.", parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void NotNull(object target, string parameterName)
{
if (target == null)
{
throw new ArgumentNullException(parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void NotDefault<T>(T target, string parameterName)
{
if (Equals(target, default(T)))
{
throw new ArgumentException("Value cannot be an the default value", parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void NotNullOrEmpty(string target, string parameterName, bool allowWhitespacesAtStartOrEnd = true)
{
if (target == null)
{
throw new ArgumentNullException(parameterName);
}
if (string.IsNullOrWhiteSpace(target))
{
throw new ArgumentException("String parameter cannot be null or empty and cannot contain only blanks.", parameterName);
}
if (!allowWhitespacesAtStartOrEnd && target.Trim() != target)
{
throw new ArgumentException("String cannot start or end with whitespaces", parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ValidFileName(string target, string parameterName)
{
NotNullOrEmpty(target, parameterName);
if (target.Intersect(Path.GetInvalidFileNameChars()).Any())
{
throw new ArgumentException("Value contains an invalid character.", parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsType<T>(object target, string parameterName)
{
if (target != null && target.GetType() != typeof(T))
{
var message = string.Format(CultureInfo.CurrentCulture, "Value must be of type {0}", typeof(T));
throw new ArgumentException(message, parameterName);
}
}
[DebuggerStepThrough]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IsType(object target, Type expectedType, string parameterName)
{
if (target != null && expectedType != null && target.GetType() != expectedType)
{
var message = string.Format(CultureInfo.CurrentCulture, "Value must be of type {0}", expectedType);
throw new ArgumentException(message, parameterName);
}
}
}
}

21
src/pinkparrot_infrastructure/PinkParrot.Infrastructure/PinkParrot.Infrastructure.xproj

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>bd1c30a8-8ffa-4a92-a9bd-b67b1cddd84c</ProjectGuid>
<RootNamespace>PinkParrot.Infrastructure</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

94
src/pinkparrot_infrastructure/PinkParrot.Infrastructure/PropertiesBag.cs

@ -0,0 +1,94 @@
// ==========================================================================
// PropertiesBag.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
namespace PinkParrot.Infrastructure
{
public class PropertiesBag
{
private readonly Dictionary<string, PropertyValue> internalDictionary = new Dictionary<string, PropertyValue>(StringComparer.OrdinalIgnoreCase);
public int Count
{
get { return internalDictionary.Count; }
}
public IReadOnlyDictionary<string, PropertyValue> Properties
{
get { return internalDictionary; }
}
public IEnumerable<string> PropertyNames
{
get { return internalDictionary.Keys; }
}
public PropertyValue this[string propertyName]
{
get
{
Guard.NotNullOrEmpty(propertyName, nameof(propertyName));
return internalDictionary[propertyName];
}
}
public bool Contains(string propertyName)
{
Guard.NotNullOrEmpty(propertyName, nameof(propertyName));
return internalDictionary.ContainsKey(propertyName);
}
public PropertiesBag Set(string propertyName, object value)
{
Guard.NotNullOrEmpty(propertyName, nameof(propertyName));
internalDictionary[propertyName] = new PropertyValue(value);
return this;
}
public bool Remove(string propertyName)
{
Guard.NotNullOrEmpty(propertyName, nameof(propertyName));
return internalDictionary.Remove(propertyName);
}
public bool Rename(string oldPropertyName, string newPropertyName)
{
Guard.NotNullOrEmpty(oldPropertyName, nameof(oldPropertyName));
Guard.NotNullOrEmpty(newPropertyName, nameof(newPropertyName));
if (internalDictionary.ContainsKey(newPropertyName))
{
throw new ArgumentException($"An property with the key '{newPropertyName}' already exists.", newPropertyName);
}
if (string.Equals(oldPropertyName, newPropertyName, StringComparison.OrdinalIgnoreCase))
{
throw new ArgumentException($"The property names '{newPropertyName}' are equal.", newPropertyName);
}
PropertyValue property;
if (!internalDictionary.TryGetValue(oldPropertyName, out property))
{
return false;
}
internalDictionary[newPropertyName] = property;
internalDictionary.Remove(oldPropertyName);
return true;
}
}
}

211
src/pinkparrot_infrastructure/PinkParrot.Infrastructure/PropertyValue.cs

@ -0,0 +1,211 @@
// ==========================================================================
// PropertyValue.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Globalization;
using NodaTime;
using NodaTime.Text;
namespace PinkParrot.Infrastructure
{
public sealed class PropertyValue
{
private readonly object rawValue;
private static readonly HashSet<Type> AllowedTypes = new HashSet<Type>
{
typeof(string),
typeof(bool),
typeof(bool?),
typeof(float),
typeof(float?),
typeof(double),
typeof(double?),
typeof(int),
typeof(int?),
typeof(long),
typeof(long?),
typeof(Instant),
typeof(Instant?),
typeof(Guid),
typeof(Guid?)
};
public object RawValue
{
get { return rawValue; }
}
internal PropertyValue(object rawValue)
{
if (rawValue != null && !AllowedTypes.Contains(rawValue.GetType()))
{
throw new ArgumentException("The type is not supported.", nameof(rawValue));
}
this.rawValue = rawValue;
}
public override string ToString()
{
return rawValue?.ToString();
}
public bool ToBoolean(CultureInfo culture)
{
return ToOrParseValue(culture, bool.Parse);
}
public bool? ToNullableBoolean(CultureInfo culture)
{
return ToNullableOrParseValue(culture, bool.Parse);
}
public float ToSingle(CultureInfo culture)
{
return ToOrParseValue(culture, x => float.Parse(x, culture));
}
public float? ToNullableSingle(CultureInfo culture)
{
return ToNullableOrParseValue(culture, x => float.Parse(x, culture));
}
public double ToDouble(CultureInfo culture)
{
return ToOrParseValue(culture, x => double.Parse(x, culture));
}
public double? ToNullableDouble(CultureInfo culture)
{
return ToNullableOrParseValue(culture, x => double.Parse(x, culture));
}
public int ToInt32(CultureInfo culture)
{
return ToOrParseValue(culture, x => int.Parse(x, culture));
}
public int? ToNullableInt32(CultureInfo culture)
{
return ToNullableOrParseValue(culture, x => int.Parse(x, culture));
}
public long ToInt64(CultureInfo culture)
{
return ToOrParseValue(culture, x => long.Parse(x, culture));
}
public long? ToNullableInt64(CultureInfo culture)
{
return ToNullableOrParseValue(culture, x => long.Parse(x, culture));
}
public Instant ToInstant(CultureInfo culture)
{
return ToOrParseValue(culture, x => InstantPattern.GeneralPattern.Parse(x).Value);
}
public Instant? ToNullableInstant(CultureInfo culture)
{
return ToNullableOrParseValue(culture, x => InstantPattern.GeneralPattern.Parse(x).Value);
}
public Guid ToGuid(CultureInfo culture)
{
return ToOrParseValue(culture, Guid.Parse);
}
public Guid? ToNullableGuid(CultureInfo culture)
{
return ToNullableOrParseValue(culture, Guid.Parse);
}
private T? ToNullableOrParseValue<T>(IFormatProvider culture, Func<string, T> parser) where T : struct
{
T result;
return TryParse(culture, parser, out result) ? result : (T?)null;
}
private T ToOrParseValue<T>(IFormatProvider culture, Func<string, T> parser)
{
T result;
return TryParse(culture, parser, out result) ? result : default(T);
}
private bool TryParse<T>(IFormatProvider culture, Func<string, T> parser, out T result)
{
var value = rawValue;
if (value != null)
{
var valueType = value.GetType();
if (valueType == typeof(T))
{
result = (T)value;
}
else if (valueType == typeof(string))
{
result = Parse(parser, valueType, value);
}
else
{
result = Convert<T>(culture, value, valueType);
}
return true;
}
result = default(T);
return false;
}
private static T Convert<T>(IFormatProvider culture, object value, Type valueType)
{
var requestedType = typeof(T);
try
{
return (T)System.Convert.ChangeType(value, requestedType, culture);
}
catch (OverflowException)
{
string message = $"The property has type '{valueType}' and cannot be casted to '{requestedType}' because it is either too small or large.";
throw new InvalidCastException(message);
}
catch (InvalidCastException)
{
string message = $"The property has type '{valueType}' and cannot be casted to '{requestedType}'.";
throw new InvalidCastException(message);
}
}
private static T Parse<T>(Func<string, T> parser, Type valueType, object value)
{
var requestedType = typeof(T);
try
{
return parser(value.ToString());
}
catch (Exception e)
{
string message = $"The property has type '{valueType}' and cannot be casted to '{requestedType}'.";
throw new InvalidCastException(message, e);
}
}
}
}

19
src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Tasks/TaskExtensions.cs

@ -0,0 +1,19 @@
// ==========================================================================
// TaskExtensions.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System.Threading.Tasks;
namespace PinkParrot.Infrastructure.Tasks
{
public static class TaskExtensions
{
public static void Forget(this Task task)
{
}
}
}

26
src/pinkparrot_infrastructure/PinkParrot.Infrastructure/Tasks/TaskHelper.cs

@ -0,0 +1,26 @@
// ==========================================================================
// TaskHelper.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System.Threading.Tasks;
namespace PinkParrot.Infrastructure.Tasks
{
public static class TaskHelper
{
public static readonly Task Done = CreateDoneTask();
private static Task CreateDoneTask()
{
var result = new TaskCompletionSource<object>();
result.SetResult(null);
return result.Task;
}
}
}

20
src/pinkparrot_infrastructure/PinkParrot.Infrastructure/project.json

@ -0,0 +1,20 @@
{
"version": "1.0.0-*",
"dependencies": {
"NodaTime": "2.0.0-alpha20160729",
"NETStandard.Library": "1.6.0"
},
"frameworks": {
"netcoreapp1.0": {
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.0"
}
}
}
},
"tooling": {
"defaultNamespace": "PinkParrot.Infrastructure"
}
}

234
src/pinkparrot_write/PinkParrot.Write/.gitignore

@ -0,0 +1,234 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
build/
bld/
[Bb]in/
[Oo]bj/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Microsoft Azure ApplicationInsights config file
ApplicationInsights.config
# Windows Store app package directory
AppPackages/
BundleArtifacts/
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
# FAKE - F# Make
.fake/

19
src/pinkparrot_write/PinkParrot.Write/PinkParrot.Write.xproj

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0.25420" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25420</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>a85201c6-6af8-4b63-8365-08f741050438</ProjectGuid>
<RootNamespace>PinkParrot.Write</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

21
src/pinkparrot_write/PinkParrot.Write/Schema/Commands/AddModelField.cs

@ -0,0 +1,21 @@
// ==========================================================================
// AddModelField.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
namespace PinkParrot.Write.Schema.Commands
{
public class AddModelField
{
public Guid AggregateId;
public string FieldType;
public string FieldName;
}
}

19
src/pinkparrot_write/PinkParrot.Write/Schema/Commands/CreateModelSchema.cs

@ -0,0 +1,19 @@
// ==========================================================================
// CreateModelSchema.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
namespace PinkParrot.Write.Schema.Commands
{
public class CreateModelSchema
{
public Guid AggregateId;
public string Name;
}
}

19
src/pinkparrot_write/PinkParrot.Write/Schema/Commands/DeleteModelField.cs

@ -0,0 +1,19 @@
// ==========================================================================
// DeleteModelField.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
namespace PinkParrot.Write.Schema.Commands
{
public class DeleteModelField
{
public Guid AggregateId;
public Guid FieldId;
}
}

17
src/pinkparrot_write/PinkParrot.Write/Schema/Commands/DeleteModelSchema.cs

@ -0,0 +1,17 @@
// ==========================================================================
// DeleteModelSchema.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
namespace PinkParrot.Write.Schema.Commands
{
public class DeleteModelSchema
{
public Guid AggregateId;
}
}

19
src/pinkparrot_write/PinkParrot.Write/Schema/Commands/DisableModelField.cs

@ -0,0 +1,19 @@
// ==========================================================================
// DisableModelField.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
namespace PinkParrot.Write.Schema.Commands
{
public class DisableModelField
{
public Guid AggregateId;
public Guid FieldId;
}
}

19
src/pinkparrot_write/PinkParrot.Write/Schema/Commands/EnableModelField.cs

@ -0,0 +1,19 @@
// ==========================================================================
// EnableModelField.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
namespace PinkParrot.Write.Schema.Commands
{
public class EnableModelField
{
public Guid AggregateId;
public Guid FieldId;
}
}

19
src/pinkparrot_write/PinkParrot.Write/Schema/Commands/HideModelField.cs

@ -0,0 +1,19 @@
// ==========================================================================
// HideModelField.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
namespace PinkParrot.Write.Schema.Commands
{
public class HideModelField
{
public Guid AggregateId;
public Guid FieldId;
}
}

19
src/pinkparrot_write/PinkParrot.Write/Schema/Commands/ShowModelField.cs

@ -0,0 +1,19 @@
// ==========================================================================
// ShowModelField.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
namespace PinkParrot.Write.Schema.Commands
{
public class ShowModelField
{
public Guid AggregateId;
public Guid FieldId;
}
}

22
src/pinkparrot_write/PinkParrot.Write/Schema/Commands/UpdateModelField.cs

@ -0,0 +1,22 @@
// ==========================================================================
// UpdateModelField.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
using PinkParrot.Infrastructure;
namespace PinkParrot.Write.Schema.Commands
{
public class UpdateModelField
{
public Guid AggregateId;
public Guid FieldId;
public PropertiesBag Settings;
}
}

22
src/pinkparrot_write/PinkParrot.Write/Schema/Commands/UpdateModelSchema.cs

@ -0,0 +1,22 @@
// ==========================================================================
// UpdateModelSchema.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
using PinkParrot.Infrastructure;
namespace PinkParrot.Write.Schema.Commands
{
public class UpdateModelSchema
{
public Guid AggregateId;
public string NewName;
public PropertiesBag Settings { get; set; }
}
}

196
src/pinkparrot_write/PinkParrot.Write/Schema/ModelSchemaDomainObject.cs

@ -0,0 +1,196 @@
// ==========================================================================
// ModelSchemaDomainObject.cs
// PinkParrot Headless CMS
// ==========================================================================
// Copyright (c) PinkParrot Group
// All rights reserved.
// ==========================================================================
using System;
using PinkParrot.Core.Schema;
using PinkParrot.Events.Schema;
using PinkParrot.Infrastructure.CQRS;
using PinkParrot.Write.Schema.Commands;
namespace PinkParrot.Write.Schema
{
public class ModelSchemaDomainObject : DomainObject
{
private readonly ModelFieldFactory fieldFactory;
private bool isDeleted;
private ModelSchema schema;
public ModelSchemaDomainObject(Guid id, int version, ModelFieldFactory fieldFactory)
: base(id, version)
{
this.fieldFactory = fieldFactory;
}
public ModelSchema Schema
{
get { return schema; }
}
public bool IsDeleted
{
get { return isDeleted; }
}
protected void Apply(ModelSchemaCreated @event)
{
schema = ModelSchema.Create(@event.Name);
}
protected void Apply(ModelFieldAdded @event)
{
schema = schema.AddField(@event.FieldId, @event.FieldType, @event.FieldName, fieldFactory);
}
protected void Apply(ModelFieldUpdated @event)
{
schema = schema.SetField(@event.FieldId, @event.Settings);
}
public void Apply(ModelFieldHidden @event)
{
schema = schema.HideField(@event.FieldId);
}
public void Apply(ModelFieldShown @event)
{
schema = schema.ShowField(@event.FieldId);
}
public void Apply(ModelFieldDisabled @event)
{
schema = schema.DisableField(@event.FieldId);
}
public void Apply(ModelFieldEnabled @event)
{
schema = schema.EnableField(@event.FieldId);
}
protected void Apply(ModelSchemaUpdated @event)
{
schema = schema.Update(schema.Metadata.Configure(@event.NewName, @event.Settings));
}
protected void Apply(ModelFieldDeleted @event)
{
schema = schema.DeleteField(@event.FieldId);
}
protected void Apply(ModelSchemaDeleted @event)
{
isDeleted = false;
}
public void Create(CreateModelSchema command)
{
VerifyNotCreated();
schema = ModelSchema.Create(command.Name);
RaiseEvent(new ModelSchemaCreated {Name = command.Name}, true);
}
public void AddField(Guid id, AddModelField command)
{
VerifyCreatedAndNotDeleted();
schema = schema.AddField(id, command.FieldType, command.FieldName, fieldFactory);
RaiseEvent(
new ModelFieldAdded {FieldId = id, FieldType = command.FieldType, FieldName = command.FieldName}, true);
}
public void Update(UpdateModelSchema command)
{
VerifyCreatedAndNotDeleted();
schema = schema.Update(schema.Metadata.Configure(command.NewName, command.Settings));
RaiseEvent(new ModelSchemaUpdated {NewName = command.NewName, Settings = command.Settings}, true);
}
public void UpdateField(UpdateModelField command)
{
VerifyCreatedAndNotDeleted();
schema = schema.SetField(command.FieldId, command.Settings);
RaiseEvent(new ModelFieldUpdated {FieldId = command.FieldId, Settings = command.Settings}, true);
}
public void HideField(HideModelField command)
{
VerifyCreatedAndNotDeleted();
schema = schema.HideField(command.FieldId);
RaiseEvent(new ModelFieldHidden {FieldId = command.FieldId}, true);
}
public void ShowField(HideModelField command)
{
VerifyCreatedAndNotDeleted();
schema = schema.ShowField(command.FieldId);
RaiseEvent(new ModelFieldShown {FieldId = command.FieldId}, true);
}
public void DisableField(DisableModelField command)
{
VerifyCreatedAndNotDeleted();
schema = schema.DisableField(command.FieldId);
RaiseEvent(new ModelFieldDisabled {FieldId = command.FieldId}, true);
}
public void EnableField(EnableModelField command)
{
VerifyCreatedAndNotDeleted();
schema = schema.EnableField(command.FieldId);
RaiseEvent(new ModelFieldEnabled {FieldId = command.FieldId}, true);
}
public void Delete(DeleteModelSchema command)
{
VerifyCreatedAndNotDeleted();
isDeleted = true;
RaiseEvent(new ModelSchemaDeleted(), true);
}
public void DeleteField(DeleteModelField command)
{
VerifyCreatedAndNotDeleted();
schema = schema.DeleteField(command.FieldId);
RaiseEvent(new ModelFieldDeleted {FieldId = command.FieldId}, true);
}
private void VerifyNotCreated()
{
if (schema != null)
{
throw new InvalidOperationException("Schema has already been created.");
}
}
private void VerifyCreatedAndNotDeleted()
{
if (isDeleted || schema == null)
{
throw new InvalidOperationException("Schema has already been deleted or not created yet.");
}
}
}
}

26
src/pinkparrot_write/PinkParrot.Write/project.json

@ -0,0 +1,26 @@
{
"version": "1.0.0-*",
"dependencies": {
"NETStandard.Library": "1.6.0",
"NodaTime": "2.0.0-alpha20160729",
"PinkParrot.Core": "1.0.0-*",
"PinkParrot.Events": "1.0.0-*",
"PinkParrot.Infrastructure": "1.0.0-*"
},
"frameworks": {
"netcoreapp1.0": {
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.0"
}
}
}
},
"tooling": {
"defaultNamespace": "PinkParrot.Write"
}
}
Loading…
Cancel
Save