Skip to content

Commit

Permalink
Improve generated content types part 1
Browse files Browse the repository at this point in the history
  • Loading branch information
iJungleboy committed Oct 25, 2024
1 parent 9e6f820 commit 5f3fad9
Show file tree
Hide file tree
Showing 10 changed files with 177 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ToSic.Eav.Data;
using ToSic.Eav.Data.Build;
using ToSic.Testing.Shared;

namespace ToSic.Eav.Core.Tests.Data.ContentTypeFactoryTests;

[TestClass]
public class ContentTypeFactoryClassTests: TestBaseEavCore
{
private ContentTypeFactory Factory() => GetService<ContentTypeFactory>();

[TestMethod]
public void Basic() => Assert.IsNotNull(Factory());

[TestMethod]
public void Create_NoSpecs()
{
var x = Factory().Create(typeof(TestTypeBasic));
Assert.AreEqual(nameof(TestTypeBasic), x.Name);
Assert.AreEqual(Scopes.Default, x.Scope);
Assert.AreEqual(Guid.Empty.ToString(), x.NameId);
Assert.AreEqual(ContentTypeFactory.NoAppId, x.AppId);
Assert.AreEqual(null, GetDescription(x));
}

[TestMethod]
public void Create_WithSpecs()
{
var x = Factory().Create(typeof(TestTypeWithSpecs));
Assert.AreEqual(TestTypeWithSpecs.SpecName, x.Name);
Assert.AreEqual(TestTypeWithSpecs.SpecScope, x.Scope);
Assert.AreEqual(TestTypeWithSpecs.SpecGuid, x.NameId);
Assert.AreEqual(ContentTypeFactory.NoAppId, x.AppId);
Assert.AreEqual(TestTypeWithSpecs.SpecDescription, GetDescription(x));
}

private static string GetDescription(IContentType type) => type.Metadata.Description?.Get<string>(nameof(ContentTypeDetails.Description));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace ToSic.Eav.Core.Tests.Data.ContentTypeFactoryTests;

/// <summary>
/// Very basic test type, without additional decoration.
/// </summary>
internal class TestTypeBasic
{
public string Name { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using ToSic.Eav.Data.ContentTypes.CodeAttributes;

namespace ToSic.Eav.Core.Tests.Data.ContentTypeFactoryTests;

[ContentTypeSpecs(Name = SpecName, Guid = SpecGuid, Scope = SpecScope, Description = SpecDescription)]
internal class TestTypeWithSpecs
{
internal const string SpecName = "TestTypeWithSpecsModified";
internal const string SpecGuid = "501ee043-1070-4cbc-a07b-8274f24bf5ea";
internal const string SpecScope = "DemoScope";
internal const string SpecDescription = "This is a test type with specs";

public string Name { get; set; }
}
3 changes: 3 additions & 0 deletions ToSic.Eav.Core.Tests/ToSic.Eav.Core.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,14 @@
<Compile Include="Configuration\DataOverrideTest.cs" />
<Compile Include="Configuration\LicenseCheckTest.cs" />
<Compile Include="Configuration\FingerprintTest.cs" />
<Compile Include="Data\ContentTypeFactoryTests\TestTypeBasic.cs" />
<Compile Include="Data\ContentTypeFactoryTests\TestTypeWithSpecs.cs" />
<Compile Include="Data\ContentType_Test.cs" />
<Compile Include="Data\SampleData.cs" />
<Compile Include="Data\Entity_Test.cs" />
<Compile Include="Data\EqualityComparerPerformance.cs" />
<Compile Include="Data\PropReqSpecsTests.cs" />
<Compile Include="Data\ContentTypeFactoryTests\ContentTypeFactoryClassTests.cs" />
<Compile Include="EavDataTestAccessors.cs" />
<Compile Include="IdentityTests\MapperTest.cs" />
<Compile Include="LookUp\LookUpTestData.cs" />
Expand Down
17 changes: 17 additions & 0 deletions ToSic.Eav.Core/Data/Build/Builder/ContentTypeAttributeBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,23 @@ namespace ToSic.Eav.Data.Build;
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public class ContentTypeAttributeBuilder() : ServiceBase("Eav.CtAtBl")
{
/// <summary>
/// Create a ContentType Attribute.
/// This contains the definition of a single attribute of a content type.
/// Specifically its name, what value type it accepts etc.
/// </summary>
/// <param name="appId"></param>
/// <param name="name"></param>
/// <param name="type"></param>
/// <param name="isTitle"></param>
/// <param name="id"></param>
/// <param name="sortOrder"></param>
/// <param name="guid"></param>
/// <param name="sysSettings"></param>
/// <param name="metadata"></param>
/// <param name="metadataItems"></param>
/// <param name="metaSourceFinder"></param>
/// <returns></returns>
public ContentTypeAttribute Create(
int appId,
string name,
Expand Down
5 changes: 0 additions & 5 deletions ToSic.Eav.Core/Data/Build/Builder/ContentTypeBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@ namespace ToSic.Eav.Data.Build;
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public class ContentTypeBuilder
{
/// <summary>
/// WIP - constructor shouldn't ever be called because of DI
/// </summary>
public ContentTypeBuilder() { }

public const int DynTypeId = 1;

public IContentType Create(
Expand Down
55 changes: 55 additions & 0 deletions ToSic.Eav.Core/Data/Build/Builder/ContentTypeFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using ToSic.Eav.Data.ContentTypes.CodeAttributes;
using ToSic.Eav.Plumbing;

namespace ToSic.Eav.Data.Build;

public class ContentTypeFactory(ContentTypeBuilder ctBuilder, ContentTypeAttributeBuilder ctAttributeBuilder, EntityBuilder entityBuilder, AttributeBuilder attributeBuilder)
{
public const int NoAppId = -1;

public IContentType Create(Type type) => Create(type, null, null, null);

private IContentType Create(Type type, string name = default, string nameId = default, string scope = default, int appId = NoAppId)
{
var ctSpecs = type.GetDirectlyAttachedAttribute<ContentTypeSpecsAttribute>();
var ctName = name ?? ctSpecs?.Name ?? type.Name;
var ctNameId = nameId ?? ctSpecs?.Guid.NullOrGetWith(g => Guid.TryParse(g, out var guid) ? guid.ToString() : null) ?? Guid.Empty.ToString();
var ctScope = scope ?? ctSpecs?.Scope ?? Scopes.Default;

// Must be null if no metadata
var ctMetadata = ContentTypeDetails(ctSpecs?.Description)?.ToListOfOne();

var contentType = ctBuilder.Create(
appId,
name: ctName,
nameId: ctNameId,
scope: ctScope,
id: 0,
metadataItems: ctMetadata,
isDynamic: true
);
return contentType;
}

/// <summary>
/// Generate a details entity for a content type.
/// Most properties like icon etc. are not important, so ATM it only does:
/// - Description
/// </summary>
/// <param name="description"></param>
/// <returns></returns>
private IEntity ContentTypeDetails(string description)
{
if (description == null)
return null;

// All props
var dic = new Dictionary<string, object> { { nameof(Data.ContentTypeDetails.Description), description } };
var attributes = attributeBuilder.Create(dic);

// Create a Description entity
var entity = entityBuilder.Create(NoAppId, ctBuilder.Transient(NoAppId, Data.ContentTypeDetails.ContentTypeTypeName, Data.ContentTypeDetails.ContentTypeTypeName), attributes: attributes);
return entity;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace ToSic.Eav.Data.ContentTypes.CodeAttributes;

[PrivateApi("WIP")]
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public class ContentTypeAttributeAttribute: Attribute
{
public string Name { get; set; }
public ValueTypes Type { get; set; }
public bool IsTitle { get; set; }
public int SortOrder { get; set; }
public string Description { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
namespace ToSic.Eav.Data.ContentTypes.CodeAttributes;

[PrivateApi("WIP")]
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public class ContentTypeSpecsAttribute: Attribute
{
/// <summary>
/// Content Type Guid, as a string, because GUIDs are not supported in attributes
/// </summary>
public string Guid { get; set; }

/// <summary>
/// Content type name.
/// </summary>
public string Name { get; set; }

/// <summary>
/// Content type description.
/// </summary>
public string Description { get; set; }

/// <summary>
/// Content Type Scope - if blank, will default to "Default"
/// </summary>
public string Scope { get; set; }
}
1 change: 1 addition & 0 deletions ToSic.Eav.Core/StartUp/StartupEavCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public static IServiceCollection AddEavCore(this IServiceCollection services)
services.TryAddTransient<ValueBuilder>();
services.TryAddTransient<ContentTypeBuilder>();
services.TryAddTransient<ContentTypeAttributeBuilder>();
services.TryAddTransient<ContentTypeFactory>();

// Configuration objects
services.TryAddTransient<IGlobalConfiguration, GlobalConfiguration>();
Expand Down

0 comments on commit 5f3fad9

Please sign in to comment.