Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Milestone 1 - Implement Content Template Engine #160

Open
wants to merge 1 commit into
base: dev/milestone-1
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System.Text.Json;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using uBeac.TemplateRendering;
using uBeac.Web;
using IResult = uBeac.IResult;
using JsonSerializer = System.Text.Json.JsonSerializer;

namespace Identity.MongoDB.API.Controllers;

public class ContentTemplatesController : BaseController
{
protected readonly IContentTemplateService ContentTemplateService;

public ContentTemplatesController(IContentTemplateService contentTemplateService)
{
ContentTemplateService = contentTemplateService;
}

[HttpPost]
public async Task<IResult> Test(string siteName = "uBeac", string userName = "Hesam", CancellationToken cancellationToken = default)
{
var randomNumber = new Random().Next();

var templateKey = $"sign-up-email-{randomNumber}";

var template = new ContentTemplate
{
UniqueKey = templateKey,
Subject = "Welcome to {{SiteName}}",
Body = "Hello {{UserName}}, Your account has been created successfully!"
};

await ContentTemplateService.Create(template, cancellationToken);

var model = new SignUpContent { SiteName = siteName, UserName = userName };
var result = await ContentTemplateService.Render(templateKey, model, cancellationToken);

return result.ToResult();
}

private class SignUpContent
{
public string SiteName { get; set; }
public string UserName { get; set; }
}
}
3 changes: 3 additions & 0 deletions src/Examples/Identity.MongoDB.API/Identity.MongoDB.API.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
<ProjectReference Include="..\..\Repository\uBeac.Core.Repositories.History.Extensions\uBeac.Core.Repositories.History.Extensions.csproj" />
<ProjectReference Include="..\..\Repository\uBeac.Core.Repositories.History.MongoDB\uBeac.Core.Repositories.History.MongoDB.csproj" />
<ProjectReference Include="..\..\Logging\uBeac.Core.Logging.MongoDB\uBeac.Core.Logging.MongoDB.csproj" />
<ProjectReference Include="..\..\TemplateRendering\uBeac.Core.TemplateRendering.Renderers.Mustache\uBeac.Core.TemplateRendering.Renderers.Mustache.csproj" />
<ProjectReference Include="..\..\TemplateRendering\uBeac.Core.TemplateRendering.Repositories.MongoDB\uBeac.Core.TemplateRendering.Repositories.MongoDB.csproj" />
<ProjectReference Include="..\..\TemplateRendering\uBeac.Core.TemplateRendering\uBeac.Core.TemplateRendering.csproj" />
<ProjectReference Include="..\..\Web\uBeac.Core.Web.Common\uBeac.Core.Web.Common.csproj" />
<ProjectReference Include="..\..\Web\uBeac.Core.Web.Jwt\uBeac.Core.Web.Jwt.csproj" />
<ProjectReference Include="..\..\Web\uBeac.Core.Web.Swagger\uBeac.Core.Web.Swagger.csproj" />
Expand Down
7 changes: 7 additions & 0 deletions src/Examples/Identity.MongoDB.API/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@
builder.Services.AddMongo<HistoryMongoDBContext>("HistoryConnection");
builder.Services.AddHistory<MongoDBHistoryRepository>().For<User>();

// Adding template rendering
builder.Services.AddTemplateRendering(templateRendering =>
{
templateRendering.UseMongoDB<MongoDBContext>(); // It's not required, If you don't want storing your templates in the database, remove it!
templateRendering.UseMustacheRenderer();
});

// Adding CORS
var corsPolicyOptions = builder.Configuration.GetSection("CorsPolicy");
builder.Services.AddCorsPolicy(corsPolicyOptions);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace uBeac.TemplateRendering;

public class ContentTemplate : Entity
{
public string UniqueKey { get; set; } // "sign-up-email"
public string Subject { get; set; } // "Welcome to {{SiteName}}"
public string Body { get; set; } // "Hello {{Name}}, Your account has been created successfully!"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace uBeac.TemplateRendering;

public interface ITemplateRenderingBuilder
{
ITemplateRenderingBuilder SetRepository(Type repositoryType);
ITemplateRenderingBuilder SetService(Type serviceType);
ITemplateRenderingBuilder SetRenderer(Type rendererType);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace uBeac.TemplateRendering;

public interface ITemplateRenderer
{
Task<string> Render(string template, object model);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using uBeac.Repositories;

namespace uBeac.TemplateRendering;

public interface IContentTemplateRepository : IEntityRepository<ContentTemplate>
{
Task<ContentTemplate> GetByUniqueKey(string uniqueKey, CancellationToken cancellationToken = default);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using uBeac.Services;

namespace uBeac.TemplateRendering;

public interface IContentTemplateService : IEntityService<ContentTemplate>
{
Task<ContentTemplate> GetByUniqueKey(string uniqueKey, CancellationToken cancellationToken = default);

Task<RenderedContent> Render(string templateKey, object model, CancellationToken cancellationToken = default);
Task<RenderedContent> Render(ContentTemplate template, object model, CancellationToken cancellationToken = default);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace uBeac.TemplateRendering;

public class RenderedContent
{
public string Subject { get; set; }
public string Body { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\Common\uBeac.Core.Common\uBeac.Core.Common.csproj" />
<ProjectReference Include="..\..\Repository\uBeac.Core.Repositories.Abstractions\uBeac.Core.Repositories.Abstractions.csproj" />
<ProjectReference Include="..\..\Service\uBeac.Core.Services.Abstractions\uBeac.Core.Services.Abstractions.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using uBeac.TemplateRendering;
using uBeac.TemplateRendering.Renderers.Mustache;

namespace Microsoft.Extensions.DependencyInjection;

public static class BuilderExtensions
{
public static ITemplateRenderingBuilder UseMustacheRenderer(this ITemplateRenderingBuilder builder)
{
builder.SetRenderer(typeof(MustacheTemplateRenderer));

return builder;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Stubble.Core.Builders;
using Stubble.Extensions.JsonNet;

namespace uBeac.TemplateRendering.Renderers.Mustache;

public class MustacheTemplateRenderer : ITemplateRenderer
{
public async Task<string> Render(string template, object model)
{
var stubble = new StubbleBuilder()
.Configure(settings =>
{
settings.AddJsonNet();
settings.SetIgnoreCaseOnKeyLookup(true);
settings.SetMaxRecursionDepth(512);
})
.Build();

return await stubble.RenderAsync(template, model);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
<PackageReference Include="Stubble.Core" Version="1.10.8" />
<PackageReference Include="Stubble.Extensions.JsonNet" Version="1.2.3" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\uBeac.Core.TemplateRendering.Abstractions\uBeac.Core.TemplateRendering.Abstractions.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using uBeac.Repositories.MongoDB;
using uBeac.TemplateRendering;
using uBeac.TemplateRendering.Repositories.MongoDB;

namespace Microsoft.Extensions.DependencyInjection;

public static class BuilderExtensions
{
public static ITemplateRenderingBuilder UseMongoDB<TContext>(this ITemplateRenderingBuilder builder)
where TContext : IMongoDBContext
{
builder.SetRepository(typeof(MongoDBContentTemplateRepository<TContext>));

return builder;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using uBeac.Repositories.History;
using uBeac.Repositories.MongoDB;

namespace uBeac.TemplateRendering.Repositories.MongoDB;

public interface IMongoDBContentTemplateRepository : IContentTemplateRepository
{
}

public class MongoDBContentTemplateRepository<TContext> : MongoEntityRepository<ContentTemplate, TContext>, IMongoDBContentTemplateRepository
where TContext : IMongoDBContext
{
public MongoDBContentTemplateRepository(TContext mongoDbContext, IApplicationContext applicationContext, IHistoryManager history) : base(mongoDbContext, applicationContext, history)
{
}

public async Task<ContentTemplate> GetByUniqueKey(string uniqueKey, CancellationToken cancellationToken = default)
{
return await Collection
.AsQueryable()
.SingleAsync(x => x.UniqueKey == uniqueKey, cancellationToken);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\Repository\uBeac.Core.Repositories.MongoDB\uBeac.Core.Repositories.MongoDB.csproj" />
<ProjectReference Include="..\uBeac.Core.TemplateRendering.Abstractions\uBeac.Core.TemplateRendering.Abstractions.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;

namespace uBeac.TemplateRendering;

public class ServiceCollectionTemplateRenderingBuilder : ITemplateRenderingBuilder
{
protected readonly IServiceCollection Services;

public ServiceCollectionTemplateRenderingBuilder(IServiceCollection services)
{
Services = services;
}

public ITemplateRenderingBuilder SetRepository(Type repositoryType)
{
Services.TryAddScoped(typeof(IContentTemplateRepository), repositoryType);

return this;
}

public ITemplateRenderingBuilder SetService(Type serviceType)
{
Services.TryAddScoped(typeof(IContentTemplateService), serviceType);

return this;
}

public ITemplateRenderingBuilder SetRenderer(Type rendererType)
{
Services.TryAddScoped(typeof(ITemplateRenderer), rendererType);

return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using uBeac.TemplateRendering;
using uBeac.TemplateRendering.Services;

namespace Microsoft.Extensions.DependencyInjection;

public static class ServiceCollectionExtensions
{
public static IServiceCollection AddTemplateRendering(this IServiceCollection services, Action<ITemplateRenderingBuilder> builder)
{
var serviceCollectionBuilder = new ServiceCollectionTemplateRenderingBuilder(services);

builder(serviceCollectionBuilder);

serviceCollectionBuilder.SetService(typeof(ContentTemplateService));

return services;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using uBeac.Services;

namespace uBeac.TemplateRendering.Services;

public class ContentTemplateService : EntityService<ContentTemplate>, IContentTemplateService
{
protected new readonly IContentTemplateRepository Repository;
protected readonly ITemplateRenderer Renderer;

public ContentTemplateService(IContentTemplateRepository repository, ITemplateRenderer renderer) : base(repository)
{
Repository = repository;
Renderer = renderer;
}

public async Task<ContentTemplate> GetByUniqueKey(string uniqueKey, CancellationToken cancellationToken = default)
{
return await Repository.GetByUniqueKey(uniqueKey, cancellationToken);
}

public async Task<RenderedContent> Render(string templateKey, object model, CancellationToken cancellationToken = default)
{
var template = await Repository.GetByUniqueKey(templateKey, cancellationToken);

return await Render(template, model, cancellationToken);
}

public async Task<RenderedContent> Render(ContentTemplate template, object model, CancellationToken cancellationToken = default)
{
var result = new RenderedContent();

if (!string.IsNullOrWhiteSpace(template.Subject))
{
result.Subject = await Renderer.Render(template.Subject, model);
}

result.Body = await Renderer.Render(template.Body, model);

return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\Service\uBeac.Core.Services\uBeac.Core.Services.csproj" />
<ProjectReference Include="..\uBeac.Core.TemplateRendering.Abstractions\uBeac.Core.TemplateRendering.Abstractions.csproj" />
</ItemGroup>

</Project>
Loading