refactor: decouple scoreboard api logic

Now scoreboard business logic is in ScoreboardService.cs and scoreboard api login is in ScoreboardController.cs
This commit is contained in:
cuqmbr 2022-07-16 16:34:26 +03:00
parent 352a5c89ba
commit 4adf64d129
5 changed files with 117 additions and 30 deletions

1
.gitignore vendored
View File

@ -454,3 +454,4 @@ $RECYCLE.BIN/
!.vscode/extensions.json
*.db
*.db*

View File

@ -1,33 +1,35 @@
using DatabaseModels;
using System.Data;
using DatabaseModels.Plain;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Server.Data;
using Server.Services;
namespace Server.Controllers;
[Route("api/[controller]")]
[Route("[controller]")]
[ApiController]
public class ScoreboardController : ControllerBase
{
private readonly ServerDbContext _context;
private readonly ScoreboardService _sbService;
public ScoreboardController(ServerDbContext context)
public ScoreboardController(ScoreboardService sbService)
{
_context = context;
_sbService = sbService;
}
// GET: api/Scoreboard
// GET: /scoreboard
[HttpGet]
public async Task<ActionResult<ScoreboardRecord[]>> Get()
{
return await _context.Scoreboard.ToArrayAsync();
return await _sbService.GetScoreboard();
}
// GET: api/Scoreboard/cuqmbr
// GET: /scoreboard/cuqmbr
[HttpGet("{username}", Name = "Get")]
public async Task<ActionResult<ScoreboardRecord>> Get(string username)
{
var sbRecord = await _context.Scoreboard.FirstOrDefaultAsync(sbr => sbr.Username == username);
var sbRecord = await _sbService.GetUserHighScore(username);
if (sbRecord == null)
{
@ -37,46 +39,50 @@ public class ScoreboardController : ControllerBase
return sbRecord;
}
// POST: api/Scoreboard
// POST: /scoreboard
[HttpPost]
public async Task<ActionResult> Post([FromBody] ScoreboardRecord sbRecord)
{
await _context.AddAsync(sbRecord);
await _context.SaveChangesAsync();
return CreatedAtAction(nameof(Get), new {sbRecord.Username}, sbRecord);
await _sbService.AddUserHighScore(sbRecord);
return CreatedAtAction(nameof(Get), new {sbRecord.User}, sbRecord);
}
// PUT: api/Scoreboard/cuqmbr
[HttpPut("{username}")]
public async Task<ActionResult> Put(string username, [FromBody] ScoreboardRecord sbRecord)
// PUT: /scoreboard/id
[HttpPut("{id}", Name = "Put")]
public async Task<ActionResult<ScoreboardRecord>> Put(int id, [FromBody] ScoreboardRecord sbRecord)
{
if (username != sbRecord.Username)
if (id != sbRecord.Id)
{
return BadRequest();
}
_context.Entry(sbRecord).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
await _sbService.UpdateScoreboardRecord(sbRecord);
}
catch (DbUpdateConcurrencyException)
catch (DBConcurrencyException)
{
if (!await ScoreboardRecordExists(sbRecord.Username))
if (!await _sbService.ScoreboardRecordExists(id))
{
return NotFound();
}
throw;
}
return NoContent();
}
private async Task<bool> ScoreboardRecordExists(string username)
// DELETE: /scoreboard/id
[HttpDelete("{id}", Name = "Delete")]
public async Task<ActionResult> Delete(int id)
{
return await _context.Scoreboard.AnyAsync(sbr => sbr.Username == username);
if (!await _sbService.ScoreboardRecordExists(id))
{
return NotFound();
}
await _sbService.DeleteScoreboardRecord(id);
return NoContent();
}
}

View File

@ -1,15 +1,23 @@
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Server.Data;
using Server.Services;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddControllers().AddNewtonsoftJson(o => {
o.SerializerSettings.ContractResolver = new DefaultContractResolver();
o.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddDbContext<ServerDbContext>(o => o.UseSqlite(builder.Configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddDbContext<ServerDbContext>(o =>
o.UseSqlite(builder.Configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddScoped<ScoreboardService>();
var app = builder.Build();

View File

@ -7,6 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.6">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

View File

@ -0,0 +1,71 @@
using DatabaseModels.Plain;
using Microsoft.EntityFrameworkCore;
using Server.Data;
namespace Server.Services;
public class ScoreboardService
{
private readonly ServerDbContext _dbContext;
public ScoreboardService(ServerDbContext dbContext)
{
_dbContext = dbContext;
}
// GET
public async Task<ScoreboardRecord[]> GetScoreboard()
{
var sbRecords = await _dbContext.Scoreboard
.Include(sbr => sbr.User)
.ToListAsync();
sbRecords.Sort((a, b) => b.Score - a.Score);
return sbRecords.DistinctBy(sbr => sbr.User.Id).ToArray();
}
public async Task<ScoreboardRecord?> GetUserHighScore(string username)
{
var userScoreboardRecords = await _dbContext.Scoreboard
.Include(sbr => sbr.User)
.Where(sbr => sbr.User.Username == username)
.ToListAsync();
return userScoreboardRecords.MaxBy(sbr => sbr.Score);
}
// POST
public async Task AddUserHighScore(ScoreboardRecord sbRecord)
{
var dbUser = await _dbContext.Users.FindAsync(sbRecord.User.Id);
sbRecord.User = dbUser;
await _dbContext.AddAsync(sbRecord);
await _dbContext.SaveChangesAsync();
}
// PUT
public async Task UpdateScoreboardRecord(ScoreboardRecord sbRecord)
{
_dbContext.Entry(sbRecord).State = EntityState.Modified;
await _dbContext.SaveChangesAsync();
}
public async Task<bool> ScoreboardRecordExists(int id)
{
return await _dbContext.Scoreboard.AnyAsync(sbr => sbr.Id == id);
}
// DELETE
public async Task DeleteScoreboardRecord(int id)
{
var sbRecord = await _dbContext.Scoreboard.FindAsync(id);
_dbContext.Scoreboard.Remove(sbRecord!);
await _dbContext.SaveChangesAsync();
}
}