Initial commit

This commit is contained in:
2026-09-17 21:45:57 +02:00
commit 9160e861e0
302 changed files with 31275 additions and 0 deletions

BIN
BookieApi/.DS_Store vendored Normal file

Binary file not shown.

15
BookieApi/.idea/.idea.Bookie/.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,15 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/contentModel.xml
/projectSettingsUpdater.xml
/.idea.Bookie.iml
/modules.xml
# Editor-based HTTP Client requests
/httpRequests/
# Ignored default folder with query files
/queries/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@@ -0,0 +1 @@
Bookie

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

8
BookieApi/Bookie.slnx Normal file
View File

@@ -0,0 +1,8 @@
<Solution>
<Folder Name="/src/">
<Project Path="src/Bookie.Api/Bookie.Api.csproj" />
<Project Path="src/Bookie.Application/Bookie.Application.csproj" />
<Project Path="src/Bookie.Domain/Bookie.Domain.csproj" />
<Project Path="src/Bookie.Infrastructure/Bookie.Infrastructure.csproj" />
</Folder>
</Solution>

7
BookieApi/nuget.config Normal file
View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
</packageSources>
</configuration>

BIN
BookieApi/src/.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.11" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.5" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.2.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Bookie.Application\Bookie.Application.csproj" />
<ProjectReference Include="..\Bookie.Infrastructure\Bookie.Infrastructure.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,6 @@
@Bookie.Api_HostAddress = http://localhost:5210
GET {{Bookie.Api_HostAddress}}/weatherforecast/
Accept: application/json
###

View File

@@ -0,0 +1,36 @@
using Bookie.Application.DTOs.Auth;
using Bookie.Application.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Bookie.Api.Controllers;
[ApiController]
[Route("api/auth")]
public class AuthController : ControllerBase
{
private readonly IAuthService _auth;
public AuthController(IAuthService auth) => _auth = auth;
/// <summary>Exchange username/password for a JWT.</summary>
[HttpPost("login")]
[AllowAnonymous]
[ProducesResponseType(typeof(AuthResponseDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public ActionResult<AuthResponseDto> Login([FromBody] LoginRequestDto request)
{
var result = _auth.Login(request);
return result is null ? Unauthorized(new { message = "Invalid credentials." }) : Ok(result);
}
/// <summary>Returns the current user's identity from the token.</summary>
[HttpGet("me")]
[Authorize]
public ActionResult<object> Me()
=> Ok(new
{
username = User.Identity?.Name,
role = User.FindFirst(System.Security.Claims.ClaimTypes.Role)?.Value
});
}

View File

@@ -0,0 +1,54 @@
using Bookie.Application.DTOs.Common;
using Bookie.Application.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Bookie.Api.Controllers;
/// <summary>
/// Shared CRUD endpoints. Reads require any authenticated user; writes require the admin role.
/// </summary>
[ApiController]
[Authorize]
public abstract class CrudControllerBase<TRead, TCreate, TUpdate> : ControllerBase
{
protected readonly ICrudService<TRead, TCreate, TUpdate, int> Service;
protected CrudControllerBase(ICrudService<TRead, TCreate, TUpdate, int> service) => Service = service;
/// <summary>Paged list with optional search + sorting.</summary>
[HttpGet]
public async Task<ActionResult<PagedResult<TRead>>> GetPaged([FromQuery] PagedQuery query, CancellationToken ct)
=> Ok(await Service.GetPagedAsync(query, ct));
[HttpGet("{id:int}")]
public async Task<ActionResult<TRead>> GetById(int id, CancellationToken ct)
{
var item = await Service.GetByIdAsync(id, ct);
return item is null ? NotFound() : Ok(item);
}
[HttpPost]
[Authorize(Roles = "admin")]
public async Task<ActionResult<TRead>> Create([FromBody] TCreate dto, CancellationToken ct)
{
var created = await Service.CreateAsync(dto, ct);
return StatusCode(StatusCodes.Status201Created, created);
}
[HttpPut("{id:int}")]
[Authorize(Roles = "admin")]
public async Task<ActionResult<TRead>> Update(int id, [FromBody] TUpdate dto, CancellationToken ct)
{
var updated = await Service.UpdateAsync(id, dto, ct);
return updated is null ? NotFound() : Ok(updated);
}
[HttpDelete("{id:int}")]
[Authorize(Roles = "admin")]
public async Task<IActionResult> Delete(int id, CancellationToken ct)
{
var ok = await Service.DeleteAsync(id, ct);
return ok ? NoContent() : NotFound();
}
}

View File

@@ -0,0 +1,21 @@
using Bookie.Application.DTOs.Dashboard;
using Bookie.Application.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Bookie.Api.Controllers;
[ApiController]
[Route("api/dashboard")]
[Authorize]
public class DashboardController : ControllerBase
{
private readonly IDashboardService _dashboard;
public DashboardController(IDashboardService dashboard) => _dashboard = dashboard;
[HttpGet("summary")]
[ProducesResponseType(typeof(DashboardSummaryDto), StatusCodes.Status200OK)]
public async Task<ActionResult<DashboardSummaryDto>> GetSummary(CancellationToken ct)
=> Ok(await _dashboard.GetSummaryAsync(ct));
}

View File

@@ -0,0 +1,11 @@
using Bookie.Application.DTOs.Leagues;
using Bookie.Application.Interfaces;
using Microsoft.AspNetCore.Mvc;
namespace Bookie.Api.Controllers;
[Route("api/leagues")]
public class LeaguesController : CrudControllerBase<LeagueDto, LeagueCreateDto, LeagueUpdateDto>
{
public LeaguesController(ILeagueService service) : base(service) { }
}

View File

@@ -0,0 +1,36 @@
using Bookie.Application.DTOs.Common;
using Bookie.Application.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Bookie.Api.Controllers;
[ApiController]
[Route("api/lookups")]
[Authorize]
public class LookupsController : ControllerBase
{
private readonly ILookupService _lookups;
public LookupsController(ILookupService lookups) => _lookups = lookups;
[HttpGet("leagues")]
public async Task<ActionResult<IReadOnlyList<LookupDto>>> Leagues(CancellationToken ct)
=> Ok(await _lookups.LeaguesAsync(ct));
[HttpGet("seasons")]
public async Task<ActionResult<IReadOnlyList<LookupDto>>> Seasons([FromQuery] int? leagueId, CancellationToken ct)
=> Ok(await _lookups.SeasonsAsync(leagueId, ct));
[HttpGet("teams")]
public async Task<ActionResult<IReadOnlyList<LookupDto>>> Teams([FromQuery] int? leagueId, [FromQuery] int? seasonId, CancellationToken ct)
=> Ok(await _lookups.TeamsAsync(leagueId, seasonId, ct));
[HttpGet("players")]
public async Task<ActionResult<IReadOnlyList<LookupDto>>> Players(CancellationToken ct)
=> Ok(await _lookups.PlayersAsync(ct));
[HttpGet("matchdays")]
public async Task<ActionResult<IReadOnlyList<LookupDto>>> Matchdays(CancellationToken ct)
=> Ok(await _lookups.MatchdaysAsync(ct));
}

View File

@@ -0,0 +1,11 @@
using Bookie.Application.DTOs.Matches;
using Bookie.Application.Interfaces;
using Microsoft.AspNetCore.Mvc;
namespace Bookie.Api.Controllers;
[Route("api/matches")]
public class MatchesController : CrudControllerBase<MatchDto, MatchCreateDto, MatchUpdateDto>
{
public MatchesController(IMatchService service) : base(service) { }
}

View File

@@ -0,0 +1,18 @@
using Bookie.Application.DTOs.Contracts;
using Bookie.Application.Interfaces;
using Microsoft.AspNetCore.Mvc;
namespace Bookie.Api.Controllers;
[Route("api/player-contracts")]
public class PlayerContractsController : CrudControllerBase<PlayerContractDto, PlayerContractCreateDto, PlayerContractUpdateDto>
{
private readonly IPlayerContractService _contracts;
public PlayerContractsController(IPlayerContractService service) : base(service) => _contracts = service;
/// <summary>All contracts for a given player.</summary>
[HttpGet("by-player/{playerId:int}")]
public async Task<ActionResult<IReadOnlyList<PlayerContractDto>>> GetByPlayer(int playerId, CancellationToken ct)
=> Ok(await _contracts.GetByPlayerAsync(playerId, ct));
}

View File

@@ -0,0 +1,11 @@
using Bookie.Application.DTOs.Players;
using Bookie.Application.Interfaces;
using Microsoft.AspNetCore.Mvc;
namespace Bookie.Api.Controllers;
[Route("api/players")]
public class PlayersController : CrudControllerBase<PlayerDto, PlayerCreateDto, PlayerUpdateDto>
{
public PlayersController(IPlayerService service) : base(service) { }
}

View File

@@ -0,0 +1,77 @@
using Bookie.Application.DTOs.Predictions;
using Bookie.Application.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Bookie.Api.Controllers;
[ApiController]
[Route("api/predictions")]
[Authorize]
public class PredictionsController : ControllerBase
{
private readonly IPredictionService _service;
private readonly ILogger<PredictionsController> _logger;
public PredictionsController(IPredictionService service, ILogger<PredictionsController> logger)
{
_service = service;
_logger = logger;
}
/// <summary>
/// Statistical projection (goals, cards, fouls, corners, shots on target) for a single
/// fixture, produced by the OpenAI-backed Football Match Statistics Predictor.
/// </summary>
[HttpPost("match/{matchId:int}")]
[ProducesResponseType(typeof(MatchPredictionDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status502BadGateway)]
public async Task<ActionResult<MatchPredictionDto>> PredictMatch(int matchId, CancellationToken ct)
{
try
{
var prediction = await _service.PredictMatchAsync(matchId, ct);
return prediction is null ? NotFound() : Ok(prediction);
}
catch (InvalidOperationException ex)
{
// Configuration or upstream OpenAI failures — surface a clean message to the client.
_logger.LogError(ex, "Prediction failed for match {MatchId}", matchId);
return Problem(title: "Prediction unavailable", detail: ex.Message, statusCode: StatusCodes.Status502BadGateway);
}
}
/// <summary>
/// Batch projection for several fixtures in a single model call. The predictor prompt is
/// batch-oriented, so this produces consistent, cross-checked estimates across the selection.
/// </summary>
[HttpPost("matches")]
[ProducesResponseType(typeof(IEnumerable<MatchPredictionDto>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status502BadGateway)]
public async Task<ActionResult<IEnumerable<MatchPredictionDto>>> PredictMatches(
[FromBody] PredictMatchesRequest request, CancellationToken ct)
{
if (request?.MatchIds is null || request.MatchIds.Count == 0)
return BadRequest("Provide at least one match id.");
if (request.MatchIds.Count > 20)
return BadRequest("A maximum of 20 matches can be predicted per request.");
try
{
var predictions = await _service.PredictMatchesAsync(request.MatchIds, ct);
return Ok(predictions);
}
catch (InvalidOperationException ex)
{
_logger.LogError(ex, "Batch prediction failed for {Count} matches", request.MatchIds.Count);
return Problem(title: "Prediction unavailable", detail: ex.Message, statusCode: StatusCodes.Status502BadGateway);
}
}
public class PredictMatchesRequest
{
public List<int> MatchIds { get; set; } = new();
}
}

View File

@@ -0,0 +1,57 @@
using Bookie.Application.DTOs.Reports;
using Bookie.Application.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Bookie.Api.Controllers;
[ApiController]
[Route("api/reports")]
[Authorize]
public class ReportsController : ControllerBase
{
private readonly IPreMatchReportService _service;
public ReportsController(IPreMatchReportService service) => _service = service;
/// <summary>
/// Pre-Match Report: all matches on the given date grouped by league/country/season,
/// with per-team historical stats computed only from earlier matches in the same season.
/// </summary>
/// <param name="date">Target day in YYYY-MM-DD. Defaults to today.</param>
/// <param name="seasonsBack">
/// How many previous seasons of the same league to fold into the stats.
/// 0 (default) = current season only; 1 = current + previous, etc.
/// </param>
[HttpGet("pre-match")]
[ProducesResponseType(typeof(PreMatchReportDto), StatusCodes.Status200OK)]
public async Task<ActionResult<PreMatchReportDto>> GetPreMatch(
[FromQuery] DateOnly? date, [FromQuery] int seasonsBack = 0, CancellationToken ct = default)
{
var target = date ?? DateOnly.FromDateTime(DateTime.Today);
var report = await _service.GetPreMatchReportAsync(target, seasonsBack, ct);
return Ok(report);
}
/// <summary>Full statistics for a single match (team stats, goals, cards, penalties).</summary>
[HttpGet("match/{matchId:int}")]
[ProducesResponseType(typeof(MatchDetailsDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<MatchDetailsDto>> GetMatchDetails(int matchId, CancellationToken ct)
{
var details = await _service.GetMatchDetailsAsync(matchId, ct);
return details is null ? NotFound() : Ok(details);
}
/// <summary>Historical head-to-head record between two teams (previous meetings before a given match).</summary>
[HttpGet("head-to-head")]
[ProducesResponseType(typeof(HeadToHeadDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<HeadToHeadDto>> GetHeadToHead(
[FromQuery] int teamAId, [FromQuery] int teamBId,
[FromQuery] int? beforeMatchId, CancellationToken ct)
{
var h2h = await _service.GetHeadToHeadAsync(teamAId, teamBId, beforeMatchId, ct);
return h2h is null ? NotFound() : Ok(h2h);
}
}

View File

@@ -0,0 +1,18 @@
using Bookie.Application.DTOs.Seasons;
using Bookie.Application.Interfaces;
using Microsoft.AspNetCore.Mvc;
namespace Bookie.Api.Controllers;
[Route("api/seasons")]
public class SeasonsController : CrudControllerBase<SeasonDto, SeasonCreateDto, SeasonUpdateDto>
{
private readonly ISeasonService _seasons;
public SeasonsController(ISeasonService service) : base(service) => _seasons = service;
/// <summary>All seasons for a given league (for dropdowns).</summary>
[HttpGet("by-league/{leagueId:int}")]
public async Task<ActionResult<IReadOnlyList<SeasonDto>>> GetByLeague(int leagueId, CancellationToken ct)
=> Ok(await _seasons.GetByLeagueAsync(leagueId, ct));
}

View File

@@ -0,0 +1,35 @@
using Bookie.Application.DTOs.Stats;
using Bookie.Application.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Bookie.Api.Controllers;
[ApiController]
[Authorize]
public class StatsController : ControllerBase
{
private readonly IStatsService _service;
public StatsController(IStatsService service) => _service = service;
/// <summary>Aggregated career statistics for a single player (goals, assists, cards, per-season, recent goals).</summary>
[HttpGet("api/players/{playerId:int}/stats")]
[ProducesResponseType(typeof(PlayerStatsDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<PlayerStatsDto>> GetPlayerStats(int playerId, CancellationToken ct)
{
var stats = await _service.GetPlayerStatsAsync(playerId, ct);
return stats is null ? NotFound() : Ok(stats);
}
/// <summary>Aggregated statistics for a single team (record, averages, form, top scorers, per-season, recent matches).</summary>
[HttpGet("api/teams/{teamId:int}/stats")]
[ProducesResponseType(typeof(TeamStatsDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<TeamStatsDto>> GetTeamStats(int teamId, CancellationToken ct)
{
var stats = await _service.GetTeamStatsAsync(teamId, ct);
return stats is null ? NotFound() : Ok(stats);
}
}

View File

@@ -0,0 +1,18 @@
using Bookie.Application.DTOs.Teams;
using Bookie.Application.Interfaces;
using Microsoft.AspNetCore.Mvc;
namespace Bookie.Api.Controllers;
[Route("api/teams")]
public class TeamsController : CrudControllerBase<TeamDto, TeamCreateDto, TeamUpdateDto>
{
private readonly ITeamService _teams;
public TeamsController(ITeamService service) : base(service) => _teams = service;
/// <summary>Unpaged list of all teams (for dropdowns).</summary>
[HttpGet("all")]
public async Task<ActionResult<IReadOnlyList<TeamDto>>> GetAll(CancellationToken ct)
=> Ok(await _teams.GetAllAsync(ct));
}

View File

@@ -0,0 +1,97 @@
using System.Text;
using System.Text.Json.Serialization;
using Bookie.Infrastructure;
using Bookie.Infrastructure.Auth;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi;
// The bookie schema mixes plain `timestamp` and `timestamp with time zone` columns
// (e.g. kickoff_at is timestamptz in the live DB). Legacy behavior lets Npgsql accept
// Local/Unspecified DateTime kinds for both, so date-range filters work without casting.
// Must be set before the Npgsql data source is built.
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", false);
var builder = WebApplication.CreateBuilder(args);
const string CorsPolicy = "BookieClient";
builder.Services.AddControllers()
.AddJsonOptions(o =>
{
// Serialize enums as strings and keep DateOnly/DateTime in ISO form.
o.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
});
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Title = "Bookie API",
Version = "v1",
Description = "Football stats API over the PostgreSQL \"bookie\" schema. " +
"Includes the Pre-Match Report feature plus CRUD for the core entities."
});
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Name = "Authorization",
Type = SecuritySchemeType.Http,
Scheme = "bearer",
BearerFormat = "JWT",
In = ParameterLocation.Header,
Description = "Enter the JWT returned by /api/auth/login."
});
c.AddSecurityRequirement(doc => new OpenApiSecurityRequirement
{
[new OpenApiSecuritySchemeReference("Bearer", doc)] = new List<string>()
});
});
// Infrastructure: EF Core (Npgsql) + services + auth options.
builder.Services.AddBookieInfrastructure(builder.Configuration);
// JWT authentication.
var jwtOptions = builder.Configuration.GetSection(JwtOptions.SectionName).Get<JwtOptions>() ?? new JwtOptions();
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = jwtOptions.Issuer,
ValidAudience = jwtOptions.Audience,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.Secret)),
ClockSkew = TimeSpan.FromMinutes(1)
};
});
builder.Services.AddAuthorization();
builder.Services.AddCors(options =>
options.AddPolicy(CorsPolicy, policy => policy
.WithOrigins(builder.Configuration.GetSection("Cors:AllowedOrigins").Get<string[]>()
?? new[] { "http://localhost:4200" })
.AllowAnyHeader()
.AllowAnyMethod()));
var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Bookie API v1");
c.RoutePrefix = "swagger";
});
app.UseCors(CorsPolicy);
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();

View File

@@ -0,0 +1,23 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"applicationUrl": "http://localhost:5210",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"applicationUrl": "https://localhost:7228;http://localhost:5210",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@@ -0,0 +1,32 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"BookieDb": "Host=158.220.99.25;Port=5432;Database=modwad;Username=trent;Password=QQVWG3DE5DHD2OWS3PRFKABOQJT55ACBEELK47FO275SVRCOP3GQ====;Search Path=bookie"
},
"Jwt": {
"Issuer": "BookieApi",
"Audience": "BookieClient",
"Secret": "CHANGE_ME_super_secret_key_at_least_32_chars_long_1234567890",
"ExpiryMinutes": 480
},
"AuthUsers": {
"Users": [
{ "Username": "admin", "Password": "admin123", "Role": "admin" },
{ "Username": "user", "Password": "user123", "Role": "user" }
]
},
"Cors": {
"AllowedOrigins": [ "http://localhost:4200" ]
},
"OpenAI": {
"ApiKey": "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",
"Model": "gpt-5.6-luna",
"BaseUrl": "https://api.openai.com/v1"
}
}

Binary file not shown.

View File

@@ -0,0 +1,421 @@
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v10.0",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v10.0": {
"Bookie.Api/1.0.0": {
"dependencies": {
"Bookie.Application": "1.0.0",
"Bookie.Infrastructure": "1.0.0",
"Microsoft.AspNetCore.Authentication.JwtBearer": "10.0.11",
"Microsoft.AspNetCore.OpenApi": "10.0.5",
"Swashbuckle.AspNetCore": "10.2.3"
},
"runtime": {
"Bookie.Api.dll": {}
}
},
"Microsoft.AspNetCore.Authentication.JwtBearer/10.0.11": {
"dependencies": {
"Microsoft.IdentityModel.Protocols.OpenIdConnect": "8.19.2"
},
"runtime": {
"lib/net10.0/Microsoft.AspNetCore.Authentication.JwtBearer.dll": {
"assemblyVersion": "10.0.11.0",
"fileVersion": "10.0.1126.37416"
}
}
},
"Microsoft.AspNetCore.OpenApi/10.0.5": {
"dependencies": {
"Microsoft.OpenApi": "2.7.5"
},
"runtime": {
"lib/net10.0/Microsoft.AspNetCore.OpenApi.dll": {
"assemblyVersion": "10.0.5.0",
"fileVersion": "10.0.526.15411"
}
}
},
"Microsoft.Bcl.Cryptography/10.0.2": {
"runtime": {
"lib/net10.0/Microsoft.Bcl.Cryptography.dll": {
"assemblyVersion": "10.0.0.2",
"fileVersion": "10.0.225.61305"
}
}
},
"Microsoft.EntityFrameworkCore/10.0.4": {
"dependencies": {
"Microsoft.EntityFrameworkCore.Abstractions": "10.0.4"
},
"runtime": {
"lib/net10.0/Microsoft.EntityFrameworkCore.dll": {
"assemblyVersion": "10.0.4.0",
"fileVersion": "10.0.426.12010"
}
}
},
"Microsoft.EntityFrameworkCore.Abstractions/10.0.4": {
"runtime": {
"lib/net10.0/Microsoft.EntityFrameworkCore.Abstractions.dll": {
"assemblyVersion": "10.0.4.0",
"fileVersion": "10.0.426.12010"
}
}
},
"Microsoft.EntityFrameworkCore.Relational/10.0.4": {
"dependencies": {
"Microsoft.EntityFrameworkCore": "10.0.4"
},
"runtime": {
"lib/net10.0/Microsoft.EntityFrameworkCore.Relational.dll": {
"assemblyVersion": "10.0.4.0",
"fileVersion": "10.0.426.12010"
}
}
},
"Microsoft.IdentityModel.Abstractions/8.22.0": {
"runtime": {
"lib/net10.0/Microsoft.IdentityModel.Abstractions.dll": {
"assemblyVersion": "8.22.0.0",
"fileVersion": "8.22.0.26208"
}
}
},
"Microsoft.IdentityModel.JsonWebTokens/8.22.0": {
"dependencies": {
"Microsoft.IdentityModel.Tokens": "8.22.0"
},
"runtime": {
"lib/net10.0/Microsoft.IdentityModel.JsonWebTokens.dll": {
"assemblyVersion": "8.22.0.0",
"fileVersion": "8.22.0.26208"
}
}
},
"Microsoft.IdentityModel.Logging/8.22.0": {
"dependencies": {
"Microsoft.IdentityModel.Abstractions": "8.22.0"
},
"runtime": {
"lib/net10.0/Microsoft.IdentityModel.Logging.dll": {
"assemblyVersion": "8.22.0.0",
"fileVersion": "8.22.0.26208"
}
}
},
"Microsoft.IdentityModel.Protocols/8.19.2": {
"dependencies": {
"Microsoft.IdentityModel.Tokens": "8.22.0"
},
"runtime": {
"lib/net10.0/Microsoft.IdentityModel.Protocols.dll": {
"assemblyVersion": "8.19.2.0",
"fileVersion": "8.19.2.26195"
}
}
},
"Microsoft.IdentityModel.Protocols.OpenIdConnect/8.19.2": {
"dependencies": {
"Microsoft.IdentityModel.Protocols": "8.19.2",
"System.IdentityModel.Tokens.Jwt": "8.22.0"
},
"runtime": {
"lib/net10.0/Microsoft.IdentityModel.Protocols.OpenIdConnect.dll": {
"assemblyVersion": "8.19.2.0",
"fileVersion": "8.19.2.26195"
}
}
},
"Microsoft.IdentityModel.Tokens/8.22.0": {
"dependencies": {
"Microsoft.Bcl.Cryptography": "10.0.2",
"Microsoft.IdentityModel.Logging": "8.22.0"
},
"runtime": {
"lib/net10.0/Microsoft.IdentityModel.Tokens.dll": {
"assemblyVersion": "8.22.0.0",
"fileVersion": "8.22.0.26208"
}
}
},
"Microsoft.OpenApi/2.7.5": {
"runtime": {
"lib/net8.0/Microsoft.OpenApi.dll": {
"assemblyVersion": "2.7.5.0",
"fileVersion": "2.7.5.0"
}
}
},
"Npgsql/10.0.3": {
"runtime": {
"lib/net10.0/Npgsql.dll": {
"assemblyVersion": "10.0.3.0",
"fileVersion": "10.0.3.0"
}
}
},
"Npgsql.EntityFrameworkCore.PostgreSQL/10.0.3": {
"dependencies": {
"Microsoft.EntityFrameworkCore": "10.0.4",
"Microsoft.EntityFrameworkCore.Relational": "10.0.4",
"Npgsql": "10.0.3"
},
"runtime": {
"lib/net10.0/Npgsql.EntityFrameworkCore.PostgreSQL.dll": {
"assemblyVersion": "10.0.3.0",
"fileVersion": "10.0.3.0"
}
}
},
"Swashbuckle.AspNetCore/10.2.3": {
"dependencies": {
"Swashbuckle.AspNetCore.Swagger": "10.2.3",
"Swashbuckle.AspNetCore.SwaggerGen": "10.2.3",
"Swashbuckle.AspNetCore.SwaggerUI": "10.2.3"
}
},
"Swashbuckle.AspNetCore.Swagger/10.2.3": {
"dependencies": {
"Microsoft.OpenApi": "2.7.5"
},
"runtime": {
"lib/net10.0/Swashbuckle.AspNetCore.Swagger.dll": {
"assemblyVersion": "10.2.3.0",
"fileVersion": "10.2.3.2721"
}
}
},
"Swashbuckle.AspNetCore.SwaggerGen/10.2.3": {
"dependencies": {
"Swashbuckle.AspNetCore.Swagger": "10.2.3"
},
"runtime": {
"lib/net10.0/Swashbuckle.AspNetCore.SwaggerGen.dll": {
"assemblyVersion": "10.2.3.0",
"fileVersion": "10.2.3.2721"
}
}
},
"Swashbuckle.AspNetCore.SwaggerUI/10.2.3": {
"runtime": {
"lib/net10.0/Swashbuckle.AspNetCore.SwaggerUI.dll": {
"assemblyVersion": "10.2.3.0",
"fileVersion": "10.2.3.2721"
}
}
},
"System.IdentityModel.Tokens.Jwt/8.22.0": {
"dependencies": {
"Microsoft.IdentityModel.JsonWebTokens": "8.22.0",
"Microsoft.IdentityModel.Tokens": "8.22.0"
},
"runtime": {
"lib/net10.0/System.IdentityModel.Tokens.Jwt.dll": {
"assemblyVersion": "8.22.0.0",
"fileVersion": "8.22.0.26208"
}
}
},
"Bookie.Application/1.0.0": {
"dependencies": {
"Bookie.Domain": "1.0.0"
},
"runtime": {
"Bookie.Application.dll": {
"assemblyVersion": "1.0.0.0",
"fileVersion": "1.0.0.0"
}
}
},
"Bookie.Domain/1.0.0": {
"runtime": {
"Bookie.Domain.dll": {
"assemblyVersion": "1.0.0.0",
"fileVersion": "1.0.0.0"
}
}
},
"Bookie.Infrastructure/1.0.0": {
"dependencies": {
"Bookie.Application": "1.0.0",
"Bookie.Domain": "1.0.0",
"Npgsql.EntityFrameworkCore.PostgreSQL": "10.0.3",
"System.IdentityModel.Tokens.Jwt": "8.22.0"
},
"runtime": {
"Bookie.Infrastructure.dll": {
"assemblyVersion": "1.0.0.0",
"fileVersion": "1.0.0.0"
}
}
}
}
},
"libraries": {
"Bookie.Api/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"Microsoft.AspNetCore.Authentication.JwtBearer/10.0.11": {
"type": "package",
"serviceable": true,
"sha512": "sha512-Dy9yElSej0rVQL8LBpCLatWTKXNH6h6VBVFmGndTCf1Wge0jSvH9U8mml6ddVDAQ089q1/fDYlhyukHSgx8unQ==",
"path": "microsoft.aspnetcore.authentication.jwtbearer/10.0.11",
"hashPath": "microsoft.aspnetcore.authentication.jwtbearer.10.0.11.nupkg.sha512"
},
"Microsoft.AspNetCore.OpenApi/10.0.5": {
"type": "package",
"serviceable": true,
"sha512": "sha512-vTcxIfOPyfFbYk1g8YcXJfkMnlEWVkSnnjxcZLy60zgwiHMRf2SnZR+9E4HlpwKxgE3yfKMOti8J6WfKuKsw6w==",
"path": "microsoft.aspnetcore.openapi/10.0.5",
"hashPath": "microsoft.aspnetcore.openapi.10.0.5.nupkg.sha512"
},
"Microsoft.Bcl.Cryptography/10.0.2": {
"type": "package",
"serviceable": true,
"sha512": "sha512-LG9Yll3B5aNpxv0+D47g6LiOiKBIlodhcHdQwcYzo8VeexFLGqx5ymetmA2aBRyo9cCcWsQWrFsdbsr8LvmWDw==",
"path": "microsoft.bcl.cryptography/10.0.2",
"hashPath": "microsoft.bcl.cryptography.10.0.2.nupkg.sha512"
},
"Microsoft.EntityFrameworkCore/10.0.4": {
"type": "package",
"serviceable": true,
"sha512": "sha512-kzTsfFK2GCytp6DDTfQOmxPU4gbGdrIlP7PxrxF3ESNLtfXrC8BoUVZENBN2WORlZPAD7CVX6AYIglgkpXQooA==",
"path": "microsoft.entityframeworkcore/10.0.4",
"hashPath": "microsoft.entityframeworkcore.10.0.4.nupkg.sha512"
},
"Microsoft.EntityFrameworkCore.Abstractions/10.0.4": {
"type": "package",
"serviceable": true,
"sha512": "sha512-qDcJqCfN1XYyX0ID/Hd9/kQTRvlia8S+Yuwyl9uFhBIKnOCbl9WMdGQCzbZUKbkpkfvf3P9CDdXsnxHyE3O0Aw==",
"path": "microsoft.entityframeworkcore.abstractions/10.0.4",
"hashPath": "microsoft.entityframeworkcore.abstractions.10.0.4.nupkg.sha512"
},
"Microsoft.EntityFrameworkCore.Relational/10.0.4": {
"type": "package",
"serviceable": true,
"sha512": "sha512-DOTjTHy93W3TwpMLM4SCm0n57Sc0Jj3+m2S6LSTstKyBB34eT1UouaMS19mpWwvtj42+sRiEjA3+rOTNoNzXFQ==",
"path": "microsoft.entityframeworkcore.relational/10.0.4",
"hashPath": "microsoft.entityframeworkcore.relational.10.0.4.nupkg.sha512"
},
"Microsoft.IdentityModel.Abstractions/8.22.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-LU3V3owsu4vGpCg2kyL7SsQEuHwcoJ8FSNBqzLADzCf3/PcKUTcx5Plsd51DoTJMfK/WigXV/03UhaN5JXE6uQ==",
"path": "microsoft.identitymodel.abstractions/8.22.0",
"hashPath": "microsoft.identitymodel.abstractions.8.22.0.nupkg.sha512"
},
"Microsoft.IdentityModel.JsonWebTokens/8.22.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-kv6peMLjALZLDAy2H3F77KjVRdwiscn2p/g3ui2chcbuEcAX2MpAbyDcYnJ7Vyh8jZ1aJWrniUMCDWoOgnu4NQ==",
"path": "microsoft.identitymodel.jsonwebtokens/8.22.0",
"hashPath": "microsoft.identitymodel.jsonwebtokens.8.22.0.nupkg.sha512"
},
"Microsoft.IdentityModel.Logging/8.22.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-G9Tl0yXSlr2pkXv4EpXjO16M4q6oo9N/od+gNyOusZ8yM8LZg1H3f/QOMFuOJiV6znzY5MkAREU97JRRnqpEQw==",
"path": "microsoft.identitymodel.logging/8.22.0",
"hashPath": "microsoft.identitymodel.logging.8.22.0.nupkg.sha512"
},
"Microsoft.IdentityModel.Protocols/8.19.2": {
"type": "package",
"serviceable": true,
"sha512": "sha512-sGxSsSrZXNmca6D+jHH2rVRyo2nNRd/g4H9CFbPmLLq0xgoH1U0orLWE5minfijw7+zq49tBs7txenbfAErRoQ==",
"path": "microsoft.identitymodel.protocols/8.19.2",
"hashPath": "microsoft.identitymodel.protocols.8.19.2.nupkg.sha512"
},
"Microsoft.IdentityModel.Protocols.OpenIdConnect/8.19.2": {
"type": "package",
"serviceable": true,
"sha512": "sha512-1XOcyY36cVymzE3qKdzKaUEZ4Pzt7ZpSa14JZoPPK1NLFUkQDs85TCqpV6XDo0YjFXj6nVK00AfOHppjghjhtw==",
"path": "microsoft.identitymodel.protocols.openidconnect/8.19.2",
"hashPath": "microsoft.identitymodel.protocols.openidconnect.8.19.2.nupkg.sha512"
},
"Microsoft.IdentityModel.Tokens/8.22.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-i4lywKKUuVmheCUA+w/q8QNPReNI0qanHI9hhz48AFqD1ljyb8sxPL2RbXOGiPV13XdJ4kxieL9ukS7tD43LxA==",
"path": "microsoft.identitymodel.tokens/8.22.0",
"hashPath": "microsoft.identitymodel.tokens.8.22.0.nupkg.sha512"
},
"Microsoft.OpenApi/2.7.5": {
"type": "package",
"serviceable": true,
"sha512": "sha512-0FA67RSnRM4tcBKqiqVu/HPdZ9+QOKbmeRjxRUGTCjPU4C0bmUhd97Dso7Yild5P7nOV6GxJ2xrK0Kv/O9xp0w==",
"path": "microsoft.openapi/2.7.5",
"hashPath": "microsoft.openapi.2.7.5.nupkg.sha512"
},
"Npgsql/10.0.3": {
"type": "package",
"serviceable": true,
"sha512": "sha512-7nb5YzXuvWWJxB0J8DiyL3we+X4FOctZrt0fIBnucOIaIevFEEwGQVZKtiu9olXdlNAK1eNgqSral6r/jlhI4w==",
"path": "npgsql/10.0.3",
"hashPath": "npgsql.10.0.3.nupkg.sha512"
},
"Npgsql.EntityFrameworkCore.PostgreSQL/10.0.3": {
"type": "package",
"serviceable": true,
"sha512": "sha512-IPGrrZnRkuW7OlHDhUESZz4G5DLkW7Nej/O3Cx+0iTsgyU5XJxBgpsvTHLloo3WWuAKKbDHXBvWPVkX1deRh1Q==",
"path": "npgsql.entityframeworkcore.postgresql/10.0.3",
"hashPath": "npgsql.entityframeworkcore.postgresql.10.0.3.nupkg.sha512"
},
"Swashbuckle.AspNetCore/10.2.3": {
"type": "package",
"serviceable": true,
"sha512": "sha512-8KNh1RWvofdU6DVLyBs4Z/OpUMnmf8oNvJQc0QxpwySRbi42bwLfdVMMrXZWANg5U5KQGQq1xW6r/hlcqw99tQ==",
"path": "swashbuckle.aspnetcore/10.2.3",
"hashPath": "swashbuckle.aspnetcore.10.2.3.nupkg.sha512"
},
"Swashbuckle.AspNetCore.Swagger/10.2.3": {
"type": "package",
"serviceable": true,
"sha512": "sha512-1jUUs3WQnrS0FUtaZPLSy1yYMEwS1zlvDmvQ2/eldPHUANX0LJSLVZecCMgSMdeGiRqeaRrIXLtSz++TCiTMww==",
"path": "swashbuckle.aspnetcore.swagger/10.2.3",
"hashPath": "swashbuckle.aspnetcore.swagger.10.2.3.nupkg.sha512"
},
"Swashbuckle.AspNetCore.SwaggerGen/10.2.3": {
"type": "package",
"serviceable": true,
"sha512": "sha512-y7t4coDRAeFYChmvlMRiH2OjbiRrm9AVIDgt17fQfs3x9PVAI5PiwWYOhg+4F13R4Q36WDc9lqfoOnNa3tNbGg==",
"path": "swashbuckle.aspnetcore.swaggergen/10.2.3",
"hashPath": "swashbuckle.aspnetcore.swaggergen.10.2.3.nupkg.sha512"
},
"Swashbuckle.AspNetCore.SwaggerUI/10.2.3": {
"type": "package",
"serviceable": true,
"sha512": "sha512-nthWONRs/FJ4yyG206g1cC52WEG8EqrjuMWjGdR+5XG7lbjFto6NqcI9EMICgVFom/UivIjUVwI76ZHbHwTPfQ==",
"path": "swashbuckle.aspnetcore.swaggerui/10.2.3",
"hashPath": "swashbuckle.aspnetcore.swaggerui.10.2.3.nupkg.sha512"
},
"System.IdentityModel.Tokens.Jwt/8.22.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-CpXGfNhLl6EgYaOC9XYsc1p7Ci9HtAy0soHJDSBNGse647al4tTq9RDr+LQsrF4Ls79Dx7VfzN34km0W4DWPow==",
"path": "system.identitymodel.tokens.jwt/8.22.0",
"hashPath": "system.identitymodel.tokens.jwt.8.22.0.nupkg.sha512"
},
"Bookie.Application/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"Bookie.Domain/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"Bookie.Infrastructure/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
}
}
}

View File

@@ -0,0 +1,20 @@
{
"runtimeOptions": {
"tfm": "net10.0",
"frameworks": [
{
"name": "Microsoft.NETCore.App",
"version": "10.0.0"
},
{
"name": "Microsoft.AspNetCore.App",
"version": "10.0.0"
}
],
"configProperties": {
"System.GC.Server": true,
"System.Reflection.NullabilityInfoContext.IsSupported": true,
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
}
}
}

View File

@@ -0,0 +1 @@
{"Version":1,"ManifestType":"Build","Endpoints":[]}

Binary file not shown.

View File

@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@@ -0,0 +1,32 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"BookieDb": "Host=158.220.99.25;Port=5432;Database=modwad;Username=trent;Password=QQVWG3DE5DHD2OWS3PRFKABOQJT55ACBEELK47FO275SVRCOP3GQ====;Search Path=bookie"
},
"Jwt": {
"Issuer": "BookieApi",
"Audience": "BookieClient",
"Secret": "CHANGE_ME_super_secret_key_at_least_32_chars_long_1234567890",
"ExpiryMinutes": 480
},
"AuthUsers": {
"Users": [
{ "Username": "admin", "Password": "admin123", "Role": "admin" },
{ "Username": "user", "Password": "user123", "Role": "user" }
]
},
"Cors": {
"AllowedOrigins": [ "http://localhost:4200" ]
},
"OpenAI": {
"ApiKey": "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",
"Model": "gpt-5.6-luna",
"BaseUrl": "https://api.openai.com/v1"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<RestoreSuccess Condition=" '$(RestoreSuccess)' == '' ">True</RestoreSuccess>
<RestoreTool Condition=" '$(RestoreTool)' == '' ">NuGet</RestoreTool>
<ProjectAssetsFile Condition=" '$(ProjectAssetsFile)' == '' ">$(MSBuildThisFileDirectory)project.assets.json</ProjectAssetsFile>
<NuGetPackageRoot Condition=" '$(NuGetPackageRoot)' == '' ">/Users/piotrkus/.nuget/packages/</NuGetPackageRoot>
<NuGetPackageFolders Condition=" '$(NuGetPackageFolders)' == '' ">/Users/piotrkus/.nuget/packages/</NuGetPackageFolders>
<NuGetProjectStyle Condition=" '$(NuGetProjectStyle)' == '' ">PackageReference</NuGetProjectStyle>
<NuGetToolVersion Condition=" '$(NuGetToolVersion)' == '' ">7.0.0</NuGetToolVersion>
</PropertyGroup>
<ItemGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<SourceRoot Include="/Users/piotrkus/.nuget/packages/" />
</ItemGroup>
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)microsoft.extensions.apidescription.server/10.0.0/build/Microsoft.Extensions.ApiDescription.Server.props" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.apidescription.server/10.0.0/build/Microsoft.Extensions.ApiDescription.Server.props')" />
<Import Project="$(NuGetPackageRoot)swashbuckle.aspnetcore/10.2.3/build/Swashbuckle.AspNetCore.props" Condition="Exists('$(NuGetPackageRoot)swashbuckle.aspnetcore/10.2.3/build/Swashbuckle.AspNetCore.props')" />
<Import Project="$(NuGetPackageRoot)microsoft.entityframeworkcore/10.0.4/buildTransitive/net10.0/Microsoft.EntityFrameworkCore.props" Condition="Exists('$(NuGetPackageRoot)microsoft.entityframeworkcore/10.0.4/buildTransitive/net10.0/Microsoft.EntityFrameworkCore.props')" />
</ImportGroup>
<PropertyGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<PkgMicrosoft_Extensions_ApiDescription_Server Condition=" '$(PkgMicrosoft_Extensions_ApiDescription_Server)' == '' ">/Users/piotrkus/.nuget/packages/microsoft.extensions.apidescription.server/10.0.0</PkgMicrosoft_Extensions_ApiDescription_Server>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Condition=" '$(ExcludeRestorePackageImports)' != 'true' ">
<Import Project="$(NuGetPackageRoot)microsoft.extensions.apidescription.server/10.0.0/build/Microsoft.Extensions.ApiDescription.Server.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.extensions.apidescription.server/10.0.0/build/Microsoft.Extensions.ApiDescription.Server.targets')" />
<Import Project="$(NuGetPackageRoot)microsoft.aspnetcore.openapi/10.0.5/build/Microsoft.AspNetCore.OpenApi.targets" Condition="Exists('$(NuGetPackageRoot)microsoft.aspnetcore.openapi/10.0.5/build/Microsoft.AspNetCore.OpenApi.targets')" />
</ImportGroup>
</Project>

View File

@@ -0,0 +1,4 @@
// <autogenerated />
using System;
using System.Reflection;
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v10.0", FrameworkDisplayName = ".NET 10.0")]

View File

@@ -0,0 +1,22 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("Bookie.Api")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
[assembly: System.Reflection.AssemblyProductAttribute("Bookie.Api")]
[assembly: System.Reflection.AssemblyTitleAttribute("Bookie.Api")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
// Wygenerowane przez klasę WriteCodeFragment programu MSBuild.

View File

@@ -0,0 +1 @@
4fc81d774ab6d58ec2f5cfd891c0c9002b7dda1a7354ee0fe29263e467485d10

View File

@@ -0,0 +1,23 @@
is_global = true
build_property.TargetFramework = net10.0
build_property.TargetFrameworkIdentifier = .NETCoreApp
build_property.TargetFrameworkVersion = v10.0
build_property.TargetPlatformMinVersion =
build_property.UsingMicrosoftNETSdkWeb = true
build_property.ProjectTypeGuids =
build_property.InvariantGlobalization =
build_property.PlatformNeutralAssembly =
build_property.EnforceExtendedAnalyzerRules =
build_property._SupportedPlatformList = Linux,macOS,Windows
build_property.RootNamespace = Bookie.Api
build_property.RootNamespace = Bookie.Api
build_property.ProjectDir = /Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/
build_property.EnableComHosting =
build_property.EnableGeneratedComInterfaceComImportInterop =
build_property.RazorLangVersion = 9.0
build_property.SupportLocalizedComponentNames =
build_property.GenerateRazorMetadataSourceChecksumAttributes =
build_property.MSBuildProjectDirectory = /Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api
build_property._RazorSourceGeneratorDebug =
build_property.EffectiveAnalysisLevelStyle = 10.0
build_property.EnableCodeStyleSeverity =

View File

@@ -0,0 +1,17 @@
// <auto-generated/>
global using Microsoft.AspNetCore.Builder;
global using Microsoft.AspNetCore.Hosting;
global using Microsoft.AspNetCore.Http;
global using Microsoft.AspNetCore.Routing;
global using Microsoft.Extensions.Configuration;
global using Microsoft.Extensions.DependencyInjection;
global using Microsoft.Extensions.Hosting;
global using Microsoft.Extensions.Logging;
global using System;
global using System.Collections.Generic;
global using System.IO;
global using System.Linq;
global using System.Net.Http;
global using System.Net.Http.Json;
global using System.Threading;
global using System.Threading.Tasks;

View File

@@ -0,0 +1,17 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Reflection;
[assembly: Microsoft.AspNetCore.Mvc.ApplicationParts.ApplicationPartAttribute("Microsoft.AspNetCore.OpenApi")]
[assembly: Microsoft.AspNetCore.Mvc.ApplicationParts.ApplicationPartAttribute("Swashbuckle.AspNetCore.SwaggerGen")]
// Wygenerowane przez klasę WriteCodeFragment programu MSBuild.

View File

@@ -0,0 +1 @@
5ae2b5be8cc6a3e3a10f34a5ec8779192f9fa4c51ff5cf9e637d4435d882f03a

View File

@@ -0,0 +1,56 @@
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/obj/Debug/net10.0/Bookie.Api.csproj.AssemblyReference.cache
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/obj/Debug/net10.0/rpswa.dswa.cache.json
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/obj/Debug/net10.0/Bookie.Api.GeneratedMSBuildEditorConfig.editorconfig
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/obj/Debug/net10.0/Bookie.Api.AssemblyInfoInputs.cache
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/obj/Debug/net10.0/Bookie.Api.AssemblyInfo.cs
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/obj/Debug/net10.0/Bookie.Api.csproj.CoreCompileInputs.cache
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/obj/Debug/net10.0/Bookie.Api.MvcApplicationPartsAssemblyInfo.cs
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/obj/Debug/net10.0/Bookie.Api.MvcApplicationPartsAssemblyInfo.cache
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/appsettings.Development.json
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/appsettings.json
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Bookie.Api.staticwebassets.endpoints.json
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Bookie.Api
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Bookie.Api.deps.json
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Bookie.Api.runtimeconfig.json
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Bookie.Api.dll
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Bookie.Api.pdb
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Microsoft.AspNetCore.Authentication.JwtBearer.dll
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Microsoft.AspNetCore.OpenApi.dll
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Microsoft.Bcl.Cryptography.dll
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Microsoft.EntityFrameworkCore.dll
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Microsoft.EntityFrameworkCore.Abstractions.dll
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Microsoft.EntityFrameworkCore.Relational.dll
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Microsoft.IdentityModel.Abstractions.dll
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Microsoft.IdentityModel.JsonWebTokens.dll
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Microsoft.IdentityModel.Logging.dll
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Microsoft.IdentityModel.Protocols.dll
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Microsoft.IdentityModel.Protocols.OpenIdConnect.dll
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Microsoft.IdentityModel.Tokens.dll
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Microsoft.OpenApi.dll
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Npgsql.dll
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Npgsql.EntityFrameworkCore.PostgreSQL.dll
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Swashbuckle.AspNetCore.Swagger.dll
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Swashbuckle.AspNetCore.SwaggerGen.dll
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Swashbuckle.AspNetCore.SwaggerUI.dll
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/System.IdentityModel.Tokens.Jwt.dll
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Bookie.Application.dll
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Bookie.Domain.dll
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Bookie.Infrastructure.dll
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Bookie.Application.pdb
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Bookie.Infrastructure.pdb
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/bin/Debug/net10.0/Bookie.Domain.pdb
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/obj/Debug/net10.0/rjimswa.dswa.cache.json
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/obj/Debug/net10.0/rjsmrazor.dswa.cache.json
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/obj/Debug/net10.0/rjsmcshtml.dswa.cache.json
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/obj/Debug/net10.0/scopedcss/bundle/Bookie.Api.styles.css
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/obj/Debug/net10.0/staticwebassets.build.json
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/obj/Debug/net10.0/staticwebassets.build.json.cache
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/obj/Debug/net10.0/staticwebassets.development.json
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/obj/Debug/net10.0/staticwebassets.build.endpoints.json
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/obj/Debug/net10.0/swae.build.ex.cache
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/obj/Debug/net10.0/Bookie.Api.csproj.Up2Date
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/obj/Debug/net10.0/Bookie.Api.dll
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/obj/Debug/net10.0/refint/Bookie.Api.dll
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/obj/Debug/net10.0/Bookie.Api.pdb
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/obj/Debug/net10.0/Bookie.Api.genruntimeconfig.cache
/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/obj/Debug/net10.0/ref/Bookie.Api.dll

View File

@@ -0,0 +1 @@
cddcce6beb97e0bfc8ebcba4b25f88f98a30040bd901e9eb5929f5bdc81f63f9

Binary file not shown.

View File

@@ -0,0 +1 @@
{"GlobalPropertiesHash":"SvmDNfl8WQF88sx+vTdWGJr/vNyTwFGKhlVC7sbeXZs=","FingerprintPatternsHash":"gq3WsqcKBUGTSNle7RKKyXRIwh7M8ccEqOqYvIzoM04=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["f0WMuA/835Lw35cdDhIgIqgzYv59afVE5VC7LS0JcOo=","e7BRcd/mzmhWN7nYWcmTjnwkfIJqxFqzPJN0ztL36kM=","PhXnjRTCI4ADbsQ9bSfv9OPJ17wsbcUmKkid6BNs7k0=","7vVwO6mZH/kl4UW4piEMre05xG3VDfslTXc8Lt9ZN0o=","G2E/I7iGdG9Uxgjg5HGsz85oSVdsgK5EXdhuYJ4/7vg="],"CachedAssets":{},"CachedCopyCandidates":{}}

View File

@@ -0,0 +1 @@
{"GlobalPropertiesHash":"7Ya2IK3+v0qPRwSRcQNiopfKEqpuNV8pucv69r0U/Y4=","FingerprintPatternsHash":"gq3WsqcKBUGTSNle7RKKyXRIwh7M8ccEqOqYvIzoM04=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["f0WMuA/835Lw35cdDhIgIqgzYv59afVE5VC7LS0JcOo=","e7BRcd/mzmhWN7nYWcmTjnwkfIJqxFqzPJN0ztL36kM=","PhXnjRTCI4ADbsQ9bSfv9OPJ17wsbcUmKkid6BNs7k0=","7vVwO6mZH/kl4UW4piEMre05xG3VDfslTXc8Lt9ZN0o=","G2E/I7iGdG9Uxgjg5HGsz85oSVdsgK5EXdhuYJ4/7vg="],"CachedAssets":{},"CachedCopyCandidates":{}}

View File

@@ -0,0 +1 @@
{"GlobalPropertiesHash":"sMy6sPK/gjym1Pxbp7fAZ0VsmoxPjNiJRRqFJXCEqj4=","FingerprintPatternsHash":"gq3WsqcKBUGTSNle7RKKyXRIwh7M8ccEqOqYvIzoM04=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["f0WMuA/835Lw35cdDhIgIqgzYv59afVE5VC7LS0JcOo=","e7BRcd/mzmhWN7nYWcmTjnwkfIJqxFqzPJN0ztL36kM="],"CachedAssets":{},"CachedCopyCandidates":{}}

View File

@@ -0,0 +1 @@
{"Version":1,"ManifestType":"Build","Endpoints":[]}

View File

@@ -0,0 +1 @@
{"Version":1,"Hash":"XdCB9qewGnfYmvHkbdmi0g4n+9B6mz3+996yG6Okdp0=","Source":"Bookie.Api","BasePath":"/","Mode":"Root","ManifestType":"Build","ReferencedProjectsConfiguration":[],"DiscoveryPatterns":[],"Assets":[],"Endpoints":[]}

View File

@@ -0,0 +1 @@
XdCB9qewGnfYmvHkbdmi0g4n+9B6mz3+996yG6Okdp0=

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,31 @@
{
"version": 2,
"dgSpecHash": "6zTNoRKMU/A=",
"success": true,
"projectFilePath": "/Users/piotrkus/RiderProjects/Bookie/BookieApi/src/Bookie.Api/Bookie.Api.csproj",
"expectedPackageFiles": [
"/Users/piotrkus/.nuget/packages/microsoft.aspnetcore.authentication.jwtbearer/10.0.11/microsoft.aspnetcore.authentication.jwtbearer.10.0.11.nupkg.sha512",
"/Users/piotrkus/.nuget/packages/microsoft.aspnetcore.openapi/10.0.5/microsoft.aspnetcore.openapi.10.0.5.nupkg.sha512",
"/Users/piotrkus/.nuget/packages/microsoft.bcl.cryptography/10.0.2/microsoft.bcl.cryptography.10.0.2.nupkg.sha512",
"/Users/piotrkus/.nuget/packages/microsoft.entityframeworkcore/10.0.4/microsoft.entityframeworkcore.10.0.4.nupkg.sha512",
"/Users/piotrkus/.nuget/packages/microsoft.entityframeworkcore.abstractions/10.0.4/microsoft.entityframeworkcore.abstractions.10.0.4.nupkg.sha512",
"/Users/piotrkus/.nuget/packages/microsoft.entityframeworkcore.analyzers/10.0.4/microsoft.entityframeworkcore.analyzers.10.0.4.nupkg.sha512",
"/Users/piotrkus/.nuget/packages/microsoft.entityframeworkcore.relational/10.0.4/microsoft.entityframeworkcore.relational.10.0.4.nupkg.sha512",
"/Users/piotrkus/.nuget/packages/microsoft.extensions.apidescription.server/10.0.0/microsoft.extensions.apidescription.server.10.0.0.nupkg.sha512",
"/Users/piotrkus/.nuget/packages/microsoft.identitymodel.abstractions/8.22.0/microsoft.identitymodel.abstractions.8.22.0.nupkg.sha512",
"/Users/piotrkus/.nuget/packages/microsoft.identitymodel.jsonwebtokens/8.22.0/microsoft.identitymodel.jsonwebtokens.8.22.0.nupkg.sha512",
"/Users/piotrkus/.nuget/packages/microsoft.identitymodel.logging/8.22.0/microsoft.identitymodel.logging.8.22.0.nupkg.sha512",
"/Users/piotrkus/.nuget/packages/microsoft.identitymodel.protocols/8.19.2/microsoft.identitymodel.protocols.8.19.2.nupkg.sha512",
"/Users/piotrkus/.nuget/packages/microsoft.identitymodel.protocols.openidconnect/8.19.2/microsoft.identitymodel.protocols.openidconnect.8.19.2.nupkg.sha512",
"/Users/piotrkus/.nuget/packages/microsoft.identitymodel.tokens/8.22.0/microsoft.identitymodel.tokens.8.22.0.nupkg.sha512",
"/Users/piotrkus/.nuget/packages/microsoft.openapi/2.7.5/microsoft.openapi.2.7.5.nupkg.sha512",
"/Users/piotrkus/.nuget/packages/npgsql/10.0.3/npgsql.10.0.3.nupkg.sha512",
"/Users/piotrkus/.nuget/packages/npgsql.entityframeworkcore.postgresql/10.0.3/npgsql.entityframeworkcore.postgresql.10.0.3.nupkg.sha512",
"/Users/piotrkus/.nuget/packages/swashbuckle.aspnetcore/10.2.3/swashbuckle.aspnetcore.10.2.3.nupkg.sha512",
"/Users/piotrkus/.nuget/packages/swashbuckle.aspnetcore.swagger/10.2.3/swashbuckle.aspnetcore.swagger.10.2.3.nupkg.sha512",
"/Users/piotrkus/.nuget/packages/swashbuckle.aspnetcore.swaggergen/10.2.3/swashbuckle.aspnetcore.swaggergen.10.2.3.nupkg.sha512",
"/Users/piotrkus/.nuget/packages/swashbuckle.aspnetcore.swaggerui/10.2.3/swashbuckle.aspnetcore.swaggerui.10.2.3.nupkg.sha512",
"/Users/piotrkus/.nuget/packages/system.identitymodel.tokens.jwt/8.22.0/system.identitymodel.tokens.jwt.8.22.0.nupkg.sha512"
],
"logs": []
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
17891904138499975

View File

@@ -0,0 +1 @@
17891904138499975

View File

@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\Bookie.Domain\Bookie.Domain.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.11" />
</ItemGroup>
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,17 @@
using System.ComponentModel.DataAnnotations;
namespace Bookie.Application.DTOs.Auth;
public class LoginRequestDto
{
[Required] public string Username { get; set; } = "";
[Required] public string Password { get; set; } = "";
}
public class AuthResponseDto
{
public string Token { get; set; } = "";
public string Username { get; set; } = "";
public string Role { get; set; } = "";
public DateTime ExpiresAt { get; set; }
}

View File

@@ -0,0 +1,8 @@
namespace Bookie.Application.DTOs.Common;
/// <summary>A minimal id/name pair for populating dropdowns in forms.</summary>
public class LookupDto
{
public int Id { get; set; }
public string Name { get; set; } = "";
}

View File

@@ -0,0 +1,64 @@
namespace Bookie.Application.DTOs.Common;
/// <summary>A page of results plus total count for server-side paging.</summary>
public class PagedResult<T>
{
public IReadOnlyList<T> Items { get; set; } = new List<T>();
public int TotalCount { get; set; }
public int Page { get; set; }
public int PageSize { get; set; }
public int TotalPages => PageSize > 0 ? (int)Math.Ceiling(TotalCount / (double)PageSize) : 0;
}
/// <summary>Common query parameters for list endpoints (paging / sorting / filtering).</summary>
public class PagedQuery
{
private const int MaxPageSize = 200;
private int _pageSize = 20;
private int _page = 1;
public int Page
{
get => _page;
set => _page = value < 1 ? 1 : value;
}
public int PageSize
{
get => _pageSize;
set => _pageSize = value is < 1 or > MaxPageSize ? 20 : value;
}
/// <summary>Free-text search term (interpreted per endpoint).</summary>
public string? Search { get; set; }
/// <summary>Field name to sort by (interpreted per endpoint).</summary>
public string? SortBy { get; set; }
/// <summary>True for descending order.</summary>
public bool SortDesc { get; set; }
/// <summary>
/// Per-column filters as repeated <c>Filters=key:value</c> query parameters
/// (e.g. <c>?Filters=status:finished&amp;Filters=teamId:41</c>). Keys are interpreted per endpoint.
/// </summary>
public List<string> Filters { get; set; } = new();
private Dictionary<string, string>? _parsed;
/// <summary>Returns the trimmed filter value for <paramref name="key"/>, or null when absent/blank.</summary>
public string? Filter(string key)
{
if (_parsed is null)
{
_parsed = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
foreach (var entry in Filters)
{
var idx = entry.IndexOf(':');
if (idx <= 0) continue;
_parsed[entry[..idx]] = entry[(idx + 1)..];
}
}
return _parsed.TryGetValue(key, out var v) && !string.IsNullOrWhiteSpace(v) ? v.Trim() : null;
}
}

View File

@@ -0,0 +1,37 @@
using System.ComponentModel.DataAnnotations;
namespace Bookie.Application.DTOs.Contracts;
public class PlayerContractDto
{
public int ContractId { get; set; }
public int PlayerId { get; set; }
public string PlayerName { get; set; } = "";
public int TeamId { get; set; }
public string TeamName { get; set; } = "";
public short? ShirtNumber { get; set; }
public DateOnly StartDate { get; set; }
public DateOnly? EndDate { get; set; }
public bool IsCurrent => EndDate is null;
}
public class PlayerContractCreateDto : IValidatableObject
{
[Required] public int PlayerId { get; set; }
[Required] public int TeamId { get; set; }
[Range(1, 99)]
public short? ShirtNumber { get; set; }
[Required] public DateOnly StartDate { get; set; }
public DateOnly? EndDate { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (EndDate.HasValue && EndDate.Value < StartDate)
yield return new ValidationResult("End date cannot be before start date.",
new[] { nameof(EndDate) });
}
}
public class PlayerContractUpdateDto : PlayerContractCreateDto { }

View File

@@ -0,0 +1,31 @@
namespace Bookie.Application.DTOs.Dashboard;
public class DashboardSummaryDto
{
public int LeagueCount { get; set; }
public int SeasonCount { get; set; }
public int TeamCount { get; set; }
public int PlayerCount { get; set; }
public int MatchCount { get; set; }
public int UpcomingMatchesThisWeek { get; set; }
public int FinishedMatches { get; set; }
public List<UpcomingMatchDto> NextMatches { get; set; } = new();
public List<StatusBreakdownDto> StatusBreakdown { get; set; } = new();
}
public class UpcomingMatchDto
{
public int MatchId { get; set; }
public DateTime KickoffAt { get; set; }
public string HomeTeamName { get; set; } = "";
public string AwayTeamName { get; set; } = "";
public string LeagueName { get; set; } = "";
public string Country { get; set; } = "";
public string Status { get; set; } = "";
}
public class StatusBreakdownDto
{
public string Status { get; set; } = "";
public int Count { get; set; }
}

Some files were not shown because too many files have changed in this diff Show More