Skip to content

Commit

Permalink
custom template api
Browse files Browse the repository at this point in the history
  • Loading branch information
Eliran-Turgeman committed Jan 3, 2025
1 parent 1a4ab13 commit 6cae758
Show file tree
Hide file tree
Showing 7 changed files with 241 additions and 107 deletions.
67 changes: 67 additions & 0 deletions EmailCollector.Api/Controllers/CustomTemplateController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using EmailCollector.Api.Authentication;
using EmailCollector.Api.Controllers.RouteConsts;
using EmailCollector.Api.DTOs;
using EmailCollector.Api.Services.CustomEmailTemplates;
using EmailCollector.Domain.Enums;
using Microsoft.AspNetCore.Mvc;

namespace EmailCollector.Api.Controllers;

[Route(Routes.CustomTemplatesControllerBase)]
[ApiController]
public class CustomTemplatesController : ControllerBase
{
private readonly ILogger<CustomTemplatesController> _logger;
private readonly CustomEmailTemplatesService _customEmailTemplatesService;

public CustomTemplatesController(ILogger<CustomTemplatesController> logger,
CustomEmailTemplatesService customEmailTemplatesService)
{
_logger = logger;
_customEmailTemplatesService = customEmailTemplatesService;
}

[HttpGet("{formId:guid}" + Routes.Templates)]
[Produces("application/json")]
[ServiceFilter(typeof(ApiKeyAuthFilter))]
public async Task<IActionResult> GetCustomTemplatesByFormId(Guid formId, [FromQuery] TemplateEvent? templateEvent = null)
{
_logger.LogInformation($"Getting custom template for form {formId}.");

return templateEvent == null ?
Ok(await _customEmailTemplatesService.GetCustomEmailTemplatesByFormId(formId)) :
Ok(await _customEmailTemplatesService.GetCustomEmailTemplateByFormIdAndEvent(formId, (TemplateEvent)templateEvent));
}

[HttpGet(Routes.Templates + "/{templateId:guid}")]
[Produces("application/json")]
[ServiceFilter(typeof(ApiKeyAuthFilter))]
public async Task<IActionResult> GetCustomTemplatesByTemplateId(Guid templateId)
{
_logger.LogInformation($"Getting custom template with id {templateId}.");

return Ok(await _customEmailTemplatesService.GetCustomEmailTemplateById(templateId));
}

[HttpPost(Routes.Templates)]
[Produces("application/json")]
[ServiceFilter(typeof(ApiKeyAuthFilter))]
public async Task<ActionResult> PostCustomTemplate(CustomEmailTemplateDto templateDto)
{
_logger.LogInformation("Creating custom template.");

var templateId = await _customEmailTemplatesService.SaveCustomEmailTemplate(templateDto);
return CreatedAtAction("GetCustomTemplatesByTemplateId", new { id = templateId }, templateDto);
}

[HttpDelete(Routes.Templates + "/{templateId:guid}")]
[Produces("application/json")]
[ServiceFilter(typeof(ApiKeyAuthFilter))]
public async Task<ActionResult> DeleteCustomTemplate(Guid templateId)
{
_logger.LogInformation("Creating custom template.");

await _customEmailTemplatesService.DeleteCustomEmailTemplate(templateId);
return Ok();
}
}
39 changes: 4 additions & 35 deletions EmailCollector.Api/Controllers/EmailSignupsController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using EmailCollector.Api.Authentication;
using EmailCollector.Api.Controllers.RouteConsts;
using Microsoft.AspNetCore.Mvc;
using EmailCollector.Domain.Entities;
using Microsoft.AspNetCore.Authorization;
Expand All @@ -10,7 +11,7 @@

namespace EmailCollector.Api.Controllers;

[Route("api/[controller]")]
[Route(Routes.EmailSignupsControllerBase)]
[ApiController]
public class EmailSignupsController : ControllerBase
{
Expand All @@ -24,39 +25,7 @@ public EmailSignupsController(IEmailSignupService emailSignupService,
_logger = logger;
}

/// <summary>
/// Get email signups for a specific form.
/// </summary>
/// <param name="formId">Form id to get email signups for.</param>
/// <returns>All emails signups for formId.</returns>
/// <remarks>
/// Sample request:
///
/// GET /api/EmailSignups/form/5
///
/// </remarks>
/// <response code="200">Returns all email signups for the form.</response>
/// <response code="404">If the form is not found.</response>
[HttpGet("form/{formId}")]
[Produces("application/json")]
[ServiceFilter(typeof(ApiKeyAuthFilter))]
public async Task<IActionResult> GetFormEmailSignups(Guid formId)
{
_logger.LogInformation($"Getting email signups for form {formId}.");

var emailSignups = await _emailSignupService.GetSignupsByFormIdAsync(formId);
if (emailSignups == null)
{
return Problem(type: "Bad Request",
title: "Form is not found",
detail: $"Form with id {formId} not found",
statusCode: StatusCodes.Status404NotFound);
}

_logger.LogInformation($"Found {emailSignups.Count()} signups for form {formId}.");

return Ok(emailSignups);
}


/// <summary>
/// Submit a signup for an email form - depending on your email confirmation settings,
Expand Down Expand Up @@ -125,7 +94,7 @@ public async Task<ActionResult<EmailSignup>> PostEmailSignup([FromBody] EmailSig
/// <response code="200">Confirmation token was valid, and email is added successfully</response>
/// <response code="400">Confirmation token is invalid or expired</response>
[AllowAnonymous]
[HttpGet("confirmations")]
[HttpGet(Routes.Confirmations)]
public async Task<IActionResult> ConfirmEmailSignup([FromQuery] string confirmationToken)
{
var confirmationResult = await _emailSignupService.ConfirmEmailSignupAsync(confirmationToken);
Expand Down
91 changes: 91 additions & 0 deletions EmailCollector.Api/Controllers/ExportsController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using System.Security.Claims;
using EmailCollector.Api.Authentication;
using EmailCollector.Api.Controllers.RouteConsts;
using EmailCollector.Api.Services;
using EmailCollector.Api.Services.Exports;
using Microsoft.AspNetCore.Mvc;

namespace EmailCollector.Api.Controllers;

[Route(Routes.ExportsControllerBase)]
public class ExportsController : ControllerBase
{
private readonly IFormService _formService;
private readonly ILogger<ExportsController> _logger;

public ExportsController(IFormService formService, ILogger<ExportsController> logger)
{
_formService = formService;
_logger = logger;
}

/// <summary>
/// Export all user's forms.
/// </summary>
/// <param name="exportFormat">export format</param>
/// <returns>file containing the exported data</returns>
/// <exception cref="ArgumentException"></exception>
[HttpGet(Routes.Export)]
[ServiceFilter(typeof(ApiKeyAuthFilter))]
public async Task<IActionResult> ExportForms([FromQuery] ExportFormat exportFormat = ExportFormat.Csv)
{
_logger.LogInformation($"Exporting forms.");
var userIdClaim = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (string.IsNullOrEmpty(userIdClaim) || !Guid.TryParse(userIdClaim, out var userId))
{
return Unauthorized("Invalid or missing user identifier");
}
var forms = await _formService.GetFormsByUserAsync(userId);
var formIds = forms.Select(f => f.Id).ToList();

var fileBytes = await _formService.ExportFormsAsync(formIds, exportFormat);
if (fileBytes == null || fileBytes.Length == 0)
{
_logger.LogInformation("No forms were available for export or result was empty.");
return NotFound("No forms found to export.");
}

const string contentType = "application/octet-stream";
var fileName = exportFormat switch
{
ExportFormat.Csv => "collecto_export.csv",
ExportFormat.Json => "collecto_export.xlsx",
// should not get there, since ExportFormat is type validated OOTB.
_ => throw new ArgumentException("Unsupported export format")
};

return File(fileBytes, contentType, fileName);
}

/// <summary>
/// Exports a single form.
/// </summary>
/// <param name="formId">form to export</param>
/// <param name="exportFormat">export format</param>
/// <returns>file containing the exported data</returns>
/// <exception cref="ArgumentException"></exception>
[HttpGet("{formId:guid}" + Routes.Export)]
[ServiceFilter(typeof(ApiKeyAuthFilter))]
public async Task<IActionResult> ExportForm(Guid formId, [FromQuery] ExportFormat exportFormat = ExportFormat.Csv)
{
_logger.LogInformation($"Exporting form {formId}.");

var fileBytes = await _formService.ExportFormsAsync([formId], exportFormat);
if (fileBytes == null || fileBytes.Length == 0)
{
_logger.LogInformation("No forms were available for export or result was empty.");
return NotFound("No forms found to export.");
}

const string contentType = "application/octet-stream";
var fileName = exportFormat switch
{
ExportFormat.Csv => "collecto_export.csv",
ExportFormat.Json => "collecto_export.xlsx",
// should not get there, since ExportFormat is type validated OOTB.
_ => throw new ArgumentException("Unsupported export format")
};

return File(fileBytes, contentType, fileName);
}
}
40 changes: 40 additions & 0 deletions EmailCollector.Api/Controllers/RouteConsts/Routes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using EmailCollector.Domain.Entities;

namespace EmailCollector.Api.Controllers.RouteConsts;

public class Routes
{
/* -------- Base routes -------- */
private const string Base = "/api";
private const string ExportsBase = "/export";
private const string FormsBase = "/forms";
private const string EmailSignupsBase = "/submissions";

/* -------- Signup forms routes -------- */
/// <summary>
/// <see cref="SignupFormsController"/>
/// </summary>
public const string SignupFormsControllerBase = Base + FormsBase;
public const string GetSubmissions = "/submissions";
public const string Export = "/export";

/* -------- Exports routes -------- */
/// <summary>
/// Export is a action performed on <see cref="SignupForm"/>
/// hence we use the same base route as <see cref="SignupFormsControllerBase"/>
/// <see cref="ExportsController"/>
/// </summary>
public const string ExportsControllerBase = Base + FormsBase;

/* -------- EmailSignups routes -------- */
public const string EmailSignupsControllerBase = Base + EmailSignupsBase;
public const string Confirmations = "/confirmations";

/* -------- CustomTemplates routes -------- */
/// <summary>
/// <see cref="CustomEmailTemplate"/> is a sub-entity of <see cref="SignupForm"/>
/// hence we use the same base route as <see cref="SignupFormsControllerBase"/>
/// </summary>
public const string CustomTemplatesControllerBase = Base + FormsBase;
public const string Templates = "/templates";
}
Loading

0 comments on commit 6cae758

Please sign in to comment.