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