From b7c221d76586f57ddc7fd6a0f624194b17591576 Mon Sep 17 00:00:00 2001 From: hz Date: Thu, 21 Aug 2025 00:28:45 -0500 Subject: [PATCH] Having the clear locations endpoint only clear world locations, and adding endpoint to remove all items --- Controllers/AdminController.cs | 17 ++++++ GameAuthApi.Tests/AdminControllerTests.cs | 35 ++++++++++++- GameAuthApi.Tests/AdminServiceTests.cs | 64 +++++++++++++++++++++++ Services/AdminService.cs | 47 +++++++++++++++++ Services/ItemService.cs | 10 ++++ Services/LocationService.cs | 17 ++++++ Services/PlayerService.cs | 5 ++ 7 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 GameAuthApi.Tests/AdminServiceTests.cs diff --git a/Controllers/AdminController.cs b/Controllers/AdminController.cs index d936c48..79511c6 100644 --- a/Controllers/AdminController.cs +++ b/Controllers/AdminController.cs @@ -2,6 +2,7 @@ using GameAuthApi.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using System.Threading.Tasks; +using GameAuthApi.Models; namespace GameAuthApi.Controllers; @@ -23,5 +24,21 @@ public class AdminController : ControllerBase var status = await _adminService.GetStatusAsync(); return Ok(status); } + + [HttpPost("reset-locations")] + [Authorize(Roles = "SUPER")] + public async Task ResetLocations() + { + var origin = await _adminService.ResetLocationsAsync(); + return Ok(origin); + } + + [HttpPost("clear-items")] + [Authorize(Roles = "SUPER")] + public async Task ClearItems() + { + await _adminService.ClearItemsAsync(); + return Ok("All items cleared."); + } } diff --git a/GameAuthApi.Tests/AdminControllerTests.cs b/GameAuthApi.Tests/AdminControllerTests.cs index 9e3926b..19be0c7 100644 --- a/GameAuthApi.Tests/AdminControllerTests.cs +++ b/GameAuthApi.Tests/AdminControllerTests.cs @@ -3,6 +3,7 @@ using GameAuthApi.Services; using Microsoft.AspNetCore.Mvc; using System.Collections.Generic; using System.Threading.Tasks; +using GameAuthApi.Models; public class AdminControllerTests { @@ -10,7 +11,7 @@ public class AdminControllerTests public async Task GetStatus_ReturnsOk() { var expected = new Dictionary { { "status", "ok" } }; - var mockService = new Mock(); + var mockService = new Mock((LocationService)null, (ItemService)null, (PlayerService)null); mockService.Setup(s => s.GetStatusAsync()).ReturnsAsync(expected); var controller = new AdminController(mockService.Object); @@ -19,5 +20,37 @@ public class AdminControllerTests var ok = Assert.IsType(result); Assert.Equal(expected, ok.Value); } + + [Fact] + public async Task ResetLocations_ReturnsOk() + { + var newLoc = new Location { LocationType = "World", X = 0, Y = 0, Z = 0 }; + var mockService = new Mock((LocationService)null, (ItemService)null, (PlayerService)null); + mockService.Setup(s => s.ResetLocationsAsync()).ReturnsAsync(newLoc); + var controller = new AdminController(mockService.Object); + + var result = await controller.ResetLocations(); + + var ok = Assert.IsType(result); + var origin = Assert.IsType(ok.Value); + Assert.Equal("World", origin.LocationType); + Assert.Equal(0, origin.X); + Assert.Equal(0, origin.Y); + Assert.Equal(0, origin.Z); + } + + [Fact] + public async Task ClearItems_ReturnsOk() + { + var mockService = new Mock((LocationService)null, (ItemService)null, (PlayerService)null); + mockService.Setup(s => s.ClearItemsAsync()).Returns(Task.CompletedTask).Verifiable(); + var controller = new AdminController(mockService.Object); + + var result = await controller.ClearItems(); + + var ok = Assert.IsType(result); + Assert.Equal("All items cleared.", ok.Value); + mockService.Verify(); + } } diff --git a/GameAuthApi.Tests/AdminServiceTests.cs b/GameAuthApi.Tests/AdminServiceTests.cs new file mode 100644 index 0000000..30f8e3a --- /dev/null +++ b/GameAuthApi.Tests/AdminServiceTests.cs @@ -0,0 +1,64 @@ +using GameAuthApi.Services; +using GameAuthApi.Models; +using Microsoft.Extensions.Configuration; + +public class AdminServiceTests +{ + [Fact] + public async Task ResetLocations_DeletesWorldLocationsOnly() + { + var worldLocs = new List { new() { Id = "1", LocationType = "World" } }; + + var cfg = new ConfigurationBuilder() + .AddInMemoryCollection(new Dictionary + { + {"MongoDB:ConnectionString", "mongodb://localhost"}, + {"MongoDB:DatabaseName", "test"} + }).Build(); + + var locSvc = new Mock(cfg); + locSvc.Setup(l => l.GetByTypeAsync("World")).ReturnsAsync(worldLocs); + locSvc.Setup(l => l.DeleteByTypeAsync("World")).Returns(Task.CompletedTask).Verifiable(); + locSvc.Setup(l => l.CreateAsync(It.IsAny())).Returns(Task.CompletedTask); + + var itemSvc = new Mock(cfg); + itemSvc.Setup(i => i.DeleteByLocationAsync("1")).Returns(Task.CompletedTask).Verifiable(); + + var playerSvc = new Mock(cfg); + playerSvc.Setup(p => p.GetAllAsync()).ReturnsAsync(new List()); + + var adminSvc = new AdminService(locSvc.Object, itemSvc.Object, playerSvc.Object); + + await adminSvc.ResetLocationsAsync(); + + locSvc.Verify(); + itemSvc.Verify(); + } + + [Fact] + public async Task ClearItems_RemovesAllItemsFromLocations() + { + var cfg = new ConfigurationBuilder() + .AddInMemoryCollection(new Dictionary + { + {"MongoDB:ConnectionString", "mongodb://localhost"}, + {"MongoDB:DatabaseName", "test"} + }).Build(); + + var locSvc = new Mock(cfg); + locSvc.Setup(l => l.ClearAllItemsAsync()).Returns(Task.CompletedTask).Verifiable(); + + var itemSvc = new Mock(cfg); + itemSvc.Setup(i => i.DeleteAllAsync()).Returns(Task.CompletedTask).Verifiable(); + + var playerSvc = new Mock(cfg); + + var adminSvc = new AdminService(locSvc.Object, itemSvc.Object, playerSvc.Object); + + await adminSvc.ClearItemsAsync(); + + locSvc.Verify(); + itemSvc.Verify(); + } +} + diff --git a/Services/AdminService.cs b/Services/AdminService.cs index eee5359..0c7748a 100644 --- a/Services/AdminService.cs +++ b/Services/AdminService.cs @@ -1,10 +1,22 @@ using System.Collections.Generic; using System.Threading.Tasks; +using GameAuthApi.Models; namespace GameAuthApi.Services; public class AdminService { + private readonly LocationService _locationService; + private readonly ItemService _itemService; + private readonly PlayerService _playerService; + + public AdminService(LocationService locationService, ItemService itemService, PlayerService playerService) + { + _locationService = locationService; + _itemService = itemService; + _playerService = playerService; + } + public virtual Task> GetStatusAsync() { var status = new Dictionary @@ -13,5 +25,40 @@ public class AdminService }; return Task.FromResult(status); } + + public virtual async Task ResetLocationsAsync() + { + var worldLocations = await _locationService.GetByTypeAsync("World"); + foreach (var loc in worldLocations) + { + await _itemService.DeleteByLocationAsync(loc.Id); + } + await _locationService.DeleteByTypeAsync("World"); + + var origin = new Location + { + LocationType = "World", + X = 0, + Y = 0, + Z = 0 + }; + await _locationService.CreateAsync(origin); + + var players = await _playerService.GetAllAsync(); + foreach (var player in players) + { + player.LocationId = origin.Id; + await _playerService.UpdateAsync(player); + await _locationService.AddPlayerToLocationAsync(origin.Id, player.Id); + } + + return origin; + } + + public virtual async Task ClearItemsAsync() + { + await _itemService.DeleteAllAsync(); + await _locationService.ClearAllItemsAsync(); + } } diff --git a/Services/ItemService.cs b/Services/ItemService.cs index 5a4af39..7b4ef80 100644 --- a/Services/ItemService.cs +++ b/Services/ItemService.cs @@ -44,4 +44,14 @@ public class ItemService { await _items.DeleteOneAsync(i => i.Id == id); } + + public virtual async Task DeleteByLocationAsync(string locationId) + { + await _items.DeleteManyAsync(i => i.LocationId == locationId); + } + + public virtual async Task DeleteAllAsync() + { + await _items.DeleteManyAsync(_ => true); + } } diff --git a/Services/LocationService.cs b/Services/LocationService.cs index 017203d..b718c2e 100644 --- a/Services/LocationService.cs +++ b/Services/LocationService.cs @@ -31,6 +31,17 @@ public class LocationService public virtual async Task DeleteAsync(string id) => await _locations.DeleteOneAsync(loc => loc.Id == id); + + public virtual async Task> GetByTypeAsync(string type) + { + return await _locations.Find(l => l.LocationType == type).ToListAsync(); + } + + public virtual async Task DeleteByTypeAsync(string type) => + await _locations.DeleteManyAsync(l => l.LocationType == type); + + public virtual async Task DeleteAllAsync() => + await _locations.DeleteManyAsync(_ => true); public virtual async Task UpdateAsync(Location loc) => await _locations.ReplaceOneAsync(l => l.Id == loc.Id, loc); @@ -83,4 +94,10 @@ public class LocationService var update = Builders.Update.Pull(l => l.Content, itemId); await _locations.UpdateOneAsync(filter, update); } + + public virtual async Task ClearAllItemsAsync() + { + var update = Builders.Update.Set(l => l.Content, new List()); + await _locations.UpdateManyAsync(_ => true, update); + } } diff --git a/Services/PlayerService.cs b/Services/PlayerService.cs index 62dcfc1..58f712c 100644 --- a/Services/PlayerService.cs +++ b/Services/PlayerService.cs @@ -29,6 +29,11 @@ public class PlayerService public virtual async Task GetByIdAsync(string id) => await _players.Find(p => p.Id == id).FirstOrDefaultAsync(); + public virtual async Task> GetAllAsync() + { + return await _players.Find(_ => true).ToListAsync(); + } + public virtual async Task CreateAsync(Player player) => await _players.InsertOneAsync(player);