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 1 commit
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
61 changes: 10 additions & 51 deletions .github/workflows/ci-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,60 +34,19 @@ 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: Test
run: dotnet test "${{ env.solution-path }}" --no-build --configuration Release --collect "XPlat Code Coverage" -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=opencover --logger "trx;LogFileName=unittests.trx"

- name: Build and analyze
- name: Push Coverage to Codacy
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
shell: powershell
CODACY_ORGANIZATION_PROVIDER: ${{ secrets.CODACY_ORGANIZATION_PROVIDER }}
CODACY_USERNAME: ${{ secrets.CODACY_USERNAME }}
CODACY_PROJECT_NAME: ${{ secrets.CODACY_PROJECT_NAME }}
CODACY_API_TOKEN: ${{ secrets.CODACY_API_TOKEN }}
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 }}"
bash <(curl -Ls https://coverage.codacy.com/get.sh) report $(find . -name '*.opencover.xml' -printf '-r %p ')
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 were converted to Async!
mitchelsellers marked this conversation as resolved.
Show resolved Hide resolved

## Installation
Standard installation via NuGet Package Manager
Expand Down
118 changes: 61 additions & 57 deletions src/NetCore.Utilities.Email/EmailTemplateFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,72 +4,76 @@
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
{
/// <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 = "");
}
/// <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;

public class EmailTemplateFactory : IEmailTemplateFactory
/// <summary>
/// Default constructor with injected dependencies
/// </summary>
/// <param name="templateSettings"></param>
/// <param name="hostingEnvironment"></param>
public EmailTemplateFactory(IOptions<EmailTemplateSettings> templateSettings, IHostEnvironment hostingEnvironment)
{
private readonly IHostEnvironment _hostingEnvironment;
private readonly IOptions<EmailTemplateSettings> _templateSettings;

public EmailTemplateFactory(IOptions<EmailTemplateSettings> templateSettings,
IHostEnvironment hostingEnvironment)
{
_templateSettings = templateSettings;
_hostingEnvironment = hostingEnvironment;
}
_templateSettings = templateSettings;
_hostingEnvironment = hostingEnvironment;
}

public string BuildEmailContent(string subject, string content, string preview = "", string 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));
/// <inheritdoc cref="IEmailTemplateFactory" />
public string BuildEmailContent(string subject, string content, string preview = "", string 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));

//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