Skip to content

Resend api added - #161

Merged
maximgorbatyuk merged 3 commits into
mainfrom
resend-integration
Jan 20, 2026
Merged

maximgorbatyuk merged 3 commits into
mainfrom
resend-integration

Conversation

@maximgorbatyuk

@maximgorbatyuk maximgorbatyuk commented Jan 20, 2026 •

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Admin endpoint to send custom emails (subject, from, to, optional CC, HTML body).
  • Chores

    • Switched email provider to Resend and updated deployment/configuration to use the new provider's API key.
  • Removed

    • Deprecated webhook integration and related webhook handling logic.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Jan 20, 2026 •

Copy link
Copy Markdown
Contributor

Walkthrough

Switches email provider from SendGrid to Resend: adds a Resend-based sender and admin email endpoint, removes SendGrid sender and webhook controller, updates DI and project dependencies, adds Resend config keys, and modifies deploy workflow to inject the Resend secret.

Changes

Cohort / File(s) Summary
Email service - new implementation
src/Infrastructure/Emails/ResendEmailApiSender.cs
New public ResendEmailApiSender implementing IEmailApiSender; reads ResendComApiKey from configuration, maps EmailContent to Resend EmailMessage (To/Cc/Bcc), sends via Resend client, and logs results.
Email service - removed implementation
src/Infrastructure/Emails/SendgridEmailApiSender.cs
Removed SendGrid-based SendgridEmailApiSender (client initialization, message composition, sending and logging).
Dependency updates
src/Infrastructure/Infrastructure.csproj
Removed SendGrid and StrongGrid package references; added Resend package reference (0.2.1).
Service registration
src/Web.Api/Setup/ServiceRegistration.cs
Swapped DI registration to use ResendEmailApiSender instead of SendgridEmailApiSender for IEmailApiSender in non-development environments.
Configuration
src/Web.Api/appsettings.json, src/Web.Api/appsettings.Production.json
Added ResendComApiKey key in both files; production file uses placeholder __RESEND_COM_API_KEY.
Admin API
src/Web.Api/Features/Admin/AdminEmailController.cs
Added AdminEmailController exposing POST /api/admin/emails/send to send custom emails via IEmailApiSender; includes request/response records and validation attributes.
Webhook removal
src/Web.Api/Features/Webhooks/WebhooksController.cs
Removed SendGrid webhook controller and related parsing/handling logic (spam-report handling, signature verification).
Build & solution
.github/workflows/deploy.yml, src/techinterview.sln
Deploy workflow substitution changed to inject RESEND_COM_API_KEY instead of SENDGRID_API_KEY; added deploy.yml as a solution item.
Minor handler tweak
src/Web.Api/Features/Salaries/UpdateSalary/UpdateSalaryHandler.cs
Passed cancellationToken to _auth.GetCurrentUserOrNullAsync and swapped thrown exception to NoPermissionsException.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Admin as "Admin Client"
  participant API as "Web.Api (AdminEmailController)"
  participant Sender as "ResendEmailApiSender"
  participant Resend as "Resend API"

  rect rgba(0,128,0,0.5)
  Admin->>API: POST /api/admin/emails/send (SendCustomEmailRequest)
  end

  rect rgba(0,0,255,0.5)
  API->>Sender: Build EmailContent and call SendAsync
  end

  rect rgba(255,165,0,0.5)
  Sender->>Resend: EmailSendAsync(EmailMessage) [To/Cc/Bcc, From, Subject, Html]
  Resend-->>Sender: Send response (status/content)
  end

  Sender-->>API: Return result / log outcome
  API-->>Admin: 200 OK (SendCustomEmailResponse)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Resend api added' is vague and generic; it lacks specificity about what the change accomplishes and doesn't clearly convey the migration from SendGrid to Resend. Consider a more descriptive title such as 'Replace SendGrid email service with Resend integration' to clearly communicate the primary change.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@src/Infrastructure/Emails/ResendEmailApiSender.cs`:
- Around line 70-75: The catch in ResendEmailApiSender (inside the
SendEmailAsync method) currently logs exceptions but swallows them; update the
method to surface failures by either rethrowing the exception after logging (use
"throw;" to preserve stack trace) or change the method signature and related
interface to return a result/boolean indicating success and return a failure
result after logging; ensure all callers are updated to handle the rethrown
exception or the new result type accordingly.
- Around line 46-62: In ResendEmailApiSender.cs the code calls email.Cc.Any()
and email.HiddenCc.Any() which can throw if those lists are null; update the
checks to guard for null (e.g., use email.Cc != null && email.Cc.Any() or
email.Cc?.Any() == true) and when iterating use a null-safe source (e.g.,
iterate over email.Cc ?? Enumerable.Empty<...>() or only enter the foreach after
the null check), keeping the existing assignments to message.Cc and message.Bcc;
reference symbols: email.Cc, email.HiddenCc, message.Cc, message.Bcc in the
sending method of the ResendEmailApiSender class.
- Around line 41-44: The loop that adds recipients to the MailMessage (the block
containing message.To.Add(recipient) in ResendEmailApiSender.cs) can throw a
NullReferenceException because EmailContent.Recipients may be null; add a
defensive null/empty check before iterating (e.g., guard with email.Recipients
!= null && email.Recipients.Any()) or iterate over email.Recipients ??
Enumerable.Empty<string>() so the foreach only runs when recipients exist;
ensure any needed System.Linq/System.Collections.Generic imports are present and
follow the same pattern used for Cc and HiddenCc.
🧹 Nitpick comments (1)
src/Infrastructure/Emails/ResendEmailApiSender.cs (1)

15-24: Consider injecting IResend instead of creating it in the constructor.

Creating the ResendClient directly in the constructor violates dependency injection best practices and makes unit testing difficult. Consider registering IResend in the DI container and injecting it.

♻️ Suggested refactor
 public ResendEmailApiSender(
-    IConfiguration configuration,
+    IResend client,
     ILogger<ResendEmailApiSender> logger)
 {
     _logger = logger;
-    var apiKey = configuration["ResendComApiKey"]
-        ?? throw new InvalidOperationException("ResendComApiKey configuration is missing");
-
-    _client = ResendClient.Create(apiKey);
+    _client = client;
 }

Then register the client in ServiceRegistration.cs:

services.AddOptions();
services.AddHttpClient<ResendClient>();
services.Configure<ResendClientOptions>(o => 
{
    o.ApiToken = configuration["ResendComApiKey"] 
        ?? throw new InvalidOperationException("ResendComApiKey configuration is missing");
});
services.AddTransient<IResend, ResendClient>();
services.AddTransient<IEmailApiSender, ResendEmailApiSender>();

Based on coding guidelines requiring review of dependency injection best practices.

Comment on lines +41 to +44
foreach (var recipient in email.Recipients)
{
message.To.Add(recipient);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, locate and examine the ResendEmailApiSender.cs file
find . -name "ResendEmailApiSender.cs" -type f

Repository: Techinterview-space/web-api

Length of output: 122


🏁 Script executed:

# Also search for the EmailContent class definition
fd "EmailContent" --type f -e cs

Repository: Techinterview-space/web-api

Length of output: 131


🏁 Script executed:

# Check for any file that might contain the email-related models
fd -e cs -x grep -l "Recipients" {} \;

Repository: Techinterview-space/web-api

Length of output: 372


🏁 Script executed:

# Read the ResendEmailApiSender.cs file to see the context around lines 41-44
cat -n ./src/Infrastructure/Emails/ResendEmailApiSender.cs

Repository: Techinterview-space/web-api

Length of output: 2747


🏁 Script executed:

# Read the EmailContent.cs file to understand Recipients property
cat -n src/Infrastructure/Emails/Contracts/Requests/EmailContent.cs

Repository: Techinterview-space/web-api

Length of output: 1196


🏁 Script executed:

# Check if the project has nullable reference types enabled
cat -n src/Infrastructure/Emails/ResendEmailApiSender.cs | head -20

Repository: Techinterview-space/web-api

Length of output: 805


🏁 Script executed:

# Check if there are any usage patterns or prior validation for Recipients
rg -n "Recipients" --type cs -B 2 -A 2 src/Web.Api/Services/Emails/TechInterviewerEmailService.cs

Repository: Techinterview-space/web-api

Length of output: 303


🏁 Script executed:

# Check the standard.ruleset to understand linting rules
find . -name "standard.ruleset" -o -name "*.ruleset" | head -5

Repository: Techinterview-space/web-api

Length of output: 93


Add null/empty validation for Recipients to prevent NullReferenceException.

The Recipients collection can be null when EmailContent is instantiated via the parameterless constructor (e.g., ASP.NET model binding), and iterating over it without checking will throw. While Cc and HiddenCc are defensively validated with .Any() checks before iteration (lines 46, 55), Recipients lacks this protection.

Proposed fix
+        if (email.Recipients == null || !email.Recipients.Any())
+        {
+            throw new ArgumentException("Email must have at least one recipient", nameof(email));
+        }
+
         foreach (var recipient in email.Recipients)
         {
             message.To.Add(recipient);
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
foreach (var recipient in email.Recipients)
{
message.To.Add(recipient);
}
if (email.Recipients == null || !email.Recipients.Any())
{
throw new ArgumentException("Email must have at least one recipient", nameof(email));
}
foreach (var recipient in email.Recipients)
{
message.To.Add(recipient);
}
🤖 Prompt for AI Agents
In `@src/Infrastructure/Emails/ResendEmailApiSender.cs` around lines 41 - 44, The
loop that adds recipients to the MailMessage (the block containing
message.To.Add(recipient) in ResendEmailApiSender.cs) can throw a
NullReferenceException because EmailContent.Recipients may be null; add a
defensive null/empty check before iterating (e.g., guard with email.Recipients
!= null && email.Recipients.Any()) or iterate over email.Recipients ??
Enumerable.Empty<string>() so the foreach only runs when recipients exist;
ensure any needed System.Linq/System.Collections.Generic imports are present and
follow the same pattern used for Cc and HiddenCc.

Comment on lines +46 to +62
if (email.Cc.Any())
{
message.Cc ??= new EmailAddressList();
foreach (var cc in email.Cc)
{
message.Cc.Add(cc);
}
}

if (email.HiddenCc.Any())
{
message.Bcc ??= new EmailAddressList();
foreach (var bcc in email.HiddenCc)
{
message.Bcc.Add(bcc);
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Potential NullReferenceException when calling .Any() on null collections.

If email.Cc or email.HiddenCc are null, calling .Any() will throw. Consider using null-conditional or null-coalescing patterns.

🐛 Proposed fix
-        if (email.Cc.Any())
+        if (email.Cc?.Any() == true)
         {
             message.Cc ??= new EmailAddressList();
             foreach (var cc in email.Cc)
             {
                 message.Cc.Add(cc);
             }
         }

-        if (email.HiddenCc.Any())
+        if (email.HiddenCc?.Any() == true)
         {
             message.Bcc ??= new EmailAddressList();
             foreach (var bcc in email.HiddenCc)
             {
                 message.Bcc.Add(bcc);
             }
         }
🤖 Prompt for AI Agents
In `@src/Infrastructure/Emails/ResendEmailApiSender.cs` around lines 46 - 62, In
ResendEmailApiSender.cs the code calls email.Cc.Any() and email.HiddenCc.Any()
which can throw if those lists are null; update the checks to guard for null
(e.g., use email.Cc != null && email.Cc.Any() or email.Cc?.Any() == true) and
when iterating use a null-safe source (e.g., iterate over email.Cc ??
Enumerable.Empty<...>() or only enter the foreach after the null check), keeping
the existing assignments to message.Cc and message.Bcc; reference symbols:
email.Cc, email.HiddenCc, message.Cc, message.Bcc in the sending method of the
ResendEmailApiSender class.

Comment on lines +70 to +75
catch (Exception e)
{
_logger.LogError(
e,
"Could not send email via Resend");
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Swallowing exceptions silently hides email delivery failures.

The catch block logs the error but doesn't propagate it. Callers will have no way to know the email failed to send, which could lead to silent failures in critical notification flows (e.g., password resets, interview confirmations).

🐛 Proposed fix - rethrow or return a result

Option 1: Rethrow after logging:

         catch (Exception e)
         {
             _logger.LogError(
                 e,
                 "Could not send email via Resend");
+            throw;
         }

Option 2: Return a result type that indicates success/failure (requires interface change).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
catch (Exception e)
{
_logger.LogError(
e,
"Could not send email via Resend");
}
catch (Exception e)
{
_logger.LogError(
e,
"Could not send email via Resend");
throw;
}
🤖 Prompt for AI Agents
In `@src/Infrastructure/Emails/ResendEmailApiSender.cs` around lines 70 - 75, The
catch in ResendEmailApiSender (inside the SendEmailAsync method) currently logs
exceptions but swallows them; update the method to surface failures by either
rethrowing the exception after logging (use "throw;" to preserve stack trace) or
change the method signature and related interface to return a result/boolean
indicating success and return a failure result after logging; ensure all callers
are updated to handle the rethrown exception or the new result type accordingly.

@maximgorbatyuk
maximgorbatyuk merged commit 3a059c0 into main Jan 20, 2026
3 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/Web.Api/Features/Admin/AdminEmailController.cs`:
- Around line 25-49: SendCustomEmailAsync currently assumes
_emailApiSender.SendAsync always succeeds, but ResendEmailApiSender swallows
exceptions so the controller returns Success=true even on failure; update the
flow so send failures are propagated and surfaced: modify ResendEmailApiSender
to either throw the exception on failure or return a failure result, then update
SendCustomEmailAsync to await SendAsync and either catch exceptions and return
an error IActionResult (e.g., BadRequest or StatusCode(500) with Success=false
and a helpful Message) or inspect the returned result and return Success=false
when appropriate; reference SendCustomEmailAsync, _emailApiSender.SendAsync,
ResendEmailApiSender, and SendCustomEmailResponse when making the changes.

In `@src/Web.Api/Features/Salaries/UpdateSalary/UpdateSalaryHandler.cs`:
- Around line 37-43: currentUser may be null when calling
_auth.GetCurrentUserOrNullAsync, so update the logic in UpdateSalaryHandler to
handle that: either replace GetCurrentUserOrNullAsync with a non-null-returning
method like GetCurrentUserAsync (so the intent is explicit) or add an explicit
null check after calling GetCurrentUserOrNullAsync and throw an appropriate
authentication exception (e.g., UnauthorizedAccessException or a custom
NotAuthenticatedException) before evaluating currentUser.Has(Role.Admin) or
accessing currentUser.Id; ensure the check occurs immediately after the call to
avoid a NullReferenceException.

Comment on lines +25 to +49
[HttpPost("send")]
public async Task<IActionResult> SendCustomEmailAsync(
[FromBody] SendCustomEmailRequest request,
CancellationToken cancellationToken)
{
var recipients = new List<string> { request.To };

var cc = !string.IsNullOrWhiteSpace(request.Cc)
? new List<string> { request.Cc }
: new List<string>();

await _emailApiSender.SendAsync(
new EmailContent(
request.From,
request.Subject,
request.HtmlBody,
recipients,
cc),
cancellationToken);

return Ok(new SendCustomEmailResponse
{
Success = true,
Message = "Email sent successfully"
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don’t return success when the send fails.
ResendEmailApiSender currently swallows exceptions and only logs them, so this action will always return Success=true even when the email was not sent. Please propagate failures (throw or return a result) and surface a non‑200 response when sending fails.

🔧 Proposed controller-side handling (pairs with making sender throw or return failure)
-        await _emailApiSender.SendAsync(
-            new EmailContent(
-                request.From,
-                request.Subject,
-                request.HtmlBody,
-                recipients,
-                cc),
-            cancellationToken);
-
-        return Ok(new SendCustomEmailResponse
-        {
-            Success = true,
-            Message = "Email sent successfully"
-        });
+        try
+        {
+            await _emailApiSender.SendAsync(
+                new EmailContent(
+                    request.From,
+                    request.Subject,
+                    request.HtmlBody,
+                    recipients,
+                    cc),
+                cancellationToken);
+
+            return Ok(new SendCustomEmailResponse
+            {
+                Success = true,
+                Message = "Email sent successfully"
+            });
+        }
+        catch (Exception)
+        {
+            return StatusCode(502, new SendCustomEmailResponse
+            {
+                Success = false,
+                Message = "Email send failed"
+            });
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
[HttpPost("send")]
public async Task<IActionResult> SendCustomEmailAsync(
[FromBody] SendCustomEmailRequest request,
CancellationToken cancellationToken)
{
var recipients = new List<string> { request.To };
var cc = !string.IsNullOrWhiteSpace(request.Cc)
? new List<string> { request.Cc }
: new List<string>();
await _emailApiSender.SendAsync(
new EmailContent(
request.From,
request.Subject,
request.HtmlBody,
recipients,
cc),
cancellationToken);
return Ok(new SendCustomEmailResponse
{
Success = true,
Message = "Email sent successfully"
});
[HttpPost("send")]
public async Task<IActionResult> SendCustomEmailAsync(
[FromBody] SendCustomEmailRequest request,
CancellationToken cancellationToken)
{
var recipients = new List<string> { request.To };
var cc = !string.IsNullOrWhiteSpace(request.Cc)
? new List<string> { request.Cc }
: new List<string>();
try
{
await _emailApiSender.SendAsync(
new EmailContent(
request.From,
request.Subject,
request.HtmlBody,
recipients,
cc),
cancellationToken);
return Ok(new SendCustomEmailResponse
{
Success = true,
Message = "Email sent successfully"
});
}
catch (Exception)
{
return StatusCode(502, new SendCustomEmailResponse
{
Success = false,
Message = "Email send failed"
});
}
}
🤖 Prompt for AI Agents
In `@src/Web.Api/Features/Admin/AdminEmailController.cs` around lines 25 - 49,
SendCustomEmailAsync currently assumes _emailApiSender.SendAsync always
succeeds, but ResendEmailApiSender swallows exceptions so the controller returns
Success=true even on failure; update the flow so send failures are propagated
and surfaced: modify ResendEmailApiSender to either throw the exception on
failure or return a failure result, then update SendCustomEmailAsync to await
SendAsync and either catch exceptions and return an error IActionResult (e.g.,
BadRequest or StatusCode(500) with Success=false and a helpful Message) or
inspect the returned result and return Success=false when appropriate; reference
SendCustomEmailAsync, _emailApiSender.SendAsync, ResendEmailApiSender, and
SendCustomEmailResponse when making the changes.

Comment on lines +37 to 43
var currentUser = await _auth.GetCurrentUserOrNullAsync(cancellationToken);

if (!currentUser.Has(Role.Admin) &&
salary.UserId != currentUser.Id)
{
throw new ForbiddenException("You can only edit your own salary records");
throw new NoPermissionsException("You can only edit your own salary records");
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Potential NullReferenceException when accessing currentUser.

The method GetCurrentUserOrNullAsync (by naming convention) can return null, but currentUser is used directly on lines 39-40 without a null check. If no authenticated user exists, this will throw a NullReferenceException.

🐛 Proposed fix: Add null check or throw appropriate exception
 var currentUser = await _auth.GetCurrentUserOrNullAsync(cancellationToken);
+if (currentUser is null)
+{
+    throw new NoPermissionsException("Authentication required");
+}

 if (!currentUser.Has(Role.Admin) &&
     salary.UserId != currentUser.Id)
 {
     throw new NoPermissionsException("You can only edit your own salary records");
 }

Alternatively, if the endpoint is already protected by an [Authorize] attribute and currentUser is guaranteed to be non-null at this point, consider using a method like GetCurrentUserAsync that throws if the user is not authenticated, to make this expectation explicit and avoid the misleading OrNull suffix.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
var currentUser = await _auth.GetCurrentUserOrNullAsync(cancellationToken);
if (!currentUser.Has(Role.Admin) &&
salary.UserId != currentUser.Id)
{
throw new ForbiddenException("You can only edit your own salary records");
throw new NoPermissionsException("You can only edit your own salary records");
}
var currentUser = await _auth.GetCurrentUserOrNullAsync(cancellationToken);
if (currentUser is null)
{
throw new NoPermissionsException("Authentication required");
}
if (!currentUser.Has(Role.Admin) &&
salary.UserId != currentUser.Id)
{
throw new NoPermissionsException("You can only edit your own salary records");
}
🤖 Prompt for AI Agents
In `@src/Web.Api/Features/Salaries/UpdateSalary/UpdateSalaryHandler.cs` around
lines 37 - 43, currentUser may be null when calling
_auth.GetCurrentUserOrNullAsync, so update the logic in UpdateSalaryHandler to
handle that: either replace GetCurrentUserOrNullAsync with a non-null-returning
method like GetCurrentUserAsync (so the intent is explicit) or add an explicit
null check after calling GetCurrentUserOrNullAsync and throw an appropriate
authentication exception (e.g., UnauthorizedAccessException or a custom
NotAuthenticatedException) before evaluating currentUser.Has(Role.Admin) or
accessing currentUser.Id; ensure the check occurs immediately after the call to
avoid a NullReferenceException.

@maximgorbatyuk
maximgorbatyuk deleted the resend-integration branch January 20, 2026 06:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant