Skip to content
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
2 changes: 2 additions & 0 deletions HealthCareABApi/HealthCareABApi.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@
<PropertyGroup Condition=" '$(RunConfiguration)' == 'https' " />
<PropertyGroup Condition=" '$(RunConfiguration)' == 'http' " />
<ItemGroup>
<PackageReference Include="MailKit" Version="4.9.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="MimeKit" Version="4.9.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.10" />
Expand Down
12 changes: 12 additions & 0 deletions HealthCareABApi/Models/SmtpSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace HealthCareABApi.Models
{
public class SmtpSettings
{
public string Server { get; set; }
public int Port { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string FromName { get; set; }
public string FromEmail { get; set; }
}
}
5 changes: 5 additions & 0 deletions HealthCareABApi/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@
using Microsoft.EntityFrameworkCore;
using HealthCareABApi.Repositories.Interfaces;
using HealthCareABApi.BackgroundJobs;
using HealthCareABApi.Models;
using Microsoft.Extensions.Configuration;

var builder = WebApplication.CreateBuilder(args);

// Register DbContext
builder.Services.AddDbContext<HealthCareDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

builder.Services.Configure<SmtpSettings>(builder.Configuration.GetSection("SmtpSettings"));

// Register repositories
builder.Services.AddScoped<IAppointmentRepository, AppointmentRepository>();
builder.Services.AddScoped<IAppointmentService, AppointmentService>();
Expand All @@ -26,6 +30,7 @@
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddScoped<IJwtTokenService, JwtTokenService>();
builder.Services.AddScoped<IFeedbackService, FeedbackService>();
builder.Services.AddScoped<IEmailService, EmailService>();

// Register background jobs
builder.Services.AddHostedService<CleanupSlotsService>();
Expand Down
221 changes: 142 additions & 79 deletions HealthCareABApi/Repositories/Implementations/AppointmentRepository.cs
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
using System;
using HealthCareABApi.Models;
using HealthCareABApi.Repositories.Data;
using Microsoft.EntityFrameworkCore;

namespace HealthCareABApi.Repositories.Implementations
{
public class AppointmentRepository : IAppointmentRepository
{
private readonly HealthCareDbContext _Dbcontext;

public AppointmentRepository(HealthCareDbContext context)
{
_Dbcontext = context;
}

public async Task<IEnumerable<Appointment>> GetAllAsync()
{
return await _Dbcontext.Appointment
.Include(a => a.Patient)
.Include(a => a.Caregiver)
.ToListAsync();
using System;
using HealthCareABApi.Models;
using HealthCareABApi.Repositories.Data;
using HealthCareABApi.Repositories.Interfaces;
using Microsoft.EntityFrameworkCore;

namespace HealthCareABApi.Repositories.Implementations
{
public class AppointmentRepository : IAppointmentRepository
{
private readonly HealthCareDbContext _Dbcontext;
private readonly IEmailService _emailService;

public AppointmentRepository(HealthCareDbContext context, IEmailService emailService)
{
_Dbcontext = context;
_emailService = emailService;
}

public async Task<IEnumerable<Appointment>> GetAllAsync()
{
return await _Dbcontext.Appointment
.Include(a => a.Patient)
.Include(a => a.Caregiver)
.ToListAsync();
}

public async Task<Appointment> GetByIdAsync(int id)
Expand All @@ -39,76 +42,136 @@ public async Task<Appointment> GetByPatientAndTimeAsync(int patientId, DateTime
a.PatientId == patientId &&
EF.Functions.DateDiffSecond(a.DateTime, localTime) == 0 && // Ignorerar millisekunder i databasen och kollar tiden på sekundnivå
a.Status == AppointmentStatus.Scheduled);
}
}

public async Task<IEnumerable<Appointment>> GetCompletedByUserIdAsync(int userId)
{
return await _Dbcontext.Appointment
.Include(x => x.Caregiver)
.Include(x => x.Patient)
{
return await _Dbcontext.Appointment
.Include(x => x.Caregiver)
.Include(x => x.Patient)
.Where(x => x.PatientId == userId && x.Status == AppointmentStatus.Completed)
.ToListAsync();
}
.ToListAsync();
}

public async Task CreateAsync(Appointment appointment)
{
if (appointment == null)
{
throw new ArgumentNullException(nameof(appointment), "Appointment is null and will blow up the system in 3........2........1.........");
}

try
{
var availability = await _Dbcontext.Availability
.FirstOrDefaultAsync(a =>
a.Caregiver.Id == appointment.CaregiverId &&
a.StartTime <= appointment.DateTime &&
a.EndTime > appointment.DateTime &&
!a.IsBooked);

var patient = await _Dbcontext.User.Where(x => x.Id == appointment.PatientId).FirstOrDefaultAsync();
var careGiver = await _Dbcontext.User.Where(x => x.Id == appointment.CaregiverId).FirstOrDefaultAsync();

if (availability == null)
{
throw new InvalidOperationException("No available slot for this time.");
}

availability.IsBooked = true;
availability.Appointment = appointment;

await _Dbcontext.Appointment.AddAsync(appointment);

await _Dbcontext.SaveChangesAsync();
//await _Dbcontext.Appointment.AddAsync(appointment);
//await _Dbcontext.SaveChangesAsync();

var body = $@"
Hello {appointment.Patient.Firstname},

Your appointment has been successfully scheduled:

Patient Name: {patient.Firstname} {patient.Lastname}
Appointment Time: {appointment.DateTime.ToString("f")}
Caregiver: {careGiver.Firstname} {careGiver.Lastname}

If you have any questions, please contact us at support@healthCareAbExample.com

The Healthcare AB Team
";


await _emailService.SendEmailAsync(patient.Email, "Appointment Booked", body, $"{patient.Firstname} {patient.Lastname}");

}
catch (DbUpdateException ex)
{
throw new InvalidOperationException("Database error while creating appointment", ex);
}
catch (Exception ex)
{
throw new InvalidOperationException("Error creating new appointment", ex);
}
}

public async Task<bool> UpdateAsync(int id, Appointment appointment)
{
var exist = await _Dbcontext.Appointment.Where(a => a.Id == id).Include(x => x.Patient).Include(x => x.Caregiver).FirstOrDefaultAsync();

if (exist == null)
{
return false;
}


_Dbcontext.Appointment.Entry(exist).CurrentValues.SetValues(appointment);
await _Dbcontext.SaveChangesAsync();

var body = $@"
Hello {appointment.Patient.Firstname},

public async Task CreateAsync(Appointment appointment)
{
if (appointment == null)
{
throw new ArgumentNullException(nameof(appointment), "Appointment is null and will blow up the system in 3........2........1.........");
}
Your appointment has been successfully Updated:

try
{
var availability = await _Dbcontext.Availability
.FirstOrDefaultAsync(a =>
a.Caregiver.Id == appointment.CaregiverId &&
a.StartTime <= appointment.DateTime &&
a.EndTime > appointment.DateTime &&
!a.IsBooked);
Patient Name: {appointment.Patient.Firstname} {appointment.Patient.Lastname}
Appointment Time: {appointment.DateTime.ToString("f")}
Caregiver: {appointment.Caregiver.Firstname} {appointment.Caregiver.Lastname}

if (availability == null)
{
throw new InvalidOperationException("No available slot for this time.");
}
If you have any questions, please contact us at support@healthCareAbExample.com

availability.IsBooked = true;
availability.Appointment = appointment;
The Healthcare AB Team
";

await _Dbcontext.Appointment.AddAsync(appointment);

await _Dbcontext.SaveChangesAsync();
}
catch (DbUpdateException ex)
{
throw new InvalidOperationException("Database error while creating appointment", ex);
}
catch (Exception ex)
await _emailService.SendEmailAsync(appointment.Patient.Email, "Appointment Updated", body, $"{appointment.Patient.Firstname} {appointment.Patient.Lastname}");

return true;
}

public async Task DeleteAsync(int id)
{
using (var transaction = await _Dbcontext.Database.BeginTransactionAsync())
{
throw new InvalidOperationException("Error creating new appointment", ex);
}
}

public async Task<bool> UpdateAsync(int id, Appointment appointment)
{
var exist = await _Dbcontext.Appointment.Where(a => a.Id == id).FirstOrDefaultAsync();
try
{
var appointment = await _Dbcontext.Appointment.Where(x => x.Id == id).Include(x => x.Patient).Include(x => x.Caregiver).FirstOrDefaultAsync();

if (exist == null)
{
return false;
}
var body = $@"
Hello {appointment.Patient.Firstname},

_Dbcontext.Appointment.Entry(exist).CurrentValues.SetValues(appointment);
await _Dbcontext.SaveChangesAsync();
return true;
}
Your appointment have been deleted:

public async Task DeleteAsync(int id)
{
using (var transaction = await _Dbcontext.Database.BeginTransactionAsync())
{
Patient Name: {appointment.Patient.Firstname} {appointment.Patient.Lastname}
Appointment Time: {appointment.DateTime.ToString("f")}
Caregiver: {appointment.Caregiver.Firstname} {appointment.Caregiver.Lastname}

try
{
If you have any questions, please contact us at support@healthCareAbExample.com

The Healthcare AB Team
";

await _emailService.SendEmailAsync(appointment.Patient.Email, "Appointment Deleted", body, $"{appointment.Patient.Firstname} {appointment.Patient.Lastname}");

var relatedAvailability = await _Dbcontext.Availability
.Where(a => a.AppointmentId == id)
.FirstOrDefaultAsync();
Expand Down Expand Up @@ -161,4 +224,4 @@ public async Task<IEnumerable<Appointment>> GetScheduledAppointmentsAsync(int us
}
}
}

7 changes: 7 additions & 0 deletions HealthCareABApi/Repositories/Interfaces/IEmailService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace HealthCareABApi.Repositories.Interfaces
{
public interface IEmailService
{
Task SendEmailAsync(string toEmail, string subject, string body, string name);
}
}
1 change: 0 additions & 1 deletion HealthCareABApi/Services/AppointmentService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ public AppointmentService(IAppointmentRepository appointmentRepository, IAvailab
{
_appointmentRepository = appointmentRepository;
_availabilityRepository = availabilityRepository;

}

public async Task<AppointmentResponseDTO> CreateAsync(CreateAppointmentDTO dto)
Expand Down
6 changes: 4 additions & 2 deletions HealthCareABApi/Services/AvailabilityService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ namespace HealthCareABApi.Services
public class AvailabilityService : IAvailabilityService
{
private readonly IAvailabilityRepository _availabilityRepository;
private readonly IAppointmentRepository _appointmentRepository;
private readonly HealthCareDbContext _Dbcontext;

public AvailabilityService(IAvailabilityRepository availabilityRepository, HealthCareDbContext context)
public AvailabilityService(IAvailabilityRepository availabilityRepository, HealthCareDbContext context, IAppointmentRepository appointmentRepository)
{
_availabilityRepository = availabilityRepository;
_appointmentRepository = appointmentRepository;
_Dbcontext = context;
}

Expand Down Expand Up @@ -175,7 +177,7 @@ public async Task DeleteAsync(int id)

if (availability.AppointmentId.HasValue)
{
_Dbcontext.Appointment.Remove(availability.Appointment);
await _appointmentRepository.DeleteAsync(availability.AppointmentId.Value);
}

_Dbcontext.Availability.Remove(availability);
Expand Down
46 changes: 46 additions & 0 deletions HealthCareABApi/Services/EmailService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using MimeKit;
using MailKit.Security;
using Microsoft.Extensions.Options;
using HealthCareABApi.Repositories.Interfaces;
using MailKit.Net.Smtp;
using HealthCareABApi.Models;
namespace HealthCareABApi.Services
{
public class EmailService : IEmailService
{
private readonly SmtpSettings _smtpSettings;

public EmailService(IOptions<SmtpSettings> smtpSettings)
{
_smtpSettings = smtpSettings.Value;
}

public async Task SendEmailAsync(string toEmail, string subject, string body, string name)
{
var message = new MimeMessage();
message.From.Add(new MailboxAddress(_smtpSettings.FromName, _smtpSettings.FromEmail));
message.To.Add(new MailboxAddress(name, toEmail));
message.Subject = subject;

var bodyBuilder = new BodyBuilder
{
HtmlBody = body
};
message.Body = bodyBuilder.ToMessageBody();
try
{
using (var client = new SmtpClient())
{
await client.ConnectAsync(_smtpSettings.Server, _smtpSettings.Port, SecureSocketOptions.StartTls);
await client.AuthenticateAsync(_smtpSettings.Username, _smtpSettings.Password);
await client.SendAsync(message);
await client.DisconnectAsync(true);
}
}
catch (Exception ex)
{
throw new Exception($"Failed to send email: {ex.Message}", ex);
}
}
}
}
Loading