Sending the survey to multiple users created
This commit is contained in:
parent
644893ded8
commit
d733b2cdb1
6 changed files with 167 additions and 118 deletions
|
|
@ -465,120 +465,69 @@ namespace Web.Areas.Admin.Controllers
|
|||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
|
||||
|
||||
|
||||
var questionnairePath = _configuration["Email:Questionnaire"];
|
||||
int surveyId = viewModel.QuestionnaireId;
|
||||
|
||||
var userEmailEncoded = HttpUtility.UrlEncode(viewModel.Email);
|
||||
|
||||
|
||||
DateTime currentDateTime;
|
||||
if (viewModel.ExpirationDateTime.HasValue)
|
||||
{
|
||||
currentDateTime = viewModel.ExpirationDateTime.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
currentDateTime = DateTime.Now;
|
||||
}
|
||||
|
||||
// Calculate the expiration date and time by adding 5 minutes to the current date and time
|
||||
DateTime expiryDateTime = currentDateTime;
|
||||
|
||||
// Generate a unique token, for example, using a cryptographic library or a GUID
|
||||
DateTime currentDateTime = viewModel.ExpirationDateTime.HasValue ? viewModel.ExpirationDateTime.Value : DateTime.Now;
|
||||
DateTime expiryDateTime = currentDateTime; // This line might need adjustment if you are actually setting an expiry.
|
||||
string token = Guid.NewGuid().ToString();
|
||||
|
||||
// Append the expiration date and time to the token (you might want to encrypt it for security)
|
||||
string tokenWithExpiry = $"{token}|{expiryDateTime.ToString("yyyy-MM-ddTHH:mm:ssZ")}";
|
||||
|
||||
var completeUrl = $"{Request.Scheme}://{Request.Host}/{questionnairePath}/{viewModel.QuestionnaireId}?t={tokenWithExpiry}&E={userEmailEncoded}";
|
||||
|
||||
//var completeUrl = $"{Request.Scheme}://{Request.Host}/{questionnairePath}/{viewModel.QuestionnaireId}?t={tokenWithExpiry}&E={userEmail}";
|
||||
|
||||
//var completeUrl = $"{Request.Scheme}://{Request.Host}/{questionnairePath}/{viewModel.QuestionnaireId}";
|
||||
|
||||
|
||||
var toEmail = viewModel.Email;
|
||||
var emailList = viewModel.Emails.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(email => email.Trim())
|
||||
.ToList();
|
||||
var question = _questionnaire.GetQuesById(viewModel.Id);
|
||||
|
||||
var subject = question.Title;
|
||||
|
||||
// Construct the email body with HTML formatting
|
||||
string emailBody = $@"
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
/* Inline CSS styles */
|
||||
body {{
|
||||
font-family: Arial, sans-serif;
|
||||
}}
|
||||
|
||||
.container {{
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
border: 0.5px solid #ccc;
|
||||
border-radius: 5px;
|
||||
background-color: #f9f9f9;
|
||||
}}
|
||||
.button {{
|
||||
display: inline-block;
|
||||
padding: 10px 20px;
|
||||
background-color: #007bff;
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
border-radius: 4px;
|
||||
}}
|
||||
.button:hover {{
|
||||
background-color: #0056b3;
|
||||
}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class='container'>
|
||||
<h4>Hey {viewModel.Name},</h4>
|
||||
<h5>{subject}</h5>
|
||||
<p>Thank you for participating in our survey. Your feedback is valuable to us.</p>
|
||||
<p>Please click the button below to start the survey:</p>
|
||||
<p class=""text-danger"">The survey will be expire :{expiryDateTime.ToLongDateString()} Time: {expiryDateTime.ToShortTimeString()} </p>
|
||||
<div style='text-align: center;'>
|
||||
<a href='{completeUrl}' class='button'>Start Survey</a>
|
||||
<br>
|
||||
|
||||
</div><br>
|
||||
<p><strong>Søren Eggert Lundsteen Olsen</strong><br>
|
||||
Seosoft ApS<br>
|
||||
<hr>
|
||||
Hovedgaden 3
|
||||
Jordrup<br>
|
||||
Kolding 6064<br>
|
||||
Denmark</p>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>";
|
||||
|
||||
|
||||
// Call the SendConfirmationEmailAsync method to send the email
|
||||
var emailSend = new EmailToSend(toEmail, subject, emailBody);
|
||||
|
||||
bool emailSent = await _emailServices.SendConfirmationEmailAsync(emailSend);
|
||||
|
||||
if (emailSent)
|
||||
bool allEmailsSent = true;
|
||||
foreach (var email in emailList)
|
||||
{
|
||||
// Email sent successfully
|
||||
// You can redirect to a success page or return a success message
|
||||
TempData["Success"] = "Questionnaire sent successfully";
|
||||
return RedirectToAction(nameof(Index));
|
||||
var userName = email.Substring(0, email.IndexOf('@')); // This assumes the email is valid and contains an '@'
|
||||
userName = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(userName.Replace(".", " ")); // Optional: Improve formatting, replace dots and capitalize names
|
||||
var userEmailEncoded = HttpUtility.UrlEncode(email);
|
||||
var completeUrl = $"{Request.Scheme}://{Request.Host}/{questionnairePath}/{viewModel.QuestionnaireId}?t={tokenWithExpiry}&E={userEmailEncoded}";
|
||||
|
||||
string emailBody = $@"
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body {{ font-family: Arial, sans-serif; }}
|
||||
.container {{ max-width: 600px; margin: 0 auto; padding: 20px; border: 0.5px solid #ccc; border-radius: 5px; background-color: #f9f9f9; }}
|
||||
.button {{ display: inline-block; padding: 10px 20px; background-color: #007bff; color: #ffffff; text-decoration: none; border-radius: 4px; }}
|
||||
.button:hover {{ background-color: #0056b3; }}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class='container'>
|
||||
<h4>Hey {userName},</h4>
|
||||
<h5>{subject}</h5>
|
||||
<p>Thank you for participating in our survey. Your feedback is valuable to us.</p>
|
||||
<p>Please click the button below to start the survey:</p>
|
||||
<p class='text-danger'>The survey will expire: {expiryDateTime.ToLongDateString()} Time: {expiryDateTime.ToShortTimeString()}</p>
|
||||
<div style='text-align: center;'>
|
||||
<a href='{completeUrl}' class='button'>Start Survey</a>
|
||||
</div><br>
|
||||
<p><strong>Søren Eggert Lundsteen Olsen</strong><br>
|
||||
Seosoft ApS<br>
|
||||
<hr>
|
||||
Hovedgaden 3 Jordrup<br>
|
||||
Kolding 6064<br>
|
||||
Denmark</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>";
|
||||
|
||||
var emailSend = new EmailToSend(email, subject, emailBody);
|
||||
bool emailSent = await _emailServices.SendConfirmationEmailAsync(emailSend);
|
||||
if (!emailSent)
|
||||
{
|
||||
allEmailsSent = false;
|
||||
ModelState.AddModelError(string.Empty, "Failed to send questionnaire via email to: " + email);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
|
||||
if (allEmailsSent)
|
||||
{
|
||||
// Email failed to send
|
||||
// You can return an error message or handle it as needed
|
||||
ModelState.AddModelError(string.Empty, "Failed to send questionnaire via email.");
|
||||
TempData["Success"] = "Questionnaire sent successfully to all recipients.";
|
||||
return RedirectToAction(nameof(Index));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ using Microsoft.AspNetCore.Mvc;
|
|||
using Microsoft.EntityFrameworkCore;
|
||||
using Model;
|
||||
using Web.ViewModel.QuestionnaireVM;
|
||||
using Web.ViewModel.QuestionVM;
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace Web.Areas.Admin.Controllers
|
||||
{
|
||||
|
|
@ -109,6 +110,35 @@ namespace Web.Areas.Admin.Controllers
|
|||
|
||||
}
|
||||
|
||||
//[HttpGet]
|
||||
//public IActionResult GenerateReport(int id)
|
||||
//{
|
||||
// var viewModel = GetQuestionnaireData(id);
|
||||
// if (viewModel == null)
|
||||
// {
|
||||
// return NotFound("No questionnaire found with the given ID.");
|
||||
// }
|
||||
|
||||
// var webReport = new WebReport();
|
||||
|
||||
// // Load your FastReport report design
|
||||
// webReport.Report.Load(Path.Combine(env.WebRootPath, "Reports", "QuestionnaireReport.frx"));
|
||||
|
||||
// // Register the data source
|
||||
// webReport.Report.RegisterData(new[] { viewModel }, "Questionnaire");
|
||||
|
||||
// webReport.Report.Prepare();
|
||||
|
||||
// using (MemoryStream ms = new MemoryStream())
|
||||
// {
|
||||
// webReport.Report.Export(new FastReport.Export.PdfSimple.PDFSimpleExport(), ms);
|
||||
// return File(ms.ToArray(), "application/pdf", "QuestionnaireReport.pdf");
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,16 +20,13 @@
|
|||
<span asp-validation-for="QuestionnaireId" class="text-danger"></span>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label asp-for="Name" class="control-label"></label>
|
||||
<input asp-for="Name" class="form-control" />
|
||||
<span asp-validation-for="Name" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Email" class="control-label"></label>
|
||||
<input asp-for="Email" class="form-control" />
|
||||
<span asp-validation-for="Email" class="text-danger"></span>
|
||||
<label asp-for="Emails" class="control-label">Email Addresses (separate with commas)</label>
|
||||
<textarea asp-for="Emails" class="form-control"></textarea>
|
||||
<span asp-validation-for="Emails" class="text-danger"></span>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label asp-for="ExpirationDateTime" class="control-label"></label>
|
||||
<input asp-for="ExpirationDateTime" class="form-control"/>
|
||||
|
|
|
|||
|
|
@ -110,6 +110,70 @@
|
|||
|
||||
</div>
|
||||
|
||||
@* @section Scripts {
|
||||
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
|
||||
<script type="text/javascript">
|
||||
google.charts.load('current', { 'packages': ['corechart', 'bar','line','table'] }); // Ensure 'bar' package is loaded if using BarChart
|
||||
google.charts.setOnLoadCallback(drawCharts);
|
||||
|
||||
function drawCharts() {
|
||||
@foreach (var question in Model.Questions.Select((value, index) => new { Value = value, Index = index }))
|
||||
{
|
||||
<text>
|
||||
var type = '@question.Value.Type.ToString()';
|
||||
console.log('Type:', type); // Debug output to check type
|
||||
var chartContainer = document.getElementById('chart_div_@question.Value.Id');
|
||||
var chart; // Declare chart variable here for scope
|
||||
|
||||
var data = new google.visualization.DataTable();
|
||||
data.addColumn('string', 'Option');
|
||||
data.addColumn('number', 'Count');
|
||||
|
||||
</text>
|
||||
if (question.Value.Type == QuestionType.Text || question.Value.Type == QuestionType.Slider || question.Value.Type == QuestionType.Open_ended)
|
||||
{
|
||||
<text>
|
||||
console.log('Initializing Bar Chart'); // Debug output
|
||||
</text>
|
||||
@foreach (var item in question.Value.SelectedText)
|
||||
{
|
||||
<text>
|
||||
data.addRow(['@Html.Raw(item)', @question.Value.Answers]);
|
||||
</text>
|
||||
}
|
||||
<text>
|
||||
chart = new google.visualization.Table(chartContainer);
|
||||
</text>
|
||||
} else {
|
||||
<text>
|
||||
console.log('Initializing Pie Chart'); // Debug output
|
||||
</text>
|
||||
@foreach (var answer in question.Value.Answers)
|
||||
{
|
||||
<text>
|
||||
data.addRow(['@Html.Raw(answer.Text)', @answer.Count]);
|
||||
</text>
|
||||
}
|
||||
<text>
|
||||
chart = new google.visualization.PieChart(chartContainer);
|
||||
</text>
|
||||
}
|
||||
<text>
|
||||
var options = {
|
||||
'title': 'Question @(question.Index + 1): @Html.Raw(question.Value.Text)',
|
||||
is3D: type !== "Text" && type !== "Slider" && type !== "Open_ended", // Only use 3D for Pie Charts
|
||||
'titleTextStyle': { color: '#17a2b8', fontSize: 12, bold: true },
|
||||
'colors': ['#cc0000', '#00cc00', '#0000cc', '#cccc00', '#00cccc', '#cc00cc', '#008080', '#808000', '#800080', '#800000', '#808080', '#404040']
|
||||
};
|
||||
|
||||
chart.draw(data, options); // Draw chart outside conditional blocks
|
||||
</text>
|
||||
}
|
||||
}
|
||||
</script>
|
||||
}
|
||||
*@
|
||||
|
||||
@section Scripts {
|
||||
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
|
@ -152,7 +216,13 @@
|
|||
data.addRow(['@Html.Raw(item)', 1]);
|
||||
</text>
|
||||
}
|
||||
<text>
|
||||
// Initialize Bar Chart for Text, Slider, or Open-ended questions
|
||||
var chart = new google.visualization.BarChart(chartContainer);
|
||||
</text>
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
@foreach (var answer in question.Value.Answers)
|
||||
|
|
@ -167,7 +237,9 @@
|
|||
'title': 'Question @(question.Index + 1): @Html.Raw(question.Value.Text)',
|
||||
is3D: true,
|
||||
'titleTextStyle': { color: '#17a2b8', fontSize: 12, bold: true },
|
||||
'colors': colors
|
||||
'colors': colors,
|
||||
'pieSliceText': 'percentage', // Display percentages on the chart slices
|
||||
'tooltip': { text: 'percentage' } // Configure tooltip to show percentage
|
||||
};
|
||||
|
||||
if (chartContainer) {
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@ namespace Web.ViewModel.QuestionnaireVM
|
|||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
|
||||
|
||||
[Required]
|
||||
public string? Name { get; set; }
|
||||
[Required]
|
||||
public string? Email { get; set; }
|
||||
public string? Emails { get; set; }
|
||||
|
||||
[Required]
|
||||
[DisplayName("Set expiration date and time for the URL")]
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.2" />
|
||||
<PackageReference Include="OpenAI" Version="1.11.0" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="8.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue