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

Updates to support Async #35

Merged
merged 6 commits into from
Mar 21, 2024
Merged
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
58 changes: 2 additions & 56 deletions .github/workflows/ci-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,60 +34,6 @@ jobs:

- name: Restore Packages
run: dotnet restore "${{ env.solution-path }}"

- name: Build
run: dotnet build "${{ env.solution-path }}" --no-restore --configuration Release -p:version=${{ steps.gitversion.outputs.majorMinorPatch }}

code-quality:
if: github.actor != 'dependabot[bot]'
runs-on: windows-latest
name: Analyze Code Quality
env:
solution-path: './src/NetCore Utilities Email.sln'
steps:
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: 11
distribution: zulu
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: Cache SonarCloud packages
uses: actions/[email protected]
with:
path: ~\sonar\cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Cache SonarCloud scanner
id: cache-sonar-scanner
uses: actions/[email protected]
with:
path: .\.sonar\scanner
key: ${{ runner.os }}-sonar-scanner
restore-keys: ${{ runner.os }}-sonar-scanner
- name: Install SonarCloud scanner
if: steps.cache-sonar-scanner.outputs.cache-hit != 'true'
shell: powershell
run: |
New-Item -Path .\.sonar\scanner -ItemType Directory
dotnet tool update dotnet-sonarscanner --tool-path .\.sonar\scanner

- name: Install GitVersion
run: dotnet tool install --global GitVersion.Tool

- name: Determine Version
id: gitversion
uses: gittools/actions/gitversion/[email protected]
with:
useConfigFile: true

- name: Build and analyze
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
shell: powershell
run: |
.\.sonar\scanner\dotnet-sonarscanner begin /k:"IowaComputerGurus_netcore.utilities.email" /o:"iowacomputergurus-github" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io"
dotnet restore "${{ env.solution-path }}"
dotnet build "${{ env.solution-path }}" --no-restore --configuration Release -p:version=${{ steps.gitversion.outputs.majorMinorPatch }}
.\.sonar\scanner\dotnet-sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}"
run: dotnet build "${{ env.solution-path }}" --no-restore --configuration Release -p:version=${{ steps.gitversion.outputs.majorMinorPatch }}
56 changes: 1 addition & 55 deletions .github/workflows/release-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,61 +5,7 @@ on:
tags:
- 'v*'

jobs:
code-quality:
runs-on: windows-latest
name: Analyze Code Quality
env:
solution-path: './src/NetCore Utilities Email.sln'
steps:
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: 11
distribution: zulu
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: Cache SonarCloud packages
uses: actions/[email protected]
with:
path: ~\sonar\cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Cache SonarCloud scanner
id: cache-sonar-scanner
uses: actions/[email protected]
with:
path: .\.sonar\scanner
key: ${{ runner.os }}-sonar-scanner
restore-keys: ${{ runner.os }}-sonar-scanner
- name: Install SonarCloud scanner
if: steps.cache-sonar-scanner.outputs.cache-hit != 'true'
shell: powershell
run: |
New-Item -Path .\.sonar\scanner -ItemType Directory
dotnet tool update dotnet-sonarscanner --tool-path .\.sonar\scanner

- name: Install GitVersion
run: dotnet tool install --global GitVersion.Tool

- name: Determine Version
id: gitversion
uses: gittools/actions/gitversion/[email protected]
with:
useConfigFile: true

- name: Build and analyze
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
shell: powershell
run: |
.\.sonar\scanner\dotnet-sonarscanner begin /k:"IowaComputerGurus_netcore.utilities.email" /o:"iowacomputergurus-github" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io"
dotnet restore "${{ env.solution-path }}"
dotnet build "${{ env.solution-path }}" --no-restore --configuration Release -p:version=${{ steps.gitversion.outputs.majorMinorPatch }}
.\.sonar\scanner\dotnet-sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}"

jobs:
build:
runs-on: ubuntu-latest
name: Build & Publish to NuGet
Expand Down
2 changes: 1 addition & 1 deletion GitVersion.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
mode: ContinuousDeployment
next-version: 5.1.4
next-version: 7.0.0
branches:
develop:
regex: develop
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@

This is a base library to provide utilities for working with email in .NET 6. This project is used by more concrete implementations such as NetCore.Utilities.Email.Smtp.

## Usage
## Breaking Changes (Version 7.0)

Starting with version 7.0, all `IEmailService` methods have been converted to asynchronous operations.

## Installation
Standard installation via NuGet Package Manager
Expand Down
118 changes: 66 additions & 52 deletions src/NetCore.Utilities.Email/EmailTemplateFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,72 +4,86 @@
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;

namespace ICG.NetCore.Utilities.Email
namespace ICG.NetCore.Utilities.Email;

/// <summary>
/// Factory class for creating email content, using templates.
/// </summary>
public interface IEmailTemplateFactory
{
/// <summary>
/// Factory class for creating email content, using templates.
/// Creates HTML email content utilizing a template
/// </summary>
public interface IEmailTemplateFactory
/// <param name="subject">The desired subject of the email</param>
/// <param name="content">The desired content of the email, HTML formatted.</param>
/// <param name="preview">
/// An optional preview textual email content element, replaced in the template for more advanced
/// control
/// </param>
/// <param name="templateName">The name of the template to use, rather than the initial template.</param>
/// <returns>The updated content wrapped in the template</returns>
/// <exception cref="ArgumentNullException">Thrown for missing subject or content</exception>
/// <exception cref="ArgumentException">Thrown if requesting a template that is not defined</exception>
/// <exception cred="FileNotFoundException">Thrown if the defined template file does not exist</exception>
string BuildEmailContent(string subject, string content, string preview = "", string templateName = "");
}

/// <inheritdoc cref="IEmailTemplateFactory" />
public class EmailTemplateFactory : IEmailTemplateFactory
{
private readonly IHostEnvironment _hostingEnvironment;
private readonly IOptions<EmailTemplateSettings> _templateSettings;

/// <summary>
/// Default constructor with injected dependencies
/// </summary>
/// <param name="templateSettings"></param>
/// <param name="hostingEnvironment"></param>
public EmailTemplateFactory(IOptions<EmailTemplateSettings> templateSettings, IHostEnvironment hostingEnvironment)
{
/// <summary>
/// Creates HTML email content utilizing a template
/// </summary>
/// <param name="subject">The desired subject of the email</param>
/// <param name="content">The desired content of the email, HTML formatted.</param>
/// <param name="preview">
/// An optional preview textual email content element, replaced in the template for more advanced
/// control
/// </param>
/// <param name="templateName">The name of the template to use, rather than the initial template.</param>
/// <returns>The updated content wrapped in the template</returns>
/// <exception cref="ArgumentNullException">Thrown for missing subject or content</exception>
/// <exception cref="ArgumentException">Thrown if requesting a template that is not defined</exception>
/// <exception cred="FileNotFoundException">Thrown if the defined template file does not exist</exception>
string BuildEmailContent(string subject, string content, string preview = "", string templateName = "");
_templateSettings = templateSettings;
_hostingEnvironment = hostingEnvironment;
}


public class EmailTemplateFactory : IEmailTemplateFactory
/// <inheritdoc cref="IEmailTemplateFactory" />
public string BuildEmailContent(string subject, string content, string preview = "", string templateName = "")
{
private readonly IHostEnvironment _hostingEnvironment;
private readonly IOptions<EmailTemplateSettings> _templateSettings;
//Validate inputs
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentNullException(nameof(subject));
}

public EmailTemplateFactory(IOptions<EmailTemplateSettings> templateSettings,
IHostEnvironment hostingEnvironment)
if (string.IsNullOrEmpty(content))
{
_templateSettings = templateSettings;
_hostingEnvironment = hostingEnvironment;
throw new ArgumentNullException(nameof(content));
}

public string BuildEmailContent(string subject, string content, string preview = "", string templateName = "")
if (!string.IsNullOrEmpty(templateName) &&
!_templateSettings.Value.AdditionalTemplates.ContainsKey(templateName))
{
//Validate inputs
if (string.IsNullOrEmpty(subject))
throw new ArgumentNullException(nameof(subject));
if (string.IsNullOrEmpty(content))
throw new ArgumentNullException(nameof(content));
if (!string.IsNullOrEmpty(templateName) &&
!_templateSettings.Value.AdditionalTemplates.ContainsKey(templateName))
throw new ArgumentException($"Requested template {templateName} was not found in configuration",
nameof(templateName));
throw new ArgumentException($"Requested template {templateName} was not found in configuration",
nameof(templateName));
}

//Get the template
var templatePath = string.IsNullOrEmpty(templateName)
? _templateSettings.Value.DefaultTemplatePath
: _templateSettings.Value.AdditionalTemplates[templateName];
var fullTemplatePath = Path.Combine(_hostingEnvironment.ContentRootPath, templatePath);
if (!File.Exists(fullTemplatePath))
throw new FileNotFoundException("Unable to find template file", fullTemplatePath);
//Get the template
var templatePath = string.IsNullOrEmpty(templateName)
? _templateSettings.Value.DefaultTemplatePath
: _templateSettings.Value.AdditionalTemplates[templateName];
var fullTemplatePath = Path.Combine(_hostingEnvironment.ContentRootPath, templatePath);
if (!File.Exists(fullTemplatePath))
{
throw new FileNotFoundException("Unable to find template file", fullTemplatePath);
}

//Replace the content
var templateBuilder =
new StringBuilder(File.ReadAllText(Path.Combine(_hostingEnvironment.ContentRootPath, templatePath)));
templateBuilder.Replace("[SUBJECT]", subject);
templateBuilder.Replace("[PREVIEW]", preview);
templateBuilder.Replace("[CONTENT]", content);
//Replace the content
var templateBuilder =
new StringBuilder(File.ReadAllText(fullTemplatePath));
templateBuilder.Replace("[SUBJECT]", subject);
templateBuilder.Replace("[PREVIEW]", preview);
templateBuilder.Replace("[CONTENT]", content);

//Return message content
return templateBuilder.ToString();
}
//Return message content
return templateBuilder.ToString();
}
}
21 changes: 15 additions & 6 deletions src/NetCore.Utilities.Email/EmailTemplateSettings.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
using System.Collections.Generic;

namespace ICG.NetCore.Utilities.Email
namespace ICG.NetCore.Utilities.Email;

/// <summary>
/// Setting object for email templates
/// </summary>
public class EmailTemplateSettings
{
public class EmailTemplateSettings
{
public string DefaultTemplatePath { get; set; }
public Dictionary<string, string> AdditionalTemplates { get; set; }
}
/// <summary>
/// The application relative file path to the default template file
/// </summary>
public string DefaultTemplatePath { get; set; }

/// <summary>
/// A collection of additional templates with a "name" and "path" for each one
/// </summary>
public Dictionary<string, string> AdditionalTemplates { get; set; }
}
Loading
Loading