From cca72cf225023d0762fec5586c20bca2a022a5af Mon Sep 17 00:00:00 2001 From: exsersewo Date: Thu, 3 Nov 2022 21:15:20 +0000 Subject: [PATCH] Init Commit --- .gitignore | 5 + .idea/.idea.DreamsCaster/.idea/.gitignore | 13 ++ .../.idea.DreamsCaster/.idea/indexLayout.xml | 8 + .idea/.idea.DreamsCaster/.idea/vcs.xml | 6 + DreamsCaster.sln | 16 ++ DreamsCaster/.dockerignore | 25 +++ DreamsCaster/AppDbContext.cs | 26 +++ DreamsCaster/Controllers/ConsoleController.cs | 90 ++++++++ DreamsCaster/Controllers/GameController.cs | 192 ++++++++++++++++++ DreamsCaster/Dockerfile | 20 ++ DreamsCaster/DreamsCaster.csproj | 17 ++ DreamsCaster/Helpers/Optional.cs | 15 ++ DreamsCaster/Models/Common.cs | 17 ++ DreamsCaster/Models/Console.cs | 10 + DreamsCaster/Models/Game.cs | 10 + DreamsCaster/Models/Release.cs | 19 ++ DreamsCaster/Program.cs | 25 +++ DreamsCaster/Properties/launchSettings.json | 31 +++ DreamsCaster/appsettings.Development.json | 8 + DreamsCaster/appsettings.json | 9 + 20 files changed, 562 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.idea.DreamsCaster/.idea/.gitignore create mode 100644 .idea/.idea.DreamsCaster/.idea/indexLayout.xml create mode 100644 .idea/.idea.DreamsCaster/.idea/vcs.xml create mode 100644 DreamsCaster.sln create mode 100644 DreamsCaster/.dockerignore create mode 100644 DreamsCaster/AppDbContext.cs create mode 100644 DreamsCaster/Controllers/ConsoleController.cs create mode 100644 DreamsCaster/Controllers/GameController.cs create mode 100644 DreamsCaster/Dockerfile create mode 100644 DreamsCaster/DreamsCaster.csproj create mode 100644 DreamsCaster/Helpers/Optional.cs create mode 100644 DreamsCaster/Models/Common.cs create mode 100644 DreamsCaster/Models/Console.cs create mode 100644 DreamsCaster/Models/Game.cs create mode 100644 DreamsCaster/Models/Release.cs create mode 100644 DreamsCaster/Program.cs create mode 100644 DreamsCaster/Properties/launchSettings.json create mode 100644 DreamsCaster/appsettings.Development.json create mode 100644 DreamsCaster/appsettings.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..add57be --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +bin/ +obj/ +/packages/ +riderModule.iml +/_ReSharper.Caches/ \ No newline at end of file diff --git a/.idea/.idea.DreamsCaster/.idea/.gitignore b/.idea/.idea.DreamsCaster/.idea/.gitignore new file mode 100644 index 0000000..7c8b529 --- /dev/null +++ b/.idea/.idea.DreamsCaster/.idea/.gitignore @@ -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 diff --git a/.idea/.idea.DreamsCaster/.idea/indexLayout.xml b/.idea/.idea.DreamsCaster/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/.idea/.idea.DreamsCaster/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.DreamsCaster/.idea/vcs.xml b/.idea/.idea.DreamsCaster/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/.idea.DreamsCaster/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/DreamsCaster.sln b/DreamsCaster.sln new file mode 100644 index 0000000..84d03bb --- /dev/null +++ b/DreamsCaster.sln @@ -0,0 +1,16 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DreamsCaster", "DreamsCaster\DreamsCaster.csproj", "{7EF668EB-6D79-4A51-A161-F4E99DCCD789}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7EF668EB-6D79-4A51-A161-F4E99DCCD789}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7EF668EB-6D79-4A51-A161-F4E99DCCD789}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7EF668EB-6D79-4A51-A161-F4E99DCCD789}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7EF668EB-6D79-4A51-A161-F4E99DCCD789}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/DreamsCaster/.dockerignore b/DreamsCaster/.dockerignore new file mode 100644 index 0000000..cd967fc --- /dev/null +++ b/DreamsCaster/.dockerignore @@ -0,0 +1,25 @@ +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/.idea +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md \ No newline at end of file diff --git a/DreamsCaster/AppDbContext.cs b/DreamsCaster/AppDbContext.cs new file mode 100644 index 0000000..649848f --- /dev/null +++ b/DreamsCaster/AppDbContext.cs @@ -0,0 +1,26 @@ +using DreamsCaster.Models; +using Microsoft.EntityFrameworkCore; +using Console = DreamsCaster.Models.Console; + +namespace DreamsCaster; + +public class AppDbContext : DbContext +{ + public DbSet Games; + public DbSet Consoles; +} + +public static class DatabaseExtensions +{ + public static bool TryGet(this IEnumerable 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; + } +} \ No newline at end of file diff --git a/DreamsCaster/Controllers/ConsoleController.cs b/DreamsCaster/Controllers/ConsoleController.cs new file mode 100644 index 0000000..e614dd6 --- /dev/null +++ b/DreamsCaster/Controllers/ConsoleController.cs @@ -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 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 PatchAsync([FromQuery] Guid consoleId) + { + + } + + [HttpPost] + [Authorize] + public async Task PostAsync([FromBody] PostGame newGame) + { + try + { + var game = Database.Games.Add(new Game() + { + Name = newGame.Name, + Data = new MetaData() + { + 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); + } + } +} \ No newline at end of file diff --git a/DreamsCaster/Controllers/GameController.cs b/DreamsCaster/Controllers/GameController.cs new file mode 100644 index 0000000..62f8b37 --- /dev/null +++ b/DreamsCaster/Controllers/GameController.cs @@ -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 Releases; + } + + public class PatchGame + { + public Optional Name; + public Optional Description; + public Optional 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 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 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 PostAsync([FromBody] PostGame newGame) + { + try + { + var game = Database.Games.Add(new Game() + { + Name = newGame.Name, + Data = new MetaData() + { + 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 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 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 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 +} \ No newline at end of file diff --git a/DreamsCaster/Dockerfile b/DreamsCaster/Dockerfile new file mode 100644 index 0000000..039c1e2 --- /dev/null +++ b/DreamsCaster/Dockerfile @@ -0,0 +1,20 @@ +FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base +WORKDIR /app +EXPOSE 80 +EXPOSE 443 + +FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build +WORKDIR /src +COPY ["DreamsCaster/DreamsCaster.csproj", "DreamsCaster/"] +RUN dotnet restore "DreamsCaster/DreamsCaster.csproj" +COPY . . +WORKDIR "/src/DreamsCaster" +RUN dotnet build "DreamsCaster.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "DreamsCaster.csproj" -c Release -o /app/publish + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "DreamsCaster.dll"] diff --git a/DreamsCaster/DreamsCaster.csproj b/DreamsCaster/DreamsCaster.csproj new file mode 100644 index 0000000..9d1fd9e --- /dev/null +++ b/DreamsCaster/DreamsCaster.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + enable + enable + Linux + + + + + + + + + + diff --git a/DreamsCaster/Helpers/Optional.cs b/DreamsCaster/Helpers/Optional.cs new file mode 100644 index 0000000..e99763d --- /dev/null +++ b/DreamsCaster/Helpers/Optional.cs @@ -0,0 +1,15 @@ +namespace DreamsCaster.Helpers; + +public struct Optional +{ + public bool HasValue; + public T Value; + + public Optional(bool hasValue, T value) + { + HasValue = hasValue; + Value = value; + } + + public static implicit operator T(Optional d) => d.HasValue ? d.Value : default; +} \ No newline at end of file diff --git a/DreamsCaster/Models/Common.cs b/DreamsCaster/Models/Common.cs new file mode 100644 index 0000000..34b7a91 --- /dev/null +++ b/DreamsCaster/Models/Common.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; + +namespace DreamsCaster.Models; + +public class IdEntity +{ + public Guid Id; +} + +public class MetaData : IdEntity +{ + public string Description; + public string CoverPhoto; + + [Required] + public virtual T Owner { get; set; } +} \ No newline at end of file diff --git a/DreamsCaster/Models/Console.cs b/DreamsCaster/Models/Console.cs new file mode 100644 index 0000000..cea502c --- /dev/null +++ b/DreamsCaster/Models/Console.cs @@ -0,0 +1,10 @@ +namespace DreamsCaster.Models; + +public class Console : IdEntity +{ + public string Name; + + public virtual ICollection Games { get; set; } + + public virtual MetaData Data { get; set; } +} \ No newline at end of file diff --git a/DreamsCaster/Models/Game.cs b/DreamsCaster/Models/Game.cs new file mode 100644 index 0000000..d754012 --- /dev/null +++ b/DreamsCaster/Models/Game.cs @@ -0,0 +1,10 @@ +namespace DreamsCaster.Models; + +public class Game : IdEntity +{ + public string Name; + + public ICollection Releases; + + public virtual MetaData Data { get; set; } +} \ No newline at end of file diff --git a/DreamsCaster/Models/Release.cs b/DreamsCaster/Models/Release.cs new file mode 100644 index 0000000..3dd84a4 --- /dev/null +++ b/DreamsCaster/Models/Release.cs @@ -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 + }; +} \ No newline at end of file diff --git a/DreamsCaster/Program.cs b/DreamsCaster/Program.cs new file mode 100644 index 0000000..381c170 --- /dev/null +++ b/DreamsCaster/Program.cs @@ -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(); \ No newline at end of file diff --git a/DreamsCaster/Properties/launchSettings.json b/DreamsCaster/Properties/launchSettings.json new file mode 100644 index 0000000..984460f --- /dev/null +++ b/DreamsCaster/Properties/launchSettings.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:1386", + "sslPort": 44381 + } + }, + "profiles": { + "DreamsCaster": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:7058;http://localhost:5273", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/DreamsCaster/appsettings.Development.json b/DreamsCaster/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/DreamsCaster/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/DreamsCaster/appsettings.json b/DreamsCaster/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/DreamsCaster/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +}