commit
cca72cf225
@ -0,0 +1,5 @@ |
|||||||
|
bin/ |
||||||
|
obj/ |
||||||
|
/packages/ |
||||||
|
riderModule.iml |
||||||
|
/_ReSharper.Caches/ |
@ -0,0 +1,13 @@ |
|||||||
|
# Default ignored files |
||||||
|
/shelf/ |
||||||
|
/workspace.xml |
||||||
|
# Rider ignored files |
||||||
|
/modules.xml |
||||||
|
/.idea.DreamsCaster.iml |
||||||
|
/contentModel.xml |
||||||
|
/projectSettingsUpdater.xml |
||||||
|
# Editor-based HTTP Client requests |
||||||
|
/httpRequests/ |
||||||
|
# Datasource local storage ignored files |
||||||
|
/dataSources/ |
||||||
|
/dataSources.local.xml |
@ -0,0 +1,8 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<project version="4"> |
||||||
|
<component name="UserContentModel"> |
||||||
|
<attachedFolders /> |
||||||
|
<explicitIncludes /> |
||||||
|
<explicitExcludes /> |
||||||
|
</component> |
||||||
|
</project> |
@ -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> |
@ -0,0 +1,26 @@ |
|||||||
|
using DreamsCaster.Models; |
||||||
|
using Microsoft.EntityFrameworkCore; |
||||||
|
using Console = DreamsCaster.Models.Console; |
||||||
|
|
||||||
|
namespace DreamsCaster; |
||||||
|
|
||||||
|
public class AppDbContext : DbContext |
||||||
|
{ |
||||||
|
public DbSet<Game> Games; |
||||||
|
public DbSet<Console> Consoles; |
||||||
|
} |
||||||
|
|
||||||
|
public static class DatabaseExtensions |
||||||
|
{ |
||||||
|
public static bool TryGet<T>(this IEnumerable<T> haystack, Guid id, out T val) where T : IdEntity |
||||||
|
{ |
||||||
|
if (haystack.Select(hay => hay.Id).Contains(id)) |
||||||
|
{ |
||||||
|
val = haystack.FirstOrDefault(hay => hay.Id.Equals(id)); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
val = null; |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,90 @@ |
|||||||
|
using DreamsCaster.Helpers; |
||||||
|
using DreamsCaster.Models; |
||||||
|
using Microsoft.AspNetCore.Authorization; |
||||||
|
using Microsoft.AspNetCore.Mvc; |
||||||
|
using Console = System.Console; |
||||||
|
|
||||||
|
namespace DreamsCaster.Controllers; |
||||||
|
|
||||||
|
[ApiController] |
||||||
|
[Route("[controller]")]
|
||||||
|
public class ConsoleController : ControllerBase |
||||||
|
{ |
||||||
|
public AppDbContext Database { get; set; } |
||||||
|
|
||||||
|
[HttpGet] |
||||||
|
public IActionResult Get([FromQuery] Guid consoleId) |
||||||
|
{ |
||||||
|
if (!Database.Consoles.TryGet(consoleId, out Game game)) return NotFound(); |
||||||
|
|
||||||
|
return Ok(game); |
||||||
|
} |
||||||
|
|
||||||
|
[HttpGet] |
||||||
|
[Authorize] |
||||||
|
public async Task<IActionResult> DeleteAsync([FromQuery] Guid consoleId) |
||||||
|
{ |
||||||
|
if (!Database.Games.TryGet(consoleId, out var game)) return NotFound(); |
||||||
|
|
||||||
|
foreach (var release in game.Releases) |
||||||
|
{ |
||||||
|
Database.Remove(release); |
||||||
|
} |
||||||
|
|
||||||
|
await Database.SaveChangesAsync(); |
||||||
|
|
||||||
|
Database.Games.Remove(game); |
||||||
|
|
||||||
|
await Database.SaveChangesAsync(); |
||||||
|
|
||||||
|
return Ok(); |
||||||
|
} |
||||||
|
|
||||||
|
[HttpPatch] |
||||||
|
[Authorize] |
||||||
|
public async Task<IActionResult> PatchAsync([FromQuery] Guid consoleId) |
||||||
|
{ |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
[HttpPost] |
||||||
|
[Authorize] |
||||||
|
public async Task<IActionResult> PostAsync([FromBody] PostGame newGame) |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
var game = Database.Games.Add(new Game() |
||||||
|
{ |
||||||
|
Name = newGame.Name, |
||||||
|
Data = new MetaData<Game>() |
||||||
|
{ |
||||||
|
CoverPhoto = newGame.CoverPhoto, |
||||||
|
Description = newGame.Description |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
await Database.SaveChangesAsync(); |
||||||
|
|
||||||
|
foreach (var release in newGame.Releases) |
||||||
|
{ |
||||||
|
if (!Database.Consoles.TryGet(release.ConsoleId, out var console)) continue; |
||||||
|
|
||||||
|
game.Entity.Releases.Add(new Release() |
||||||
|
{ |
||||||
|
ReleaseDate = release.Release, |
||||||
|
Console = console |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
await Database.SaveChangesAsync(); |
||||||
|
|
||||||
|
return Ok(game); |
||||||
|
} |
||||||
|
catch (Exception ex) |
||||||
|
{ |
||||||
|
Console.WriteLine(ex); |
||||||
|
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,192 @@ |
|||||||
|
using System.Runtime.InteropServices.ComTypes; |
||||||
|
using DreamsCaster.Helpers; |
||||||
|
using DreamsCaster.Models; |
||||||
|
using Microsoft.AspNetCore.Authorization; |
||||||
|
using Microsoft.AspNetCore.Mvc; |
||||||
|
using Console = System.Console; |
||||||
|
|
||||||
|
namespace DreamsCaster.Controllers; |
||||||
|
|
||||||
|
[ApiController] |
||||||
|
[Route("[controller]")]
|
||||||
|
public class GameController : ControllerBase |
||||||
|
{ |
||||||
|
public class PostRelease |
||||||
|
{ |
||||||
|
public DateTime Release; |
||||||
|
public Guid ConsoleId; |
||||||
|
} |
||||||
|
|
||||||
|
public class PostGame |
||||||
|
{ |
||||||
|
public string Name; |
||||||
|
public string Description; |
||||||
|
public string CoverPhoto; |
||||||
|
|
||||||
|
public List<PostRelease> Releases; |
||||||
|
} |
||||||
|
|
||||||
|
public class PatchGame |
||||||
|
{ |
||||||
|
public Optional<string> Name; |
||||||
|
public Optional<string> Description; |
||||||
|
public Optional<string> CoverPhoto; |
||||||
|
} |
||||||
|
|
||||||
|
public AppDbContext Database { get; set; } |
||||||
|
|
||||||
|
#region Game CRUD |
||||||
|
|
||||||
|
[HttpGet] |
||||||
|
public IActionResult Get([FromQuery] Guid gameId) |
||||||
|
{ |
||||||
|
if (!Database.Games.TryGet(gameId, out Game game)) return NotFound(); |
||||||
|
|
||||||
|
return Ok(game); |
||||||
|
} |
||||||
|
|
||||||
|
[HttpGet] |
||||||
|
[Authorize] |
||||||
|
public async Task<IActionResult> DeleteAsync([FromQuery] Guid gameId) |
||||||
|
{ |
||||||
|
if (!Database.Games.TryGet(gameId, out var game)) return NotFound(); |
||||||
|
|
||||||
|
foreach (var release in game.Releases) |
||||||
|
{ |
||||||
|
Database.Remove(release); |
||||||
|
} |
||||||
|
|
||||||
|
await Database.SaveChangesAsync(); |
||||||
|
|
||||||
|
Database.Games.Remove(game); |
||||||
|
|
||||||
|
await Database.SaveChangesAsync(); |
||||||
|
|
||||||
|
return Ok(); |
||||||
|
} |
||||||
|
|
||||||
|
[HttpPatch] |
||||||
|
[Authorize] |
||||||
|
public async Task<IActionResult> PatchAsync([FromQuery] Guid gameId, [FromBody] PatchGame newData) |
||||||
|
{ |
||||||
|
if (!Database.Games.TryGet(gameId, out Game game)) return NotFound(); |
||||||
|
|
||||||
|
if (newData.Name.HasValue) game.Name = newData.Name; |
||||||
|
if (newData.Description.HasValue) game.Data.Description = newData.Description; |
||||||
|
if (newData.CoverPhoto.HasValue) game.Data.CoverPhoto = newData.CoverPhoto; |
||||||
|
|
||||||
|
await Database.SaveChangesAsync(); |
||||||
|
|
||||||
|
return Ok(game); |
||||||
|
} |
||||||
|
|
||||||
|
[HttpPost] |
||||||
|
[Authorize] |
||||||
|
public async Task<IActionResult> PostAsync([FromBody] PostGame newGame) |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
var game = Database.Games.Add(new Game() |
||||||
|
{ |
||||||
|
Name = newGame.Name, |
||||||
|
Data = new MetaData<Game>() |
||||||
|
{ |
||||||
|
CoverPhoto = newGame.CoverPhoto, |
||||||
|
Description = newGame.Description |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
await Database.SaveChangesAsync(); |
||||||
|
|
||||||
|
foreach (var release in newGame.Releases) |
||||||
|
{ |
||||||
|
if (!Database.Consoles.TryGet(release.ConsoleId, out var console)) continue; |
||||||
|
|
||||||
|
game.Entity.Releases.Add(new Release() |
||||||
|
{ |
||||||
|
ReleaseDate = release.Release, |
||||||
|
Console = console |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
await Database.SaveChangesAsync(); |
||||||
|
|
||||||
|
return Ok(game); |
||||||
|
} |
||||||
|
catch (Exception ex) |
||||||
|
{ |
||||||
|
Console.WriteLine(ex); |
||||||
|
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#endregion Game CRUD |
||||||
|
|
||||||
|
#region Releases CUD |
||||||
|
|
||||||
|
[HttpPatch("{gameId:guid}/releases")] |
||||||
|
[Authorize] |
||||||
|
public async Task<IActionResult> PatchReleaseAsync([FromQuery] Guid gameId, [FromBody] PostRelease release) |
||||||
|
{ |
||||||
|
if (!Database.Games.TryGet(gameId, out Game game)) return NotFound(); |
||||||
|
if (!Database.Consoles.TryGet(release.ConsoleId, out var console)) return NotFound(); |
||||||
|
|
||||||
|
try |
||||||
|
{ |
||||||
|
game.Releases.Add(Release.New(release.Release, console)); |
||||||
|
|
||||||
|
await Database.SaveChangesAsync(); |
||||||
|
|
||||||
|
return Ok(); |
||||||
|
} |
||||||
|
catch (Exception ex) |
||||||
|
{ |
||||||
|
Console.WriteLine(ex); |
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
[HttpPut("{gameId:guid}/releases/{releaseId:guid}")] |
||||||
|
[Authorize] |
||||||
|
public async Task<IActionResult> PatchReleaseAsync([FromQuery] Guid gameId, [FromQuery] Guid releaseId, [FromBody] DateTime newReleaseDate) |
||||||
|
{ |
||||||
|
if (!Database.Games.TryGet(gameId, out Game game)) return NotFound(); |
||||||
|
if (!game.Releases.TryGet(releaseId, out var release)) return NotFound(); |
||||||
|
|
||||||
|
try |
||||||
|
{ |
||||||
|
release.ReleaseDate = newReleaseDate; |
||||||
|
|
||||||
|
await Database.SaveChangesAsync(); |
||||||
|
|
||||||
|
return Ok(); |
||||||
|
} |
||||||
|
catch (Exception ex) |
||||||
|
{ |
||||||
|
Console.WriteLine(ex); |
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
[HttpDelete("{gameId:guid}/releases/{releaseId:guid}")] |
||||||
|
[Authorize] |
||||||
|
public async Task<IActionResult> DeleteReleaseAsync([FromQuery] Guid gameId, [FromQuery] Guid releaseId) |
||||||
|
{ |
||||||
|
if (!Database.Games.TryGet(gameId, out Game game)) return NotFound(); |
||||||
|
if (!game.Releases.TryGet(releaseId, out Release release)) return NotFound(); |
||||||
|
|
||||||
|
try |
||||||
|
{ |
||||||
|
game.Releases.Remove(release); |
||||||
|
return Ok(); |
||||||
|
} |
||||||
|
catch (Exception ex) |
||||||
|
{ |
||||||
|
Console.WriteLine(ex); |
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#endregion Releases CUD |
||||||
|
} |
@ -0,0 +1,17 @@ |
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web"> |
||||||
|
|
||||||
|
<PropertyGroup> |
||||||
|
<TargetFramework>net6.0</TargetFramework> |
||||||
|
<Nullable>enable</Nullable> |
||||||
|
<ImplicitUsings>enable</ImplicitUsings> |
||||||
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS> |
||||||
|
</PropertyGroup> |
||||||
|
|
||||||
|
<ItemGroup> |
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.10" /> |
||||||
|
<PackageReference Include="PagedList.EntityFramework" Version="1.0.1" /> |
||||||
|
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.2" /> |
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" /> |
||||||
|
</ItemGroup> |
||||||
|
|
||||||
|
</Project> |
@ -0,0 +1,15 @@ |
|||||||
|
namespace DreamsCaster.Helpers; |
||||||
|
|
||||||
|
public struct Optional<T> |
||||||
|
{ |
||||||
|
public bool HasValue; |
||||||
|
public T Value; |
||||||
|
|
||||||
|
public Optional(bool hasValue, T value) |
||||||
|
{ |
||||||
|
HasValue = hasValue; |
||||||
|
Value = value; |
||||||
|
} |
||||||
|
|
||||||
|
public static implicit operator T(Optional<T> d) => d.HasValue ? d.Value : default; |
||||||
|
} |
@ -0,0 +1,17 @@ |
|||||||
|
using System.ComponentModel.DataAnnotations; |
||||||
|
|
||||||
|
namespace DreamsCaster.Models; |
||||||
|
|
||||||
|
public class IdEntity |
||||||
|
{ |
||||||
|
public Guid Id; |
||||||
|
} |
||||||
|
|
||||||
|
public class MetaData<T> : IdEntity |
||||||
|
{ |
||||||
|
public string Description; |
||||||
|
public string CoverPhoto; |
||||||
|
|
||||||
|
[Required] |
||||||
|
public virtual T Owner { get; set; } |
||||||
|
} |
@ -0,0 +1,10 @@ |
|||||||
|
namespace DreamsCaster.Models; |
||||||
|
|
||||||
|
public class Console : IdEntity |
||||||
|
{ |
||||||
|
public string Name; |
||||||
|
|
||||||
|
public virtual ICollection<Game> Games { get; set; } |
||||||
|
|
||||||
|
public virtual MetaData<Console> Data { get; set; } |
||||||
|
} |
@ -0,0 +1,10 @@ |
|||||||
|
namespace DreamsCaster.Models; |
||||||
|
|
||||||
|
public class Game : IdEntity |
||||||
|
{ |
||||||
|
public string Name; |
||||||
|
|
||||||
|
public ICollection<Release> Releases; |
||||||
|
|
||||||
|
public virtual MetaData<Game> Data { get; set; } |
||||||
|
} |
@ -0,0 +1,19 @@ |
|||||||
|
using System.ComponentModel.DataAnnotations; |
||||||
|
|
||||||
|
namespace DreamsCaster.Models; |
||||||
|
|
||||||
|
public class Release : IdEntity |
||||||
|
{ |
||||||
|
public DateTime ReleaseDate; |
||||||
|
|
||||||
|
[Required] |
||||||
|
public virtual Game Game { get; set; } |
||||||
|
[Required] |
||||||
|
public virtual Console Console { get; set; } |
||||||
|
|
||||||
|
public static Release New(DateTime date, Console console) |
||||||
|
=> new() |
||||||
|
{ |
||||||
|
ReleaseDate = date, Console = console |
||||||
|
}; |
||||||
|
} |
@ -0,0 +1,25 @@ |
|||||||
|
var builder = WebApplication.CreateBuilder(args); |
||||||
|
|
||||||
|
// Add services to the container. |
||||||
|
|
||||||
|
builder.Services.AddControllers(); |
||||||
|
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle |
||||||
|
builder.Services.AddEndpointsApiExplorer(); |
||||||
|
builder.Services.AddSwaggerGen(); |
||||||
|
|
||||||
|
var app = builder.Build(); |
||||||
|
|
||||||
|
// Configure the HTTP request pipeline. |
||||||
|
if (app.Environment.IsDevelopment()) |
||||||
|
{ |
||||||
|
app.UseSwagger(); |
||||||
|
app.UseSwaggerUI(); |
||||||
|
} |
||||||
|
|
||||||
|
app.UseHttpsRedirection(); |
||||||
|
|
||||||
|
app.UseAuthorization(); |
||||||
|
|
||||||
|
app.MapControllers(); |
||||||
|
|
||||||
|
app.Run(); |
@ -0,0 +1,8 @@ |
|||||||
|
{ |
||||||
|
"Logging": { |
||||||
|
"LogLevel": { |
||||||
|
"Default": "Information", |
||||||
|
"Microsoft.AspNetCore": "Warning" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,9 @@ |
|||||||
|
{ |
||||||
|
"Logging": { |
||||||
|
"LogLevel": { |
||||||
|
"Default": "Information", |
||||||
|
"Microsoft.AspNetCore": "Warning" |
||||||
|
} |
||||||
|
}, |
||||||
|
"AllowedHosts": "*" |
||||||
|
} |
Loading…
Reference in new issue