something

This commit is contained in:
2025-10-01 01:56:05 +03:00
parent ece9cedb37
commit 40342a0e14
112 changed files with 5468 additions and 5468 deletions

View File

@@ -1,29 +1,29 @@
using LctMonolith.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LctMonolith.Controllers;
/// <summary>
/// Basic analytics endpoints.
/// </summary>
[ApiController]
[Route("api/analytics")]
[Authorize]
public class AnalyticsController : ControllerBase
{
private readonly IAnalyticsService _analytics;
public AnalyticsController(IAnalyticsService analytics)
{
_analytics = analytics;
}
/// <summary>Get aggregate system summary metrics.</summary>
[HttpGet("summary")]
public async Task<IActionResult> GetSummary(CancellationToken ct)
{
var summary = await _analytics.GetSummaryAsync(ct);
return Ok(summary);
}
}
using LctMonolith.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LctMonolith.Controllers;
/// <summary>
/// Basic analytics endpoints.
/// </summary>
[ApiController]
[Route("api/analytics")]
[Authorize]
public class AnalyticsController : ControllerBase
{
private readonly IAnalyticsService _analytics;
public AnalyticsController(IAnalyticsService analytics)
{
_analytics = analytics;
}
/// <summary>Get aggregate system summary metrics.</summary>
[HttpGet("summary")]
public async Task<IActionResult> GetSummary(CancellationToken ct)
{
var summary = await _analytics.GetSummaryAsync(ct);
return Ok(summary);
}
}

View File

@@ -1,86 +1,86 @@
using System.Security.Claims;
using LctMonolith.Models.Database;
using LctMonolith.Services;
using LctMonolith.Services.Contracts;
using LctMonolith.Services.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.Data;
using Microsoft.AspNetCore.Mvc;
using RefreshRequest = LctMonolith.Services.Models.RefreshRequest;
namespace LctMonolith.Controllers;
/// <summary>
/// Authentication endpoints (mocked local identity + JWT issuing).
/// </summary>
[ApiController]
[Route("api/auth")]
public class AuthController : ControllerBase
{
private readonly UserManager<AppUser> _userManager;
private readonly SignInManager<AppUser> _signInManager;
private readonly ITokenService _tokenService;
public AuthController(UserManager<AppUser> userManager, SignInManager<AppUser> signInManager, ITokenService tokenService)
{
_userManager = userManager;
_signInManager = signInManager;
_tokenService = tokenService;
}
/// <summary>Registers a new user (simplified).</summary>
[HttpPost("register")]
[AllowAnonymous]
public async Task<ActionResult<TokenPair>> Register(AuthRequest req, CancellationToken ct)
{
var existing = await _userManager.FindByEmailAsync(req.Email);
if (existing != null) return Conflict("Email already registered");
var user = new AppUser { UserName = req.Email, Email = req.Email, FirstName = req.FirstName, LastName = req.LastName };
var result = await _userManager.CreateAsync(user, req.Password);
if (!result.Succeeded) return BadRequest(result.Errors);
var tokens = await _tokenService.IssueAsync(user, ct);
return Ok(tokens);
}
/// <summary>Login with email + password.</summary>
[HttpPost("login")]
[AllowAnonymous]
public async Task<ActionResult<TokenPair>> Login(AuthRequest req, CancellationToken ct)
{
var user = await _userManager.FindByEmailAsync(req.Email);
if (user == null) return Unauthorized();
var passOk = await _signInManager.CheckPasswordSignInAsync(user, req.Password, lockoutOnFailure: false);
if (!passOk.Succeeded) return Unauthorized();
var tokens = await _tokenService.IssueAsync(user, ct);
return Ok(tokens);
}
/// <summary>Refresh access token by refresh token.</summary>
[HttpPost("refresh")]
[AllowAnonymous]
public async Task<ActionResult<TokenPair>> Refresh(RefreshRequest req, CancellationToken ct)
{
var pair = await _tokenService.RefreshAsync(req.RefreshToken, ct);
return Ok(pair);
}
/// <summary>Revoke refresh token (logout).</summary>
[HttpPost("revoke")]
[Authorize]
public async Task<IActionResult> Revoke(RevokeRequest req, CancellationToken ct)
{
await _tokenService.RevokeAsync(req.RefreshToken, ct);
return NoContent();
}
/// <summary>Returns current user id (debug).</summary>
[HttpGet("me")]
[Authorize]
public ActionResult<object> Me()
{
var id = User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.FindFirstValue(ClaimTypes.Name);
return Ok(new { userId = id });
}
}
using System.Security.Claims;
using LctMonolith.Models.Database;
using LctMonolith.Services;
using LctMonolith.Services.Contracts;
using LctMonolith.Services.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.Data;
using Microsoft.AspNetCore.Mvc;
using RefreshRequest = LctMonolith.Services.Models.RefreshRequest;
namespace LctMonolith.Controllers;
/// <summary>
/// Authentication endpoints (mocked local identity + JWT issuing).
/// </summary>
[ApiController]
[Route("api/auth")]
public class AuthController : ControllerBase
{
private readonly UserManager<AppUser> _userManager;
private readonly SignInManager<AppUser> _signInManager;
private readonly ITokenService _tokenService;
public AuthController(UserManager<AppUser> userManager, SignInManager<AppUser> signInManager, ITokenService tokenService)
{
_userManager = userManager;
_signInManager = signInManager;
_tokenService = tokenService;
}
/// <summary>Registers a new user (simplified).</summary>
[HttpPost("register")]
[AllowAnonymous]
public async Task<ActionResult<TokenPair>> Register(AuthRequest req, CancellationToken ct)
{
var existing = await _userManager.FindByEmailAsync(req.Email);
if (existing != null) return Conflict("Email already registered");
var user = new AppUser { UserName = req.Email, Email = req.Email, FirstName = req.FirstName, LastName = req.LastName };
var result = await _userManager.CreateAsync(user, req.Password);
if (!result.Succeeded) return BadRequest(result.Errors);
var tokens = await _tokenService.IssueAsync(user, ct);
return Ok(tokens);
}
/// <summary>Login with email + password.</summary>
[HttpPost("login")]
[AllowAnonymous]
public async Task<ActionResult<TokenPair>> Login(AuthRequest req, CancellationToken ct)
{
var user = await _userManager.FindByEmailAsync(req.Email);
if (user == null) return Unauthorized();
var passOk = await _signInManager.CheckPasswordSignInAsync(user, req.Password, lockoutOnFailure: false);
if (!passOk.Succeeded) return Unauthorized();
var tokens = await _tokenService.IssueAsync(user, ct);
return Ok(tokens);
}
/// <summary>Refresh access token by refresh token.</summary>
[HttpPost("refresh")]
[AllowAnonymous]
public async Task<ActionResult<TokenPair>> Refresh(RefreshRequest req, CancellationToken ct)
{
var pair = await _tokenService.RefreshAsync(req.RefreshToken, ct);
return Ok(pair);
}
/// <summary>Revoke refresh token (logout).</summary>
[HttpPost("revoke")]
[Authorize]
public async Task<IActionResult> Revoke(RevokeRequest req, CancellationToken ct)
{
await _tokenService.RevokeAsync(req.RefreshToken, ct);
return NoContent();
}
/// <summary>Returns current user id (debug).</summary>
[HttpGet("me")]
[Authorize]
public ActionResult<object> Me()
{
var id = User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.FindFirstValue(ClaimTypes.Name);
return Ok(new { userId = id });
}
}

View File

@@ -1,75 +1,75 @@
using LctMonolith.Models.Database;
using LctMonolith.Services.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LctMonolith.Controllers;
[ApiController]
[Route("api/dialogue")]
[Authorize]
public class DialogueController : ControllerBase
{
private readonly IDialogueService _dialogueService;
public DialogueController(IDialogueService dialogueService)
{
_dialogueService = dialogueService;
}
[HttpGet("mission/{missionId:guid}")]
public async Task<IActionResult> GetByMission(Guid missionId)
{
var d = await _dialogueService.GetDialogueByMissionIdAsync(missionId);
return d == null ? NotFound() : Ok(d);
}
[HttpGet("message/{messageId:guid}")]
public async Task<IActionResult> GetMessage(Guid messageId)
{
var m = await _dialogueService.GetDialogueMessageByIdAsync(messageId);
return m == null ? NotFound() : Ok(m);
}
[HttpGet("message/{messageId:guid}/options")]
public async Task<IActionResult> GetOptions(Guid messageId)
{
var opts = await _dialogueService.GetResponseOptionsAsync(messageId);
return Ok(opts);
}
public record DialogueResponseRequest(Guid ResponseOptionId, Guid PlayerId);
[HttpPost("message/{messageId:guid}/respond")]
public async Task<IActionResult> Respond(Guid messageId, DialogueResponseRequest req)
{
var next = await _dialogueService.ProcessDialogueResponseAsync(messageId, req.ResponseOptionId, req.PlayerId);
if (next == null) return Ok(new { end = true });
return Ok(next);
}
public class CreateDialogueRequest
{
public Guid MissionId { get; set; }
public Guid InitialDialogueMessageId { get; set; }
public Guid InterimDialogueMessageId { get; set; }
public Guid EndDialogueMessageId { get; set; }
}
[HttpPost]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Create(CreateDialogueRequest dto)
{
var d = new Dialogue
{
Id = Guid.NewGuid(),
MissionId = dto.MissionId,
InitialDialogueMessageId = dto.InitialDialogueMessageId,
InterimDialogueMessageId = dto.InterimDialogueMessageId,
EndDialogueMessageId = dto.EndDialogueMessageId,
Mission = null! // EF will populate if included
};
d = await _dialogueService.CreateDialogueAsync(d);
return CreatedAtAction(nameof(GetByMission), new { missionId = d.MissionId }, d);
}
}
using LctMonolith.Models.Database;
using LctMonolith.Services.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LctMonolith.Controllers;
[ApiController]
[Route("api/dialogue")]
[Authorize]
public class DialogueController : ControllerBase
{
private readonly IDialogueService _dialogueService;
public DialogueController(IDialogueService dialogueService)
{
_dialogueService = dialogueService;
}
[HttpGet("mission/{missionId:guid}")]
public async Task<IActionResult> GetByMission(Guid missionId)
{
var d = await _dialogueService.GetDialogueByMissionIdAsync(missionId);
return d == null ? NotFound() : Ok(d);
}
[HttpGet("message/{messageId:guid}")]
public async Task<IActionResult> GetMessage(Guid messageId)
{
var m = await _dialogueService.GetDialogueMessageByIdAsync(messageId);
return m == null ? NotFound() : Ok(m);
}
[HttpGet("message/{messageId:guid}/options")]
public async Task<IActionResult> GetOptions(Guid messageId)
{
var opts = await _dialogueService.GetResponseOptionsAsync(messageId);
return Ok(opts);
}
public record DialogueResponseRequest(Guid ResponseOptionId, Guid PlayerId);
[HttpPost("message/{messageId:guid}/respond")]
public async Task<IActionResult> Respond(Guid messageId, DialogueResponseRequest req)
{
var next = await _dialogueService.ProcessDialogueResponseAsync(messageId, req.ResponseOptionId, req.PlayerId);
if (next == null) return Ok(new { end = true });
return Ok(next);
}
public class CreateDialogueRequest
{
public Guid MissionId { get; set; }
public Guid InitialDialogueMessageId { get; set; }
public Guid InterimDialogueMessageId { get; set; }
public Guid EndDialogueMessageId { get; set; }
}
[HttpPost]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Create(CreateDialogueRequest dto)
{
var d = new Dialogue
{
Id = Guid.NewGuid(),
MissionId = dto.MissionId,
InitialDialogueMessageId = dto.InitialDialogueMessageId,
InterimDialogueMessageId = dto.InterimDialogueMessageId,
EndDialogueMessageId = dto.EndDialogueMessageId,
Mission = null! // EF will populate if included
};
d = await _dialogueService.CreateDialogueAsync(d);
return CreatedAtAction(nameof(GetByMission), new { missionId = d.MissionId }, d);
}
}

View File

@@ -1,34 +1,34 @@
using System.Security.Claims;
using LctMonolith.Services.Contracts;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LctMonolith.Controllers;
[ApiController]
[Route("api/inventory")]
[Authorize]
public class InventoryController : ControllerBase
{
private readonly IInventoryService _inventoryService;
public InventoryController(IInventoryService inventoryService) => _inventoryService = inventoryService;
private Guid CurrentUserId() => Guid.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!);
/// <summary>Get inventory for current authenticated user.</summary>
[HttpGet]
public async Task<IActionResult> GetMine(CancellationToken ct)
{
var items = await _inventoryService.GetStoreInventoryAsync(CurrentUserId(), ct);
return Ok(items.Select(i => new { i.StoreItemId, i.Quantity, i.AcquiredAt }));
}
/// <summary>Admin: get inventory for specific user.</summary>
[HttpGet("user/{userId:guid}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> GetByUser(Guid userId, CancellationToken ct)
{
var items = await _inventoryService.GetStoreInventoryAsync(userId, ct);
return Ok(items);
}
}
using System.Security.Claims;
using LctMonolith.Services.Contracts;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LctMonolith.Controllers;
[ApiController]
[Route("api/inventory")]
[Authorize]
public class InventoryController : ControllerBase
{
private readonly IInventoryService _inventoryService;
public InventoryController(IInventoryService inventoryService) => _inventoryService = inventoryService;
private Guid CurrentUserId() => Guid.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!);
/// <summary>Get inventory for current authenticated user.</summary>
[HttpGet]
public async Task<IActionResult> GetMine(CancellationToken ct)
{
var items = await _inventoryService.GetStoreInventoryAsync(CurrentUserId(), ct);
return Ok(items.Select(i => new { i.StoreItemId, i.Quantity, i.AcquiredAt }));
}
/// <summary>Admin: get inventory for specific user.</summary>
[HttpGet("user/{userId:guid}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> GetByUser(Guid userId, CancellationToken ct)
{
var items = await _inventoryService.GetStoreInventoryAsync(userId, ct);
return Ok(items);
}
}

View File

@@ -1,58 +1,58 @@
using LctMonolith.Models.Database;
using LctMonolith.Models.DTO;
using LctMonolith.Services.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LctMonolith.Controllers;
[ApiController]
[Route("api/mission-categories")]
[Authorize]
public class MissionCategoriesController : ControllerBase
{
private readonly IMissionCategoryService _service;
public MissionCategoriesController(IMissionCategoryService service) => _service = service;
[HttpGet]
public async Task<IActionResult> GetAll()
{
var list = await _service.GetAllCategoriesAsync();
return Ok(list);
}
[HttpGet("{id:guid}")]
public async Task<IActionResult> Get(Guid id)
{
var c = await _service.GetCategoryByIdAsync(id);
return c == null ? NotFound() : Ok(c);
}
[HttpPost]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Create(CreateMissionCategoryDto dto)
{
var c = await _service.CreateCategoryAsync(new MissionCategory { Title = dto.Title });
return CreatedAtAction(nameof(Get), new { id = c.Id }, c);
}
[HttpPut("{id:guid}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Update(Guid id, CreateMissionCategoryDto dto)
{
var c = await _service.GetCategoryByIdAsync(id);
if (c == null) return NotFound();
c.Title = dto.Title;
await _service.UpdateCategoryAsync(c);
return Ok(c);
}
[HttpDelete("{id:guid}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Delete(Guid id)
{
var ok = await _service.DeleteCategoryAsync(id);
return ok ? NoContent() : NotFound();
}
}
using LctMonolith.Models.Database;
using LctMonolith.Models.DTO;
using LctMonolith.Services.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LctMonolith.Controllers;
[ApiController]
[Route("api/mission-categories")]
[Authorize]
public class MissionCategoriesController : ControllerBase
{
private readonly IMissionCategoryService _service;
public MissionCategoriesController(IMissionCategoryService service) => _service = service;
[HttpGet]
public async Task<IActionResult> GetAll()
{
var list = await _service.GetAllCategoriesAsync();
return Ok(list);
}
[HttpGet("{id:guid}")]
public async Task<IActionResult> Get(Guid id)
{
var c = await _service.GetCategoryByIdAsync(id);
return c == null ? NotFound() : Ok(c);
}
[HttpPost]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Create(CreateMissionCategoryDto dto)
{
var c = await _service.CreateCategoryAsync(new MissionCategory { Title = dto.Title });
return CreatedAtAction(nameof(Get), new { id = c.Id }, c);
}
[HttpPut("{id:guid}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Update(Guid id, CreateMissionCategoryDto dto)
{
var c = await _service.GetCategoryByIdAsync(id);
if (c == null) return NotFound();
c.Title = dto.Title;
await _service.UpdateCategoryAsync(c);
return Ok(c);
}
[HttpDelete("{id:guid}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Delete(Guid id)
{
var ok = await _service.DeleteCategoryAsync(id);
return ok ? NoContent() : NotFound();
}
}

View File

@@ -1,112 +1,112 @@
using LctMonolith.Models.Database;
using LctMonolith.Models.DTO;
using LctMonolith.Services.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LctMonolith.Controllers;
[ApiController]
[Route("api/missions")]
[Authorize]
public class MissionsController : ControllerBase
{
private readonly IMissionService _missions;
private readonly IRuleValidationService _rules;
public MissionsController(IMissionService missions, IRuleValidationService rules)
{
_missions = missions;
_rules = rules;
}
[HttpGet("{id:guid}")]
public async Task<IActionResult> Get(Guid id)
{
var m = await _missions.GetMissionByIdAsync(id);
return m == null ? NotFound() : Ok(m);
}
[HttpGet("category/{categoryId:guid}")]
public async Task<IActionResult> ByCategory(Guid categoryId)
{
var list = await _missions.GetMissionsByCategoryAsync(categoryId);
return Ok(list);
}
[HttpGet("player/{playerId:guid}/available")]
public async Task<IActionResult> Available(Guid playerId)
{
var list = await _missions.GetAvailableMissionsForPlayerAsync(playerId);
return Ok(list);
}
[HttpGet("{id:guid}/rank-rules")]
public async Task<IActionResult> RankRules(Guid id)
{
var rules = await _rules.GetApplicableRankRulesAsync(id);
return Ok(rules);
}
public class CreateMissionRequest
{
public string Title { get; set; } = string.Empty;
public string? Description { get; set; }
public Guid MissionCategoryId { get; set; }
public Guid? ParentMissionId { get; set; }
public int ExpReward { get; set; }
public int ManaReward { get; set; }
}
[HttpPost]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Create(CreateMissionRequest dto)
{
var mission = new Mission
{
Title = dto.Title,
Description = dto.Description ?? string.Empty,
MissionCategoryId = dto.MissionCategoryId,
ParentMissionId = dto.ParentMissionId,
ExpReward = dto.ExpReward,
ManaReward = dto.ManaReward
};
mission = await _missions.CreateMissionAsync(mission);
return CreatedAtAction(nameof(Get), new { id = mission.Id }, mission);
}
[HttpPut("{id:guid}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Update(Guid id, CreateMissionRequest dto)
{
var existing = await _missions.GetMissionByIdAsync(id);
if (existing == null) return NotFound();
existing.Title = dto.Title;
existing.Description = dto.Description ?? string.Empty;
existing.MissionCategoryId = dto.MissionCategoryId;
existing.ParentMissionId = dto.ParentMissionId;
existing.ExpReward = dto.ExpReward;
existing.ManaReward = dto.ManaReward;
await _missions.UpdateMissionAsync(existing);
return Ok(existing);
}
[HttpDelete("{id:guid}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Delete(Guid id)
{
var ok = await _missions.DeleteMissionAsync(id);
return ok ? NoContent() : NotFound();
}
public record CompleteMissionRequest(Guid PlayerId, object? Proof);
[HttpPost("{missionId:guid}/complete")]
public async Task<IActionResult> Complete(Guid missionId, CompleteMissionRequest r)
{
var result = await _missions.CompleteMissionAsync(missionId, r.PlayerId, r.Proof);
if (!result.Success) return BadRequest(result);
return Ok(result);
}
}
using LctMonolith.Models.Database;
using LctMonolith.Models.DTO;
using LctMonolith.Services.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LctMonolith.Controllers;
[ApiController]
[Route("api/missions")]
[Authorize]
public class MissionsController : ControllerBase
{
private readonly IMissionService _missions;
private readonly IRuleValidationService _rules;
public MissionsController(IMissionService missions, IRuleValidationService rules)
{
_missions = missions;
_rules = rules;
}
[HttpGet("{id:guid}")]
public async Task<IActionResult> Get(Guid id)
{
var m = await _missions.GetMissionByIdAsync(id);
return m == null ? NotFound() : Ok(m);
}
[HttpGet("category/{categoryId:guid}")]
public async Task<IActionResult> ByCategory(Guid categoryId)
{
var list = await _missions.GetMissionsByCategoryAsync(categoryId);
return Ok(list);
}
[HttpGet("player/{playerId:guid}/available")]
public async Task<IActionResult> Available(Guid playerId)
{
var list = await _missions.GetAvailableMissionsForPlayerAsync(playerId);
return Ok(list);
}
[HttpGet("{id:guid}/rank-rules")]
public async Task<IActionResult> RankRules(Guid id)
{
var rules = await _rules.GetApplicableRankRulesAsync(id);
return Ok(rules);
}
public class CreateMissionRequest
{
public string Title { get; set; } = string.Empty;
public string? Description { get; set; }
public Guid MissionCategoryId { get; set; }
public Guid? ParentMissionId { get; set; }
public int ExpReward { get; set; }
public int ManaReward { get; set; }
}
[HttpPost]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Create(CreateMissionRequest dto)
{
var mission = new Mission
{
Title = dto.Title,
Description = dto.Description ?? string.Empty,
MissionCategoryId = dto.MissionCategoryId,
ParentMissionId = dto.ParentMissionId,
ExpReward = dto.ExpReward,
ManaReward = dto.ManaReward
};
mission = await _missions.CreateMissionAsync(mission);
return CreatedAtAction(nameof(Get), new { id = mission.Id }, mission);
}
[HttpPut("{id:guid}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Update(Guid id, CreateMissionRequest dto)
{
var existing = await _missions.GetMissionByIdAsync(id);
if (existing == null) return NotFound();
existing.Title = dto.Title;
existing.Description = dto.Description ?? string.Empty;
existing.MissionCategoryId = dto.MissionCategoryId;
existing.ParentMissionId = dto.ParentMissionId;
existing.ExpReward = dto.ExpReward;
existing.ManaReward = dto.ManaReward;
await _missions.UpdateMissionAsync(existing);
return Ok(existing);
}
[HttpDelete("{id:guid}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Delete(Guid id)
{
var ok = await _missions.DeleteMissionAsync(id);
return ok ? NoContent() : NotFound();
}
public record CompleteMissionRequest(Guid PlayerId, object? Proof);
[HttpPost("{missionId:guid}/complete")]
public async Task<IActionResult> Complete(Guid missionId, CompleteMissionRequest r)
{
var result = await _missions.CompleteMissionAsync(missionId, r.PlayerId, r.Proof);
if (!result.Success) return BadRequest(result);
return Ok(result);
}
}

View File

@@ -1,58 +1,58 @@
using System.Security.Claims;
using LctMonolith.Services;
using LctMonolith.Services.Contracts;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LctMonolith.Controllers;
/// <summary>
/// In-app user notifications API.
/// </summary>
[ApiController]
[Route("api/notifications")]
[Authorize]
public class NotificationsController : ControllerBase
{
private readonly INotificationService _notifications;
public NotificationsController(INotificationService notifications)
{
_notifications = notifications;
}
private Guid GetUserId() => Guid.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!);
/// <summary>Get up to 100 unread notifications.</summary>
[HttpGet("unread")]
public async Task<IActionResult> GetUnread(CancellationToken ct)
{
var list = await _notifications.GetUnreadAsync(GetUserId(), ct);
return Ok(list);
}
/// <summary>Get recent notifications (paged by take).</summary>
[HttpGet]
public async Task<IActionResult> GetAll([FromQuery] int take = 100, CancellationToken ct = default)
{
var list = await _notifications.GetAllAsync(GetUserId(), take, ct);
return Ok(list);
}
/// <summary>Mark a notification as read.</summary>
[HttpPost("mark/{id:guid}")]
public async Task<IActionResult> MarkRead(Guid id, CancellationToken ct)
{
await _notifications.MarkReadAsync(GetUserId(), id, ct);
return NoContent();
}
/// <summary>Mark all notifications as read.</summary>
[HttpPost("mark-all")]
public async Task<IActionResult> MarkAll(CancellationToken ct)
{
var cnt = await _notifications.MarkAllReadAsync(GetUserId(), ct);
return Ok(new { updated = cnt });
}
}
using System.Security.Claims;
using LctMonolith.Services;
using LctMonolith.Services.Contracts;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LctMonolith.Controllers;
/// <summary>
/// In-app user notifications API.
/// </summary>
[ApiController]
[Route("api/notifications")]
[Authorize]
public class NotificationsController : ControllerBase
{
private readonly INotificationService _notifications;
public NotificationsController(INotificationService notifications)
{
_notifications = notifications;
}
private Guid GetUserId() => Guid.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!);
/// <summary>Get up to 100 unread notifications.</summary>
[HttpGet("unread")]
public async Task<IActionResult> GetUnread(CancellationToken ct)
{
var list = await _notifications.GetUnreadAsync(GetUserId(), ct);
return Ok(list);
}
/// <summary>Get recent notifications (paged by take).</summary>
[HttpGet]
public async Task<IActionResult> GetAll([FromQuery] int take = 100, CancellationToken ct = default)
{
var list = await _notifications.GetAllAsync(GetUserId(), take, ct);
return Ok(list);
}
/// <summary>Mark a notification as read.</summary>
[HttpPost("mark/{id:guid}")]
public async Task<IActionResult> MarkRead(Guid id, CancellationToken ct)
{
await _notifications.MarkReadAsync(GetUserId(), id, ct);
return NoContent();
}
/// <summary>Mark all notifications as read.</summary>
[HttpPost("mark-all")]
public async Task<IActionResult> MarkAll(CancellationToken ct)
{
var cnt = await _notifications.MarkAllReadAsync(GetUserId(), ct);
return Ok(new { updated = cnt });
}
}

View File

@@ -1,78 +1,78 @@
using LctMonolith.Services.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LctMonolith.Controllers;
[ApiController]
[Route("api/players")]
[Authorize]
public class PlayersController : ControllerBase
{
private readonly IPlayerService _playerService;
private readonly IProgressTrackingService _progressService;
public PlayersController(IPlayerService playerService, IProgressTrackingService progressService)
{
_playerService = playerService;
_progressService = progressService;
}
[HttpGet("{playerId:guid}")]
public async Task<IActionResult> GetPlayer(Guid playerId)
{
var player = await _playerService.GetPlayerWithProgressAsync(playerId);
return Ok(player);
}
[HttpGet("user/{userId:guid}")]
public async Task<IActionResult> GetByUser(Guid userId)
{
var p = await _playerService.GetPlayerByUserIdAsync(userId.ToString());
if (p == null) return NotFound();
return Ok(p);
}
public class CreatePlayerRequest { public Guid UserId { get; set; } public string Username { get; set; } = string.Empty; }
[HttpPost]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Create(CreatePlayerRequest req)
{
var p = await _playerService.CreatePlayerAsync(req.UserId.ToString(), req.Username);
return CreatedAtAction(nameof(GetPlayer), new { playerId = p.Id }, p);
}
public record AdjustValueRequest(int Value);
[HttpPost("{playerId:guid}/experience")]
[Authorize(Roles = "Admin")] // manual adjust
public async Task<IActionResult> AddExperience(Guid playerId, AdjustValueRequest r)
{
var p = await _playerService.AddPlayerExperienceAsync(playerId, r.Value);
return Ok(new { p.Id, p.Experience });
}
[HttpPost("{playerId:guid}/mana")]
[Authorize(Roles = "Admin")] // manual adjust
public async Task<IActionResult> AddMana(Guid playerId, AdjustValueRequest r)
{
var p = await _playerService.AddPlayerManaAsync(playerId, r.Value);
return Ok(new { p.Id, p.Mana });
}
[HttpGet("top")]
public async Task<IActionResult> GetTop([FromQuery] int count = 10)
{
var list = await _playerService.GetTopPlayersAsync(count, TimeSpan.FromDays(30));
return Ok(list);
}
[HttpGet("{playerId:guid}/progress")]
public async Task<IActionResult> GetProgress(Guid playerId)
{
var prog = await _progressService.GetPlayerOverallProgressAsync(playerId);
return Ok(prog);
}
}
using LctMonolith.Services.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LctMonolith.Controllers;
[ApiController]
[Route("api/players")]
[Authorize]
public class PlayersController : ControllerBase
{
private readonly IPlayerService _playerService;
private readonly IProgressTrackingService _progressService;
public PlayersController(IPlayerService playerService, IProgressTrackingService progressService)
{
_playerService = playerService;
_progressService = progressService;
}
[HttpGet("{playerId:guid}")]
public async Task<IActionResult> GetPlayer(Guid playerId)
{
var player = await _playerService.GetPlayerWithProgressAsync(playerId);
return Ok(player);
}
[HttpGet("user/{userId:guid}")]
public async Task<IActionResult> GetByUser(Guid userId)
{
var p = await _playerService.GetPlayerByUserIdAsync(userId.ToString());
if (p == null) return NotFound();
return Ok(p);
}
public class CreatePlayerRequest { public Guid UserId { get; set; } public string Username { get; set; } = string.Empty; }
[HttpPost]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Create(CreatePlayerRequest req)
{
var p = await _playerService.CreatePlayerAsync(req.UserId.ToString(), req.Username);
return CreatedAtAction(nameof(GetPlayer), new { playerId = p.Id }, p);
}
public record AdjustValueRequest(int Value);
[HttpPost("{playerId:guid}/experience")]
[Authorize(Roles = "Admin")] // manual adjust
public async Task<IActionResult> AddExperience(Guid playerId, AdjustValueRequest r)
{
var p = await _playerService.AddPlayerExperienceAsync(playerId, r.Value);
return Ok(new { p.Id, p.Experience });
}
[HttpPost("{playerId:guid}/mana")]
[Authorize(Roles = "Admin")] // manual adjust
public async Task<IActionResult> AddMana(Guid playerId, AdjustValueRequest r)
{
var p = await _playerService.AddPlayerManaAsync(playerId, r.Value);
return Ok(new { p.Id, p.Mana });
}
[HttpGet("top")]
public async Task<IActionResult> GetTop([FromQuery] int count = 10)
{
var list = await _playerService.GetTopPlayersAsync(count, TimeSpan.FromDays(30));
return Ok(list);
}
[HttpGet("{playerId:guid}/progress")]
public async Task<IActionResult> GetProgress(Guid playerId)
{
var prog = await _progressService.GetPlayerOverallProgressAsync(playerId);
return Ok(prog);
}
}

View File

@@ -1,67 +1,67 @@
using System.Security.Claims;
using LctMonolith.Models.Database;
using LctMonolith.Services.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LctMonolith.Controllers;
[ApiController]
[Route("api/profile")]
[Authorize]
public class ProfileController : ControllerBase
{
private readonly IProfileService _profiles;
public ProfileController(IProfileService profiles) => _profiles = profiles;
private Guid CurrentUserId() => Guid.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!);
public class UpdateProfileDto
{
public string? FirstName { get; set; }
public string? LastName { get; set; }
public DateOnly? BirthDate { get; set; }
public string? About { get; set; }
public string? Location { get; set; }
}
[HttpGet("me")]
public async Task<IActionResult> GetMe(CancellationToken ct)
{
var p = await _profiles.GetByUserIdAsync(CurrentUserId(), ct);
if (p == null) return NotFound();
return Ok(p);
}
[HttpGet("{userId:guid}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> GetByUser(Guid userId, CancellationToken ct)
{
var p = await _profiles.GetByUserIdAsync(userId, ct);
return p == null ? NotFound() : Ok(p);
}
[HttpPut]
public async Task<IActionResult> Upsert(UpdateProfileDto dto, CancellationToken ct)
{
var p = await _profiles.UpsertAsync(CurrentUserId(), dto.FirstName, dto.LastName, dto.BirthDate, dto.About, dto.Location, ct);
return Ok(p);
}
[HttpPost("avatar")]
[RequestSizeLimit(7_000_000)] // ~7MB
public async Task<IActionResult> UploadAvatar(IFormFile file, CancellationToken ct)
{
if (file == null || file.Length == 0) return BadRequest("File required");
await using var stream = file.OpenReadStream();
var p = await _profiles.UpdateAvatarAsync(CurrentUserId(), stream, file.ContentType, file.FileName, ct);
return Ok(new { p.AvatarUrl });
}
[HttpDelete("avatar")]
public async Task<IActionResult> DeleteAvatar(CancellationToken ct)
{
var ok = await _profiles.DeleteAvatarAsync(CurrentUserId(), ct);
return ok ? NoContent() : NotFound();
}
}
using System.Security.Claims;
using LctMonolith.Models.Database;
using LctMonolith.Services.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LctMonolith.Controllers;
[ApiController]
[Route("api/profile")]
[Authorize]
public class ProfileController : ControllerBase
{
private readonly IProfileService _profiles;
public ProfileController(IProfileService profiles) => _profiles = profiles;
private Guid CurrentUserId() => Guid.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!);
public class UpdateProfileDto
{
public string? FirstName { get; set; }
public string? LastName { get; set; }
public DateOnly? BirthDate { get; set; }
public string? About { get; set; }
public string? Location { get; set; }
}
[HttpGet("me")]
public async Task<IActionResult> GetMe(CancellationToken ct)
{
var p = await _profiles.GetByUserIdAsync(CurrentUserId(), ct);
if (p == null) return NotFound();
return Ok(p);
}
[HttpGet("{userId:guid}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> GetByUser(Guid userId, CancellationToken ct)
{
var p = await _profiles.GetByUserIdAsync(userId, ct);
return p == null ? NotFound() : Ok(p);
}
[HttpPut]
public async Task<IActionResult> Upsert(UpdateProfileDto dto, CancellationToken ct)
{
var p = await _profiles.UpsertAsync(CurrentUserId(), dto.FirstName, dto.LastName, dto.BirthDate, dto.About, dto.Location, ct);
return Ok(p);
}
[HttpPost("avatar")]
[RequestSizeLimit(7_000_000)] // ~7MB
public async Task<IActionResult> UploadAvatar(IFormFile file, CancellationToken ct)
{
if (file == null || file.Length == 0) return BadRequest("File required");
await using var stream = file.OpenReadStream();
var p = await _profiles.UpdateAvatarAsync(CurrentUserId(), stream, file.ContentType, file.FileName, ct);
return Ok(new { p.AvatarUrl });
}
[HttpDelete("avatar")]
public async Task<IActionResult> DeleteAvatar(CancellationToken ct)
{
var ok = await _profiles.DeleteAvatarAsync(CurrentUserId(), ct);
return ok ? NoContent() : NotFound();
}
}

View File

@@ -1,72 +1,72 @@
using LctMonolith.Models.Database;
using LctMonolith.Models.DTO;
using LctMonolith.Services.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LctMonolith.Controllers;
[ApiController]
[Route("api/ranks")]
[Authorize]
public class RanksController : ControllerBase
{
private readonly IRankService _rankService;
private readonly IRuleValidationService _ruleValidation;
public RanksController(IRankService rankService, IRuleValidationService ruleValidation)
{
_rankService = rankService;
_ruleValidation = ruleValidation;
}
[HttpGet]
public async Task<IActionResult> GetAll()
{
var ranks = await _rankService.GetAllRanksAsync();
return Ok(ranks);
}
[HttpGet("{id:guid}")]
public async Task<IActionResult> Get(Guid id)
{
var r = await _rankService.GetRankByIdAsync(id);
return r == null ? NotFound() : Ok(r);
}
[HttpPost]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Create(CreateRankDto dto)
{
var rank = await _rankService.CreateRankAsync(new Rank { Title = dto.Title, ExpNeeded = dto.ExpNeeded });
return CreatedAtAction(nameof(Get), new { id = rank.Id }, rank);
}
[HttpPut("{id:guid}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Update(Guid id, CreateRankDto dto)
{
var r = await _rankService.GetRankByIdAsync(id);
if (r == null) return NotFound();
r.Title = dto.Title;
r.ExpNeeded = dto.ExpNeeded;
await _rankService.UpdateRankAsync(r);
return Ok(r);
}
[HttpDelete("{id:guid}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Delete(Guid id)
{
var ok = await _rankService.DeleteRankAsync(id);
return ok ? NoContent() : NotFound();
}
[HttpGet("validate-advance/{playerId:guid}/{targetRankId:guid}")]
public async Task<IActionResult> CanAdvance(Guid playerId, Guid targetRankId)
{
var ok = await _ruleValidation.ValidateRankAdvancementRulesAsync(playerId, targetRankId);
return Ok(new { playerId, targetRankId, canAdvance = ok });
}
}
using LctMonolith.Models.Database;
using LctMonolith.Models.DTO;
using LctMonolith.Services.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LctMonolith.Controllers;
[ApiController]
[Route("api/ranks")]
[Authorize]
public class RanksController : ControllerBase
{
private readonly IRankService _rankService;
private readonly IRuleValidationService _ruleValidation;
public RanksController(IRankService rankService, IRuleValidationService ruleValidation)
{
_rankService = rankService;
_ruleValidation = ruleValidation;
}
[HttpGet]
public async Task<IActionResult> GetAll()
{
var ranks = await _rankService.GetAllRanksAsync();
return Ok(ranks);
}
[HttpGet("{id:guid}")]
public async Task<IActionResult> Get(Guid id)
{
var r = await _rankService.GetRankByIdAsync(id);
return r == null ? NotFound() : Ok(r);
}
[HttpPost]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Create(CreateRankDto dto)
{
var rank = await _rankService.CreateRankAsync(new Rank { Title = dto.Title, ExpNeeded = dto.ExpNeeded });
return CreatedAtAction(nameof(Get), new { id = rank.Id }, rank);
}
[HttpPut("{id:guid}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Update(Guid id, CreateRankDto dto)
{
var r = await _rankService.GetRankByIdAsync(id);
if (r == null) return NotFound();
r.Title = dto.Title;
r.ExpNeeded = dto.ExpNeeded;
await _rankService.UpdateRankAsync(r);
return Ok(r);
}
[HttpDelete("{id:guid}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Delete(Guid id)
{
var ok = await _rankService.DeleteRankAsync(id);
return ok ? NoContent() : NotFound();
}
[HttpGet("validate-advance/{playerId:guid}/{targetRankId:guid}")]
public async Task<IActionResult> CanAdvance(Guid playerId, Guid targetRankId)
{
var ok = await _ruleValidation.ValidateRankAdvancementRulesAsync(playerId, targetRankId);
return Ok(new { playerId, targetRankId, canAdvance = ok });
}
}

View File

@@ -1,65 +1,65 @@
using LctMonolith.Services.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LctMonolith.Controllers;
[ApiController]
[Route("api/rewards")]
[Authorize]
public class RewardController : ControllerBase
{
private readonly IRewardService _rewardService;
public RewardController(IRewardService rewardService)
{
_rewardService = rewardService;
}
/// <summary>List skill rewards configured for a mission.</summary>
[HttpGet("mission/{missionId:guid}/skills")]
public async Task<IActionResult> GetMissionSkillRewards(Guid missionId)
{
var rewards = await _rewardService.GetMissionSkillRewardsAsync(missionId);
return Ok(rewards.Select(r => new { r.SkillId, r.Value }));
}
/// <summary>List item rewards configured for a mission.</summary>
[HttpGet("mission/{missionId:guid}/items")]
public async Task<IActionResult> GetMissionItemRewards(Guid missionId)
{
var rewards = await _rewardService.GetMissionItemRewardsAsync(missionId);
return Ok(rewards.Select(r => new { r.ItemId }));
}
/// <summary>Check if mission rewards can be claimed by player (missionId used as rewardId).</summary>
[HttpGet("mission/{missionId:guid}/can-claim/{playerId:guid}")]
public async Task<IActionResult> CanClaim(Guid missionId, Guid playerId)
{
var can = await _rewardService.CanClaimRewardAsync(missionId, playerId);
return Ok(new { missionId, playerId, canClaim = can });
}
public record ClaimRewardRequest(Guid PlayerId);
/// <summary>Claim mission rewards if available (idempotent on already claimed).</summary>
[HttpPost("mission/{missionId:guid}/claim")]
public async Task<IActionResult> Claim(Guid missionId, ClaimRewardRequest req)
{
var can = await _rewardService.CanClaimRewardAsync(missionId, req.PlayerId);
if (!can) return Conflict(new { message = "Rewards already claimed or mission not completed" });
await _rewardService.DistributeMissionRewardsAsync(missionId, req.PlayerId);
return Ok(new { missionId, req.PlayerId, status = "claimed" });
}
public record ForceDistributeRequest(Guid PlayerId);
/// <summary>Admin: force distribute rewards regardless of previous state (may duplicate). Use cautiously.</summary>
[HttpPost("mission/{missionId:guid}/force-distribute")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> ForceDistribute(Guid missionId, ForceDistributeRequest req)
{
await _rewardService.DistributeMissionRewardsAsync(missionId, req.PlayerId);
return Ok(new { missionId, req.PlayerId, status = "forced" });
}
}
using LctMonolith.Services.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LctMonolith.Controllers;
[ApiController]
[Route("api/rewards")]
[Authorize]
public class RewardController : ControllerBase
{
private readonly IRewardService _rewardService;
public RewardController(IRewardService rewardService)
{
_rewardService = rewardService;
}
/// <summary>List skill rewards configured for a mission.</summary>
[HttpGet("mission/{missionId:guid}/skills")]
public async Task<IActionResult> GetMissionSkillRewards(Guid missionId)
{
var rewards = await _rewardService.GetMissionSkillRewardsAsync(missionId);
return Ok(rewards.Select(r => new { r.SkillId, r.Value }));
}
/// <summary>List item rewards configured for a mission.</summary>
[HttpGet("mission/{missionId:guid}/items")]
public async Task<IActionResult> GetMissionItemRewards(Guid missionId)
{
var rewards = await _rewardService.GetMissionItemRewardsAsync(missionId);
return Ok(rewards.Select(r => new { r.ItemId }));
}
/// <summary>Check if mission rewards can be claimed by player (missionId used as rewardId).</summary>
[HttpGet("mission/{missionId:guid}/can-claim/{playerId:guid}")]
public async Task<IActionResult> CanClaim(Guid missionId, Guid playerId)
{
var can = await _rewardService.CanClaimRewardAsync(missionId, playerId);
return Ok(new { missionId, playerId, canClaim = can });
}
public record ClaimRewardRequest(Guid PlayerId);
/// <summary>Claim mission rewards if available (idempotent on already claimed).</summary>
[HttpPost("mission/{missionId:guid}/claim")]
public async Task<IActionResult> Claim(Guid missionId, ClaimRewardRequest req)
{
var can = await _rewardService.CanClaimRewardAsync(missionId, req.PlayerId);
if (!can) return Conflict(new { message = "Rewards already claimed or mission not completed" });
await _rewardService.DistributeMissionRewardsAsync(missionId, req.PlayerId);
return Ok(new { missionId, req.PlayerId, status = "claimed" });
}
public record ForceDistributeRequest(Guid PlayerId);
/// <summary>Admin: force distribute rewards regardless of previous state (may duplicate). Use cautiously.</summary>
[HttpPost("mission/{missionId:guid}/force-distribute")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> ForceDistribute(Guid missionId, ForceDistributeRequest req)
{
await _rewardService.DistributeMissionRewardsAsync(missionId, req.PlayerId);
return Ok(new { missionId, req.PlayerId, status = "forced" });
}
}

View File

@@ -1,79 +1,79 @@
using LctMonolith.Models.Database;
using LctMonolith.Models.DTO;
using LctMonolith.Services.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LctMonolith.Controllers;
[ApiController]
[Route("api/skills")]
[Authorize]
public class SkillsController : ControllerBase
{
private readonly ISkillService _skillService;
public SkillsController(ISkillService skillService)
{
_skillService = skillService;
}
[HttpGet]
public async Task<IActionResult> GetAll()
{
var list = await _skillService.GetAllSkillsAsync();
return Ok(list);
}
[HttpGet("{id:guid}")]
public async Task<IActionResult> Get(Guid id)
{
var s = await _skillService.GetSkillByIdAsync(id);
return s == null ? NotFound() : Ok(s);
}
[HttpPost]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Create(CreateSkillDto dto)
{
var skill = await _skillService.CreateSkillAsync(new Skill { Title = dto.Title });
return CreatedAtAction(nameof(Get), new { id = skill.Id }, skill);
}
[HttpPut("{id:guid}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Update(Guid id, CreateSkillDto dto)
{
var s = await _skillService.GetSkillByIdAsync(id);
if (s == null) return NotFound();
s.Title = dto.Title;
await _skillService.UpdateSkillAsync(s);
return Ok(s);
}
[HttpDelete("{id:guid}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Delete(Guid id)
{
var ok = await _skillService.DeleteSkillAsync(id);
return ok ? NoContent() : NotFound();
}
[HttpGet("player/{playerId:guid}")]
public async Task<IActionResult> PlayerSkills(Guid playerId)
{
var list = await _skillService.GetPlayerSkillsAsync(playerId);
return Ok(list);
}
public record UpdatePlayerSkillRequest(int Level);
[HttpPost("player/{playerId:guid}/{skillId:guid}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> UpdatePlayerSkill(Guid playerId, Guid skillId, UpdatePlayerSkillRequest r)
{
var ps = await _skillService.UpdatePlayerSkillAsync(playerId, skillId, r.Level);
return Ok(new { ps.PlayerId, ps.SkillId, ps.Score });
}
}
using LctMonolith.Models.Database;
using LctMonolith.Models.DTO;
using LctMonolith.Services.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LctMonolith.Controllers;
[ApiController]
[Route("api/skills")]
[Authorize]
public class SkillsController : ControllerBase
{
private readonly ISkillService _skillService;
public SkillsController(ISkillService skillService)
{
_skillService = skillService;
}
[HttpGet]
public async Task<IActionResult> GetAll()
{
var list = await _skillService.GetAllSkillsAsync();
return Ok(list);
}
[HttpGet("{id:guid}")]
public async Task<IActionResult> Get(Guid id)
{
var s = await _skillService.GetSkillByIdAsync(id);
return s == null ? NotFound() : Ok(s);
}
[HttpPost]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Create(CreateSkillDto dto)
{
var skill = await _skillService.CreateSkillAsync(new Skill { Title = dto.Title });
return CreatedAtAction(nameof(Get), new { id = skill.Id }, skill);
}
[HttpPut("{id:guid}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Update(Guid id, CreateSkillDto dto)
{
var s = await _skillService.GetSkillByIdAsync(id);
if (s == null) return NotFound();
s.Title = dto.Title;
await _skillService.UpdateSkillAsync(s);
return Ok(s);
}
[HttpDelete("{id:guid}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Delete(Guid id)
{
var ok = await _skillService.DeleteSkillAsync(id);
return ok ? NoContent() : NotFound();
}
[HttpGet("player/{playerId:guid}")]
public async Task<IActionResult> PlayerSkills(Guid playerId)
{
var list = await _skillService.GetPlayerSkillsAsync(playerId);
return Ok(list);
}
public record UpdatePlayerSkillRequest(int Level);
[HttpPost("player/{playerId:guid}/{skillId:guid}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> UpdatePlayerSkill(Guid playerId, Guid skillId, UpdatePlayerSkillRequest r)
{
var ps = await _skillService.UpdatePlayerSkillAsync(playerId, skillId, r.Level);
return Ok(new { ps.PlayerId, ps.SkillId, ps.Score });
}
}

View File

@@ -1,43 +1,43 @@
using System.Security.Claims;
using LctMonolith.Services;
using LctMonolith.Services.Contracts;
using LctMonolith.Services.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LctMonolith.Controllers;
/// <summary>
/// Store endpoints for listing items and purchasing.
/// </summary>
[ApiController]
[Route("api/store")]
[Authorize]
public class StoreController : ControllerBase
{
private readonly IStoreService _storeService;
public StoreController(IStoreService storeService)
{
_storeService = storeService;
}
private Guid GetUserId() => Guid.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!);
/// <summary>List active store items.</summary>
[HttpGet("items")]
public async Task<IActionResult> GetItems(CancellationToken ct)
{
var items = await _storeService.GetActiveItemsAsync(ct);
return Ok(items);
}
/// <summary>Purchase an item for the authenticated user.</summary>
[HttpPost("purchase")]
public async Task<IActionResult> Purchase(PurchaseRequest req, CancellationToken ct)
{
var inv = await _storeService.PurchaseAsync(GetUserId(), req.ItemId, req.Quantity, ct);
return Ok(new { inv.StoreItemId, inv.Quantity, inv.AcquiredAt });
}
}
using System.Security.Claims;
using LctMonolith.Services;
using LctMonolith.Services.Contracts;
using LctMonolith.Services.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LctMonolith.Controllers;
/// <summary>
/// Store endpoints for listing items and purchasing.
/// </summary>
[ApiController]
[Route("api/store")]
[Authorize]
public class StoreController : ControllerBase
{
private readonly IStoreService _storeService;
public StoreController(IStoreService storeService)
{
_storeService = storeService;
}
private Guid GetUserId() => Guid.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!);
/// <summary>List active store items.</summary>
[HttpGet("items")]
public async Task<IActionResult> GetItems(CancellationToken ct)
{
var items = await _storeService.GetActiveItemsAsync(ct);
return Ok(items);
}
/// <summary>Purchase an item for the authenticated user.</summary>
[HttpPost("purchase")]
public async Task<IActionResult> Purchase(PurchaseRequest req, CancellationToken ct)
{
var inv = await _storeService.PurchaseAsync(GetUserId(), req.ItemId, req.Quantity, ct);
return Ok(new { inv.StoreItemId, inv.Quantity, inv.AcquiredAt });
}
}