Added api endpoints and configured hopframe
This commit is contained in:
15
src/Portfolio.Api/Controller/AboutController.cs
Normal file
15
src/Portfolio.Api/Controller/AboutController.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Portfolio.Shared.Services;
|
||||
|
||||
namespace Portfolio.Api.Controller;
|
||||
|
||||
[ApiController, Route("api/about")]
|
||||
public class AboutController(IAboutRepository repository) : ControllerBase {
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAbout(CancellationToken ct) {
|
||||
var about = await repository.GetAbout(ct);
|
||||
return Ok(about);
|
||||
}
|
||||
|
||||
}
|
||||
15
src/Portfolio.Api/Controller/ProjectController.cs
Normal file
15
src/Portfolio.Api/Controller/ProjectController.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Portfolio.Shared.Services;
|
||||
|
||||
namespace Portfolio.Api.Controller;
|
||||
|
||||
[ApiController, Route("api/projects")]
|
||||
public class ProjectController(IProjectRepository repository) : ControllerBase {
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetProjects(CancellationToken ct) {
|
||||
var projects = await repository.GetProjects(ct);
|
||||
return Ok(projects);
|
||||
}
|
||||
|
||||
}
|
||||
15
src/Portfolio.Api/Controller/TechnologyController.cs
Normal file
15
src/Portfolio.Api/Controller/TechnologyController.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Portfolio.Shared.Services;
|
||||
|
||||
namespace Portfolio.Api.Controller;
|
||||
|
||||
[ApiController, Route("api/technologies")]
|
||||
public class TechnologyController(ITechnologyRepository repository) : ControllerBase {
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetTechnologies(CancellationToken ct) {
|
||||
var technologies = await repository.GetTechnologies(ct);
|
||||
return Ok(technologies);
|
||||
}
|
||||
|
||||
}
|
||||
16
src/Portfolio.Api/Controller/TimelineController.cs
Normal file
16
src/Portfolio.Api/Controller/TimelineController.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Portfolio.Shared.Models;
|
||||
using Portfolio.Shared.Services;
|
||||
|
||||
namespace Portfolio.Api.Controller;
|
||||
|
||||
[ApiController, Route("api/timeline")]
|
||||
public class TimelineController(ITimelineRepository repository) : ControllerBase {
|
||||
|
||||
[HttpGet("{type}")]
|
||||
public async Task<IActionResult> GetTimeline(TimelineEntryType type, CancellationToken ct) {
|
||||
var timeline = await repository.GetTimeline(type, ct);
|
||||
return Ok(timeline);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,7 +19,7 @@ public class DatabaseContext(DbContextOptions<DatabaseContext> options) : DbCont
|
||||
modelBuilder.Entity<Project>()
|
||||
.HasMany(p => p.Languages)
|
||||
.WithMany()
|
||||
.UsingEntity("ProjectLanguage");
|
||||
.UsingEntity("LanguageProject");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
using HopFrame.Core.Config;
|
||||
using HopFrame.Web;
|
||||
using Portfolio.Api;
|
||||
using Portfolio.Api.Services;
|
||||
using Portfolio.Shared.Models;
|
||||
using Portfolio.Shared.Services;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
@@ -8,11 +12,53 @@ var builder = WebApplication.CreateBuilder(args);
|
||||
builder.Services.AddOpenApi();
|
||||
builder.AddServiceDefaults();
|
||||
|
||||
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
|
||||
builder.AddNpgsqlDbContext<DatabaseContext>("data");
|
||||
|
||||
builder.Services.AddScoped<IProjectRepository, ProjectRepository>();
|
||||
builder.Services.AddScoped<ITechnologyRepository, TechnologyRepository>();
|
||||
builder.Services.AddScoped<ITimelineRepository, TimelineRepository>();
|
||||
builder.Services.AddScoped<IAboutRepository, AboutRepository>();
|
||||
|
||||
builder.Services.AddControllers();
|
||||
|
||||
builder.Services.AddHopFrame(options => {
|
||||
options.DisplayUserInfo(false);
|
||||
options.AddDbContext<DatabaseContext>();
|
||||
options.AddDbContext<DatabaseContext>(context => {
|
||||
context.Table<Project>(table => {
|
||||
var langConfig = table.InnerConfig.Properties
|
||||
.Single(prop => prop.Name == nameof(Project.Languages));
|
||||
|
||||
langConfig
|
||||
.GetType()!
|
||||
.GetProperty(nameof(PropertyConfig.IsRelation))!
|
||||
.SetValue(langConfig, true);
|
||||
|
||||
langConfig
|
||||
.GetType()!
|
||||
.GetProperty(nameof(PropertyConfig.IsEnumerable))!
|
||||
.SetValue(langConfig, true);
|
||||
|
||||
langConfig
|
||||
.GetType()!
|
||||
.GetProperty(nameof(PropertyConfig.IsRequired))!
|
||||
.SetValue(langConfig, true);
|
||||
|
||||
table.Property(p => p.Languages)
|
||||
.FormatEach<Language>((l, _) => l.Label)
|
||||
.List(false);
|
||||
|
||||
table.Property(p => p.Cover)
|
||||
.List(false);
|
||||
|
||||
table.Property(p => p.Description)
|
||||
.List(false)
|
||||
.IsTextArea(true);
|
||||
|
||||
table.Property(p => p.SourceCode)
|
||||
.List(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
builder.Services.AddRazorComponents()
|
||||
.AddInteractiveServerComponents();
|
||||
@@ -32,6 +78,8 @@ await using (var scope = app.Services.CreateAsyncScope()) {
|
||||
app.UseHttpsRedirection();
|
||||
app.MapDefaultEndpoints();
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
app.UseAntiforgery();
|
||||
app.MapStaticAssets();
|
||||
app.MapRazorComponents<App>()
|
||||
|
||||
14
src/Portfolio.Api/Services/AboutRepository.cs
Normal file
14
src/Portfolio.Api/Services/AboutRepository.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Portfolio.Shared.Models;
|
||||
using Portfolio.Shared.Services;
|
||||
|
||||
namespace Portfolio.Api.Services;
|
||||
|
||||
internal sealed class AboutRepository(DatabaseContext context) : IAboutRepository {
|
||||
|
||||
public async Task<About> GetAbout(CancellationToken ct) {
|
||||
return await context.About
|
||||
.SingleAsync(ct);
|
||||
}
|
||||
|
||||
}
|
||||
15
src/Portfolio.Api/Services/ProjectRepository.cs
Normal file
15
src/Portfolio.Api/Services/ProjectRepository.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Portfolio.Shared.Models;
|
||||
using Portfolio.Shared.Services;
|
||||
|
||||
namespace Portfolio.Api.Services;
|
||||
|
||||
internal sealed class ProjectRepository(DatabaseContext context) : IProjectRepository {
|
||||
|
||||
public async Task<IEnumerable<Project>> GetProjects(CancellationToken ct) {
|
||||
return await context.Projects
|
||||
.Include(p => p.Languages)
|
||||
.ToArrayAsync(ct);
|
||||
}
|
||||
|
||||
}
|
||||
13
src/Portfolio.Api/Services/TechnologyRepository.cs
Normal file
13
src/Portfolio.Api/Services/TechnologyRepository.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Portfolio.Shared.Models;
|
||||
using Portfolio.Shared.Services;
|
||||
|
||||
namespace Portfolio.Api.Services;
|
||||
|
||||
internal sealed class TechnologyRepository(DatabaseContext context) : ITechnologyRepository {
|
||||
|
||||
public async Task<IEnumerable<Technology>> GetTechnologies(CancellationToken ct) {
|
||||
return await context.Technologies.ToArrayAsync(ct);
|
||||
}
|
||||
|
||||
}
|
||||
15
src/Portfolio.Api/Services/TimelineRepository.cs
Normal file
15
src/Portfolio.Api/Services/TimelineRepository.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Portfolio.Shared.Models;
|
||||
using Portfolio.Shared.Services;
|
||||
|
||||
namespace Portfolio.Api.Services;
|
||||
|
||||
internal sealed class TimelineRepository(DatabaseContext context) : ITimelineRepository {
|
||||
|
||||
public async Task<IEnumerable<TimelineEntry>> GetTimeline(TimelineEntryType type, CancellationToken ct) {
|
||||
return await context.Timeline
|
||||
.Where(entry => entry.Type == type)
|
||||
.ToArrayAsync(ct);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Portfolio.Shared.Models;
|
||||
|
||||
public class About {
|
||||
public sealed class About {
|
||||
|
||||
[Key]
|
||||
public int Id { get; private set; } = 0;
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Portfolio.Shared.Models;
|
||||
|
||||
public class TimelineEntry {
|
||||
public sealed class TimelineEntry {
|
||||
|
||||
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public int Id { get; init; }
|
||||
|
||||
9
src/Portfolio.Shared/Services/IAboutRepository.cs
Normal file
9
src/Portfolio.Shared/Services/IAboutRepository.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Portfolio.Shared.Models;
|
||||
|
||||
namespace Portfolio.Shared.Services;
|
||||
|
||||
public interface IAboutRepository {
|
||||
|
||||
Task<About> GetAbout(CancellationToken ct);
|
||||
|
||||
}
|
||||
9
src/Portfolio.Shared/Services/IProjectRepository.cs
Normal file
9
src/Portfolio.Shared/Services/IProjectRepository.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Portfolio.Shared.Models;
|
||||
|
||||
namespace Portfolio.Shared.Services;
|
||||
|
||||
public interface IProjectRepository {
|
||||
|
||||
Task<IEnumerable<Project>> GetProjects(CancellationToken ct);
|
||||
|
||||
}
|
||||
9
src/Portfolio.Shared/Services/ITechnologyRepository.cs
Normal file
9
src/Portfolio.Shared/Services/ITechnologyRepository.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Portfolio.Shared.Models;
|
||||
|
||||
namespace Portfolio.Shared.Services;
|
||||
|
||||
public interface ITechnologyRepository {
|
||||
|
||||
Task<IEnumerable<Technology>> GetTechnologies(CancellationToken ct);
|
||||
|
||||
}
|
||||
9
src/Portfolio.Shared/Services/ITimelineRepository.cs
Normal file
9
src/Portfolio.Shared/Services/ITimelineRepository.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Portfolio.Shared.Models;
|
||||
|
||||
namespace Portfolio.Shared.Services;
|
||||
|
||||
public interface ITimelineRepository {
|
||||
|
||||
Task<IEnumerable<TimelineEntry>> GetTimeline(TimelineEntryType type, CancellationToken ct);
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user