mirror of
https://github.com/GCMatters/hermes.git
synced 2026-02-04 05:30:13 +01:00
Merge branch 'ChangingFromControllerToEndpoints' into maksCSS
This commit is contained in:
@@ -1,89 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using System.Reflection.Metadata;
|
|
||||||
using WebApp.Data;
|
|
||||||
using WebApp.Entities;
|
|
||||||
|
|
||||||
namespace WebApp.Controllers.Api
|
|
||||||
{
|
|
||||||
[ApiController]
|
|
||||||
[Route("api/events")]
|
|
||||||
public class EventsApiController : ControllerBase
|
|
||||||
{
|
|
||||||
private readonly ApplicationDbContext _context;
|
|
||||||
|
|
||||||
public EventsApiController(ApplicationDbContext context)
|
|
||||||
{
|
|
||||||
_context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
// GET: /api/events
|
|
||||||
[HttpGet]
|
|
||||||
public IActionResult GetAll()
|
|
||||||
{
|
|
||||||
var events = _context.Events.ToList();
|
|
||||||
return Ok(events);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GET: /api/events/5
|
|
||||||
[HttpGet("{id}")]
|
|
||||||
public IActionResult GetById(int id)
|
|
||||||
{
|
|
||||||
var ev = _context.Events.Find(id);
|
|
||||||
if (ev == null)
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
return Ok(ev);
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST: /api/events
|
|
||||||
[HttpPost]
|
|
||||||
public IActionResult Create([FromBody] Event ev)
|
|
||||||
{
|
|
||||||
if (!ModelState.IsValid)
|
|
||||||
return BadRequest(ModelState);
|
|
||||||
|
|
||||||
ev.EventDate = DateTime.SpecifyKind(ev.EventDate, DateTimeKind.Utc);
|
|
||||||
|
|
||||||
_context.Events.Add(ev);
|
|
||||||
_context.SaveChanges();
|
|
||||||
|
|
||||||
return CreatedAtAction(nameof(GetById), new { id = ev.EventId }, ev);
|
|
||||||
}
|
|
||||||
|
|
||||||
// PUT: /api/events/5
|
|
||||||
[HttpPut("{id}")]
|
|
||||||
public IActionResult Update(int id, [FromBody] Event updated)
|
|
||||||
{
|
|
||||||
if (id != updated.EventId)
|
|
||||||
return BadRequest("ID w URL nie zgadza się z obiektem.");
|
|
||||||
|
|
||||||
var ev = _context.Events.Find(id);
|
|
||||||
if (ev == null)
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
ev.Title = updated.Title;
|
|
||||||
ev.Description = updated.Description;
|
|
||||||
ev.Location = updated.Location;
|
|
||||||
ev.EventDate = updated.EventDate;
|
|
||||||
ev.OrganisationId = updated.OrganisationId;
|
|
||||||
|
|
||||||
_context.SaveChanges();
|
|
||||||
return NoContent();
|
|
||||||
}
|
|
||||||
|
|
||||||
// DELETE: /api/events/5
|
|
||||||
[HttpDelete("{id}")]
|
|
||||||
public IActionResult Delete(int id)
|
|
||||||
{
|
|
||||||
var ev = _context.Events.Find(id);
|
|
||||||
if (ev == null)
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
_context.Events.Remove(ev);
|
|
||||||
_context.SaveChanges();
|
|
||||||
|
|
||||||
return NoContent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
15
WebApp/DTOs/EventCreateDto.cs
Normal file
15
WebApp/DTOs/EventCreateDto.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using WebApp.Entities;
|
||||||
|
|
||||||
|
namespace WebApp.DTOs;
|
||||||
|
|
||||||
|
// Input values in JSON file to create event
|
||||||
|
public record class EventCreateDto
|
||||||
|
(
|
||||||
|
[Required] int? OrganisationId,
|
||||||
|
[Required][StringLength(50)] string Title,
|
||||||
|
[StringLength(500)] string Description,
|
||||||
|
[Required][StringLength(100)] string Location,
|
||||||
|
[Required] DateTime? EventDate,
|
||||||
|
ICollection<EventSkill> EventSkills
|
||||||
|
);
|
||||||
17
WebApp/DTOs/EventDetailsDto.cs
Normal file
17
WebApp/DTOs/EventDetailsDto.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using WebApp.Entities;
|
||||||
|
|
||||||
|
namespace WebApp.DTOs;
|
||||||
|
|
||||||
|
// Output values in JSON file
|
||||||
|
public record class EventDetailsDto
|
||||||
|
(
|
||||||
|
int EventId,
|
||||||
|
[Required] int? OrganisationId,
|
||||||
|
[Required][StringLength(50)] string Title,
|
||||||
|
[StringLength(500)] string Description,
|
||||||
|
[Required][StringLength(100)] string Location,
|
||||||
|
[Required] DateTime? EventDate,
|
||||||
|
ICollection<EventSkill> EventSkills,
|
||||||
|
ICollection<EventRegistration> EventRegistrations
|
||||||
|
);
|
||||||
16
WebApp/DTOs/EventSummaryDto.cs
Normal file
16
WebApp/DTOs/EventSummaryDto.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using WebApp.Entities;
|
||||||
|
|
||||||
|
namespace WebApp.DTOs;
|
||||||
|
|
||||||
|
// Output values in JSON file
|
||||||
|
public record class EventSummaryDto(
|
||||||
|
int EventId,
|
||||||
|
[Required] string Organisation,
|
||||||
|
[Required] [StringLength(50)] string Title,
|
||||||
|
[StringLength(500)] string Description,
|
||||||
|
[Required] [StringLength(100)] string Location,
|
||||||
|
[Required] DateTime? EventDate,
|
||||||
|
ICollection<EventSkill> EventSkills,
|
||||||
|
ICollection<EventRegistration> EventRegistrations
|
||||||
|
);
|
||||||
15
WebApp/DTOs/EventUpdateDto.cs
Normal file
15
WebApp/DTOs/EventUpdateDto.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using WebApp.Entities;
|
||||||
|
|
||||||
|
namespace WebApp.DTOs;
|
||||||
|
|
||||||
|
// Input values in JSON file to update event
|
||||||
|
public record class EventUpdateDto
|
||||||
|
(
|
||||||
|
[Required] int? OrganisationId,
|
||||||
|
[Required][StringLength(50)] string Title,
|
||||||
|
[StringLength(500)] string Description,
|
||||||
|
[Required][StringLength(100)] string Location,
|
||||||
|
[Required] DateTime? EventDate,
|
||||||
|
ICollection<EventSkill> EventSkills
|
||||||
|
);
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using WebApp.Entities;
|
|
||||||
|
|
||||||
namespace WebApp.DTOs;
|
|
||||||
public record class EventsDto(
|
|
||||||
int EventId,
|
|
||||||
int OrganisationId, //foreign key
|
|
||||||
[StringLength(200)] string Title,
|
|
||||||
[StringLength(800)] string Description,
|
|
||||||
[StringLength(100)] string Location,
|
|
||||||
DateTime EventDate,
|
|
||||||
Organisation? Organisation,
|
|
||||||
ICollection<EventSkill> EventSkills,
|
|
||||||
ICollection<EventRegistration> EventRegistrations
|
|
||||||
);
|
|
||||||
124
WebApp/Endpoints/EventsEndpoints.cs
Normal file
124
WebApp/Endpoints/EventsEndpoints.cs
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using WebApp.Data;
|
||||||
|
using WebApp.DTOs;
|
||||||
|
using WebApp.Entities;
|
||||||
|
using WebApp.Mapping;
|
||||||
|
|
||||||
|
namespace WebApp.Endpoints
|
||||||
|
{
|
||||||
|
public static class EventsEndpoints
|
||||||
|
{
|
||||||
|
const string GetEventEndpointName = "GetEvent";
|
||||||
|
|
||||||
|
public static RouteGroupBuilder MapEventsEndpoints(this WebApplication app)
|
||||||
|
{
|
||||||
|
var group = app.MapGroup("api/events")
|
||||||
|
.WithParameterValidation();
|
||||||
|
|
||||||
|
// GET /events
|
||||||
|
group.MapGet("/", async (ApplicationDbContext dbContext) =>
|
||||||
|
await dbContext.Events
|
||||||
|
.Include(Eve => Eve.Organisation)
|
||||||
|
.OrderByDescending(Eve => Eve.EventId)
|
||||||
|
.Select(Eve => Eve.ToEventSummaryDto()) //EventSummaryDto
|
||||||
|
.AsNoTracking()
|
||||||
|
.ToListAsync());
|
||||||
|
|
||||||
|
// GET /events/1
|
||||||
|
group.MapGet("/{id}", async (int id, ApplicationDbContext dbContext) =>
|
||||||
|
{
|
||||||
|
Event? Eve = await dbContext.Events.FindAsync(id);
|
||||||
|
|
||||||
|
if (Eve is null) return Results.NotFound();
|
||||||
|
|
||||||
|
// Sprawdź, czy token należy do organizacji, a jeżeli tak, to do której.
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// Jeśli token należy do organizacji, która utworzyła to wydarzenie,
|
||||||
|
// to zwróć także EventRegistrations. W przeciwnym razie usuń to pole
|
||||||
|
// przed jego wysłaniem!
|
||||||
|
// ...
|
||||||
|
|
||||||
|
return Results.Ok(Eve.ToEventDetailsDto()); //EventDetailsDto
|
||||||
|
})
|
||||||
|
.WithName(GetEventEndpointName);
|
||||||
|
|
||||||
|
// POST /events
|
||||||
|
group.MapPost("/", async (EventCreateDto newEvent, ApplicationDbContext dbContext) =>
|
||||||
|
{
|
||||||
|
|
||||||
|
// Uzyskaj organizację z tokenu
|
||||||
|
// ...
|
||||||
|
|
||||||
|
Event Eve = newEvent.ToEntity();
|
||||||
|
|
||||||
|
// Wyzeruj EventRegistrations, ponieważ nie są to dane,
|
||||||
|
// które powinniśmy przyjmować bez zgody wolontariuszy!
|
||||||
|
// ...
|
||||||
|
|
||||||
|
dbContext.Events.Add(Eve);
|
||||||
|
await dbContext.SaveChangesAsync();
|
||||||
|
|
||||||
|
return Results.CreatedAtRoute(
|
||||||
|
GetEventEndpointName,
|
||||||
|
new { id = Eve.EventId },
|
||||||
|
Eve.ToEventDetailsDto()); //EventDetailsDto
|
||||||
|
});
|
||||||
|
|
||||||
|
// PUT /events/1
|
||||||
|
group.MapPut("/{id}", async (int id, EventUpdateDto updatedEvent, ApplicationDbContext dbContext) =>
|
||||||
|
{
|
||||||
|
var existingEvent = await dbContext.Events.FindAsync(id);
|
||||||
|
|
||||||
|
if (existingEvent is null)
|
||||||
|
{
|
||||||
|
return Results.NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uzyskaj organizację z tokenu
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// Sprawdź, czy organizacja ma prawo
|
||||||
|
// do zmodyfikowania tego (EventId = id) eventu.
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// Nadpisz organisationId (obecne w updatedEvent,
|
||||||
|
// lecz nie sprawdzane poniżej) na to, co odczytaliśmy
|
||||||
|
// do existingEvent.
|
||||||
|
// ...
|
||||||
|
|
||||||
|
dbContext.Entry(existingEvent)
|
||||||
|
.CurrentValues
|
||||||
|
.SetValues(updatedEvent.ToEntity(id));
|
||||||
|
|
||||||
|
dbContext.Entry(existingEvent)
|
||||||
|
.Collection(Eve => Eve.EventRegistrations)
|
||||||
|
.IsModified = false;
|
||||||
|
|
||||||
|
await dbContext.SaveChangesAsync();
|
||||||
|
|
||||||
|
return Results.NoContent();
|
||||||
|
});
|
||||||
|
|
||||||
|
// DELETE /events/1
|
||||||
|
group.MapDelete("/{id}", async (int id, ApplicationDbContext dbContext) =>
|
||||||
|
{
|
||||||
|
|
||||||
|
// Uzyskaj organizację z tokenu
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// Sprawdź, czy organizacja ma prawo
|
||||||
|
// do usunięcia tego (EventId = id) eventu.
|
||||||
|
// ...
|
||||||
|
|
||||||
|
await dbContext.Events
|
||||||
|
.Where(Eve => Eve.EventId == id)
|
||||||
|
.ExecuteDeleteAsync();
|
||||||
|
|
||||||
|
return Results.NoContent();
|
||||||
|
});
|
||||||
|
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
64
WebApp/Mapping/EventMapping.cs
Normal file
64
WebApp/Mapping/EventMapping.cs
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using WebApp.DTOs;
|
||||||
|
using WebApp.Entities;
|
||||||
|
|
||||||
|
namespace WebApp.Mapping;
|
||||||
|
|
||||||
|
public static class EventMapping
|
||||||
|
{
|
||||||
|
public static Event ToEntity(this EventCreateDto ECDto)
|
||||||
|
{
|
||||||
|
return new Event()
|
||||||
|
{
|
||||||
|
OrganisationId = ECDto.OrganisationId!.Value,
|
||||||
|
Title = ECDto.Title,
|
||||||
|
Description = ECDto.Description,
|
||||||
|
Location = ECDto.Location,
|
||||||
|
EventDate = DateTime.SpecifyKind(ECDto.EventDate!.Value, DateTimeKind.Utc),
|
||||||
|
EventSkills = ECDto.EventSkills,
|
||||||
|
EventRegistrations = []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Event ToEntity(this EventUpdateDto EUDto, int id)
|
||||||
|
{
|
||||||
|
return new Event()
|
||||||
|
{
|
||||||
|
EventId = id,
|
||||||
|
OrganisationId = EUDto.OrganisationId!.Value,
|
||||||
|
Title = EUDto.Title,
|
||||||
|
Description = EUDto.Description,
|
||||||
|
Location = EUDto.Location,
|
||||||
|
EventDate = DateTime.SpecifyKind(EUDto.EventDate!.Value, DateTimeKind.Utc),
|
||||||
|
EventSkills = EUDto.EventSkills
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EventSummaryDto ToEventSummaryDto(this Event myEvent)
|
||||||
|
{
|
||||||
|
return new EventSummaryDto(
|
||||||
|
myEvent.EventId,
|
||||||
|
myEvent.Organisation!.Name,
|
||||||
|
myEvent.Title,
|
||||||
|
myEvent.Description,
|
||||||
|
myEvent.Location,
|
||||||
|
myEvent.EventDate,
|
||||||
|
myEvent.EventSkills,
|
||||||
|
myEvent.EventRegistrations
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EventDetailsDto ToEventDetailsDto(this Event myEvent)
|
||||||
|
{
|
||||||
|
return new EventDetailsDto(
|
||||||
|
myEvent.EventId,
|
||||||
|
myEvent.OrganisationId,
|
||||||
|
myEvent.Title,
|
||||||
|
myEvent.Description,
|
||||||
|
myEvent.Location,
|
||||||
|
myEvent.EventDate,
|
||||||
|
myEvent.EventSkills,
|
||||||
|
myEvent.EventRegistrations
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,45 +1,54 @@
|
|||||||
using Microsoft.AspNetCore.Identity;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using WebApp.Data;
|
using WebApp.Data;
|
||||||
|
using WebApp.Endpoints;
|
||||||
using WebApp.Entities;
|
using WebApp.Entities;
|
||||||
|
|
||||||
|
// Create WebAppliaction Builder
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
// Add services to the container.
|
// Configure Database Conecction
|
||||||
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
|
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
|
||||||
builder.Services.AddDbContext<ApplicationDbContext>(options =>
|
builder.Services.AddDbContext<ApplicationDbContext>(options =>
|
||||||
options.UseNpgsql(connectionString));
|
options.UseNpgsql(connectionString));
|
||||||
|
|
||||||
|
// Add Developer Exception Filter
|
||||||
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
|
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
|
||||||
|
|
||||||
|
// Configure Identity
|
||||||
builder.Services.AddDefaultIdentity<User>(options => options.SignIn.RequireConfirmedAccount = true)
|
builder.Services.AddDefaultIdentity<User>(options => options.SignIn.RequireConfirmedAccount = true)
|
||||||
.AddEntityFrameworkStores<ApplicationDbContext>();
|
.AddEntityFrameworkStores<ApplicationDbContext>();
|
||||||
builder.Services.AddControllersWithViews();
|
|
||||||
|
|
||||||
|
// API Services For Swagger
|
||||||
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
|
builder.Services.AddSwaggerGen(c =>
|
||||||
|
{
|
||||||
|
c.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo { Title = "hermes", Version = "v1" });
|
||||||
|
});
|
||||||
|
|
||||||
|
// Build Application
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
// Configure the HTTP request pipeline.
|
||||||
if (app.Environment.IsDevelopment())
|
if (app.Environment.IsDevelopment())
|
||||||
{
|
{
|
||||||
app.UseMigrationsEndPoint();
|
app.UseMigrationsEndPoint();
|
||||||
|
app.UseSwagger();
|
||||||
|
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "hermes v1"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
app.UseExceptionHandler("/Home/Error");
|
|
||||||
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
|
||||||
app.UseHsts();
|
app.UseHsts();
|
||||||
}
|
}
|
||||||
|
|
||||||
app.UseHttpsRedirection();
|
// Middleware Configuration
|
||||||
app.UseDefaultFiles();
|
app.UseHttpsRedirection(); // Redirects all HTTP requests to HTTPS
|
||||||
app.UseStaticFiles();
|
app.UseDefaultFiles(); // Serves default files (index.html) if no specific file is requested
|
||||||
|
app.UseStaticFiles(); // Serves static files(CSS, JS, Img) from the wwwroot folder.
|
||||||
app.UseRouting();
|
app.UseRouting(); // Enables routing to match incoming request to endpoints
|
||||||
|
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
app.MapControllerRoute(
|
// Map Minimal API Endpoints
|
||||||
name: "default",
|
app.MapEventsEndpoints();
|
||||||
pattern: "{controller=Home}/{action=Index}/{id?}");
|
|
||||||
app.MapRazorPages();
|
|
||||||
|
|
||||||
app.Run();
|
app.Run();
|
||||||
|
|||||||
@@ -21,8 +21,14 @@
|
|||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.OpenApi" Version="1.6.24" />
|
||||||
|
<PackageReference Include="MinimalApis.Extensions" Version="0.11.0" />
|
||||||
<PackageReference Include="Npgsql" Version="9.0.3" />
|
<PackageReference Include="Npgsql" Version="9.0.3" />
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.1" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="8.1.1" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="8.1.1" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="8.1.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
Reference in New Issue
Block a user