Skip to content

Commit

Permalink
Merge pull request #6 from lucasdaquina/feat/get-medications
Browse files Browse the repository at this point in the history
Feat/get-medications
  • Loading branch information
lucasdaquina authored Jul 26, 2024
2 parents b173e5c + 9a7b0bd commit add4a5c
Show file tree
Hide file tree
Showing 24 changed files with 199 additions and 85 deletions.
15 changes: 15 additions & 0 deletions Init.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#! /bin/bash

echo 'Assuming you have docker installed on your machine. If not, please install docker first.'

echo 'Pulling the latest version of SQL Server 2019 on Ubuntu 16.04 from Microsoft Container Registry (MCR)'
docker pull mcr.microsoft.com/mssql/server

echo 'Running the SQL Server 2019 container'
docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=Password123456" -p 1433:1433 -d mcr.microsoft.com/mssql/server:2019-latest

echo 'SQL Server 2019 container is running'

echo 'run the command "update-database" inside VisualStudio click Tools -> NuGet Package Manager -> Package Manager Console'
echo 'Select the "Default project" as "src\Application'

16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,18 @@
# sm-medication-api
SmartMed Back End code challenge


Steps to run api:

1. Clone the repository
2. Open the project in your favorite IDE (Visual Studio)
3. Open terminal/cmd and navigate to the solution folder
3. Run Init.sh with the command .\Init.sh to pull docker sql server image and run the container
4. After the sql server's running
- On VisualStudio click Tools -> NuGet Package Manager -> Package Manager Console
- Select the "Default project" as "src\Application"
- run the command dotnet ef database update --project .\src\SM.Medication.Infrastructure\SM.Medication.Infrastructure.csproj --startup-project .\src\SM.Medication.Api\SM.Medication.Api.csproj"

Now the Solution is ready, with a base SQL Server DB running with 3 medications on the medication table already.

PS: The token to call the API is "SmartMed eyAiVG9rZW4iOiAiMTIzIiwgIlJvbGUiOiAiQWRtaW4ifQ=="
20 changes: 20 additions & 0 deletions src/SM.Medication.Api/EndPoints/MedicationEndPoints.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace SM.Medication.Api.EndPoints;

public static class MedicationEndPoints
{
private const string MEDICATION_TAG = "Medication";
public static void MapMedicationEndPoints(this WebApplication app)
{
app.MapGet("/medications",
async (IMedicationHandler handler) =>
{
return await handler.Handle();
})
.WithTags(MEDICATION_TAG)
.WithMetadata(new SwaggerOperationAttribute(MEDICATION_TAG, "Get List of Medications"))
.WithMetadata(new SwaggerResponseAttribute(StatusCodes.Status200OK, "Success!"))
.WithMetadata(new SwaggerResponseAttribute(StatusCodes.Status401Unauthorized, "You're not Authorized!"))
.WithMetadata(new SwaggerResponseAttribute(StatusCodes.Status500InternalServerError, "Failed!"))
.RequireAuthorization(); ;
}
}
27 changes: 27 additions & 0 deletions src/SM.Medication.Api/Extensions/MapsterExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.Reflection;
using Mapster;
using MapsterMapper;

namespace SM.Medication.Api.Extensions;

public static class MapsterExtensions
{
public static void SetupMapster(this WebApplicationBuilder builder)
{
var typeAdapterConfig = TypeAdapterConfig.GlobalSettings;

// Scan the current assembly
typeAdapterConfig.Scan(Assembly.GetExecutingAssembly());

// Scan assemblies of referenced projects
var referencedAssemblies = Assembly.GetExecutingAssembly().GetReferencedAssemblies();
foreach (var assemblyName in referencedAssemblies)
{
var assembly = Assembly.Load(assemblyName);
typeAdapterConfig.Scan(assembly);
}

var mapperConfig = new Mapper(typeAdapterConfig);
builder.Services.AddSingleton<IMapper>(mapperConfig);
}
}
48 changes: 48 additions & 0 deletions src/SM.Medication.Api/Extensions/OpenAiExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using Microsoft.OpenApi.Models;

namespace SM.Medication.Api.Extensions;

public static class OpenAiExtensions
{
public static void SetupOpenApi(this WebApplicationBuilder builder)
{
var securityScheme = new OpenApiSecurityScheme()
{
Name = "Authorization",
Type = SecuritySchemeType.ApiKey,
Scheme = AuthSchemeConstants.SmartMedAuthScheme,
BearerFormat = "JWT",
In = ParameterLocation.Header,
Description = "JSON Web Token based security"
};

var securityRequirement = new OpenApiSecurityRequirement();
var secondSecurityDefinition = new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = AuthSchemeConstants.SmartMedAuthScheme
}
};
securityRequirement.Add(secondSecurityDefinition, []);

var info = new OpenApiInfo()
{
Version = "v1",
Title = "SmartMed Medication API",
Description = "Medication API service for any communication regard medicament.",
TermsOfService = new Uri("https://www.smartmed.world"),
};


builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(action =>
{
action.SwaggerDoc("v1", info);
action.AddSecurityDefinition(AuthSchemeConstants.SmartMedAuthScheme, securityScheme);
action.AddSecurityRequirement(securityRequirement);
action.EnableAnnotations();
});
}
}
47 changes: 6 additions & 41 deletions src/SM.Medication.Api/Extensions/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.OpenApi.Models;
using SM.Medication.Application.Handlers;
using SM.Medication.Domain.Interfaces;
using SM.Medication.Infrastructure.Services.Repositories;
using SM.Medication.Shared.Options;
using SmartMed.Medication.Auth.Constants;

namespace SM.Medication.Api.Extensions;

Expand All @@ -15,45 +16,9 @@ public static void AddOptions(this WebApplicationBuilder builder)
});
}

public static void SetupOpenApi(this IServiceCollection services)
public static void AddInterfaces(this WebApplicationBuilder builder)
{
var securityScheme = new OpenApiSecurityScheme()
{
Name = "Authorization",
Type = SecuritySchemeType.ApiKey,
Scheme = AuthSchemeConstants.SmartMedAuthScheme,
BearerFormat = "JWT",
In = ParameterLocation.Header,
Description = "JSON Web Token based security"
};

var securityRequirement = new OpenApiSecurityRequirement();
var secondSecurityDefinition = new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = AuthSchemeConstants.SmartMedAuthScheme
}
};
securityRequirement.Add(secondSecurityDefinition, []);

var info = new OpenApiInfo()
{
Version = "v1",
Title = "SmartMed Medication API",
Description = "Medication API service for any communication regard medicament.",
TermsOfService = new Uri("https://www.smartmed.world"),
};


services.AddEndpointsApiExplorer();
services.AddSwaggerGen(action =>
{
action.SwaggerDoc("v1", info);
action.AddSecurityDefinition(AuthSchemeConstants.SmartMedAuthScheme, securityScheme);
action.AddSecurityRequirement(securityRequirement);
action.EnableAnnotations();
});
builder.Services.AddScoped<IMedicationHandler, MedicationHandler>();
builder.Services.AddScoped<IMedicationRepository, MedicationRepository>();
}
}
3 changes: 3 additions & 0 deletions src/SM.Medication.Api/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
global using SM.Medication.Application.Interfaces;
global using SmartMed.Medication.Auth.Constants;
global using Swashbuckle.AspNetCore.Annotations;
39 changes: 6 additions & 33 deletions src/SM.Medication.Api/Program.cs
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
using Microsoft.AspNetCore.Localization;
using System.Globalization;
using Microsoft.EntityFrameworkCore;
using SM.Medication.Api.EndPoints;
using SM.Medication.Api.Extensions;
using SM.Medication.Auth;
using SM.Medication.Auth.Extensions;
using SM.Medication.Auth.Options;
using SM.Medication.Infrastructure.Persistence;
using SmartMed.Medication.Auth.Constants;
using Swashbuckle.AspNetCore.Annotations;

var builder = WebApplication.CreateBuilder(args);

builder.AddOptions();
builder.Services.AddCors(options => options.AddPolicy("allowAny", o => o.AllowAnyOrigin()));

builder.Services.SetupOpenApi();
builder.SetupOpenApi();

builder.Services.AddDbContext<SmartMedMedicationDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("MedicationDb")));
Expand All @@ -25,35 +22,11 @@

builder.Services.AddAuthorization();

var app = builder.Build();

//var supportedCultures = new[]
//{
// new CultureInfo("en-US"),
// new CultureInfo("fr"),
//};
//app.UseRequestLocalization(new RequestLocalizationOptions
//{
// DefaultRequestCulture = new RequestCulture("en-US"),
// // Formatting numbers, dates, etc.
// SupportedCultures = supportedCultures,
// // UI strings that we have localized.
// SupportedUICultures = supportedCultures
//});

app.MapGet("/", () => "Hello World!");

builder.AddInterfaces();
builder.SetupMapster();

app.MapGet("/medications", async (SmartMedMedicationDbContext dbContext) =>
{
var medications = await dbContext.Medications.ToListAsync();
return medications;
}).WithTags("Home")
.WithMetadata(new SwaggerOperationAttribute("Home", "Base Get Endpoint"))
.WithMetadata(new SwaggerResponseAttribute(StatusCodes.Status200OK, "Success!"))
.WithMetadata(new SwaggerResponseAttribute(StatusCodes.Status401Unauthorized, "You're not Authorized!"))
.WithMetadata(new SwaggerResponseAttribute(StatusCodes.Status500InternalServerError, "Failed!"))
.RequireAuthorization(); ;
var app = builder.Build();
app.MapMedicationEndPoints();

if (app.Environment.IsDevelopment())
{
Expand Down
1 change: 1 addition & 0 deletions src/SM.Medication.Application/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
global using SM.Medication.Domain.DTO;
16 changes: 16 additions & 0 deletions src/SM.Medication.Application/Handlers/MedicationHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using MapsterMapper;
using SM.Medication.Application.Interfaces;
using SM.Medication.Domain.Interfaces;

namespace SM.Medication.Application.Handlers;

public class MedicationHandler(
IMedicationRepository medicationRepository,
IMapper mapper) : IMedicationHandler
{
public async Task<List<MedicationDTO>> Handle()
{
var medications = await medicationRepository.GetAll();
return mapper.Map<List<MedicationDTO>>(medications);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace SM.Medication.Application.Interfaces;
public interface IMedicationHandler
{
Task<List<MedicationDTO>> Handle();
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Mapster" Version="7.4.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\SM.Medication.Domain\SM.Medication.Domain.csproj" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using Microsoft.AspNetCore.Http;
namespace SM.Medication.Auth.Extensions;

public static class SmartMedAuthExtensions
Expand Down
2 changes: 2 additions & 0 deletions src/SM.Medication.Auth/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
global using Microsoft.AspNetCore.Authentication;
global using Microsoft.AspNetCore.Http;
2 changes: 0 additions & 2 deletions src/SM.Medication.Auth/Options/SMAuthSchemeOptions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using Microsoft.AspNetCore.Authentication;

namespace SM.Medication.Auth.Options;
public class SMAuthSchemeOptions : AuthenticationSchemeOptions
{
Expand Down
2 changes: 0 additions & 2 deletions src/SM.Medication.Auth/SmartMedAuthenticationHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
Expand Down
3 changes: 1 addition & 2 deletions src/SM.Medication.Domain/Common/AuditableEntity.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using Microsoft.AspNetCore.Http;

namespace SM.Medication.Domain.Common;

public class AuditableEntity
{
public string? CreatedBy { get; set; }
Expand Down
7 changes: 7 additions & 0 deletions src/SM.Medication.Domain/DTO/MedicationDTO.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace SM.Medication.Domain.DTO;

public class MedicationDTO
{
public string? Name { get; set; }
public int Quantity { get; set; }
}
6 changes: 6 additions & 0 deletions src/SM.Medication.Domain/Interfaces/IMedicationRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace SM.Medication.Domain.Interfaces;

public interface IMedicationRepository
{
Task<List<Domain.Entities.Medication>> GetAll();
}
2 changes: 2 additions & 0 deletions src/SM.Medication.Infrastructure/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
global using Microsoft.EntityFrameworkCore;
global using Microsoft.EntityFrameworkCore.Infrastructure;
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace SM.Medication.Infrastructure.Mapping;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage;

namespace SM.Medication.Infrastructure.Persistence;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using SM.Medication.Domain.Interfaces;
using SM.Medication.Infrastructure.Persistence;

namespace SM.Medication.Infrastructure.Services.Repositories;

public class MedicationRepository(SmartMedMedicationDbContext context) : IMedicationRepository
{
public async Task<List<Domain.Entities.Medication>> GetAll()
{
return await context
.Medications
.ToListAsync();
}
}

0 comments on commit add4a5c

Please sign in to comment.