< Summary

Information
Class: Chronicis.Client.Services.QuestApiService
Assembly: Chronicis.Client
File(s): /home/runner/work/chronicis/chronicis/src/Chronicis.Client/Services/QuestApiService.cs
Line coverage
100%
Covered lines: 4
Uncovered lines: 0
Coverable lines: 4
Total lines: 120
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%

File(s)

/home/runner/work/chronicis/chronicis/src/Chronicis.Client/Services/QuestApiService.cs

#LineLine coverage
 1using System.Net.Http.Json;
 2using Chronicis.Shared.DTOs.Quests;
 3using MudBlazor;
 4
 5namespace Chronicis.Client.Services;
 6
 7/// <summary>
 8/// Service for communicating with the Quest API.
 9/// Uses HttpClientExtensions for consistent error handling and logging.
 10/// Handles RowVersion concurrency for quest updates.
 11/// </summary>
 12public class QuestApiService : IQuestApiService
 13{
 14    private readonly HttpClient _http;
 15    private readonly ILogger<QuestApiService> _logger;
 16    private readonly ISnackbar _snackbar;
 17
 18    public QuestApiService(
 19        HttpClient http,
 20        ILogger<QuestApiService> logger,
 21        ISnackbar snackbar)
 22    {
 723        _http = http;
 724        _logger = logger;
 725        _snackbar = snackbar;
 726    }
 27
 28    public async Task<List<QuestDto>> GetArcQuestsAsync(Guid arcId)
 29    {
 30        return await _http.GetListAsync<QuestDto>(
 31            $"arcs/{arcId}/quests",
 32            _logger,
 33            $"quests for arc {arcId}");
 34    }
 35
 36    public async Task<QuestDto?> GetQuestAsync(Guid questId)
 37    {
 38        return await _http.GetEntityAsync<QuestDto>(
 39            $"quests/{questId}",
 40            _logger,
 41            $"quest {questId}");
 42    }
 43
 44    public async Task<QuestDto?> CreateQuestAsync(Guid arcId, QuestCreateDto createDto)
 45    {
 46        return await _http.PostEntityAsync<QuestDto>(
 47            $"arcs/{arcId}/quests",
 48            createDto,
 49            _logger,
 50            "create quest");
 51    }
 52
 53    public async Task<QuestDto?> UpdateQuestAsync(Guid questId, QuestEditDto editDto)
 54    {
 55        try
 56        {
 57            var response = await _http.PutAsJsonAsync($"quests/{questId}", editDto);
 58
 59            if (response.StatusCode == System.Net.HttpStatusCode.Conflict)
 60            {
 61                // 409 Conflict - rowversion mismatch
 62                _logger.LogWarning("Quest {QuestId} update conflict (stale RowVersion)", questId);
 63
 64                // Read the current server state from response body
 65                var currentQuest = await response.Content.ReadFromJsonAsync<QuestDto>();
 66                if (currentQuest != null)
 67                {
 68                    _snackbar.Add("Quest was modified by another user. Changes reloaded.", Severity.Warning);
 69                    return currentQuest;
 70                }
 71
 72                _snackbar.Add("Quest update conflict. Please reload.", Severity.Error);
 73                return null;
 74            }
 75
 76            response.EnsureSuccessStatusCode();
 77            return await response.Content.ReadFromJsonAsync<QuestDto>();
 78        }
 79        catch (Exception ex)
 80        {
 81            _logger.LogError(ex, "Failed to update quest {QuestId}", questId);
 82            _snackbar.Add("Failed to update quest", Severity.Error);
 83            return null;
 84        }
 85    }
 86
 87    public async Task<bool> DeleteQuestAsync(Guid questId)
 88    {
 89        return await _http.DeleteEntityAsync(
 90            $"quests/{questId}",
 91            _logger,
 92            $"quest {questId}");
 93    }
 94
 95    public async Task<PagedResult<QuestUpdateEntryDto>> GetQuestUpdatesAsync(Guid questId, int skip = 0, int take = 20)
 96    {
 97        return await _http.GetEntityAsync<PagedResult<QuestUpdateEntryDto>>(
 98            $"quests/{questId}/updates?skip={skip}&take={take}",
 99            _logger,
 100            $"updates for quest {questId}")
 101            ?? new PagedResult<QuestUpdateEntryDto>();
 102    }
 103
 104    public async Task<QuestUpdateEntryDto?> AddQuestUpdateAsync(Guid questId, QuestUpdateCreateDto createDto)
 105    {
 106        return await _http.PostEntityAsync<QuestUpdateEntryDto>(
 107            $"quests/{questId}/updates",
 108            createDto,
 109            _logger,
 110            "add quest update");
 111    }
 112
 113    public async Task<bool> DeleteQuestUpdateAsync(Guid questId, Guid updateId)
 114    {
 115        return await _http.DeleteEntityAsync(
 116            $"quests/{questId}/updates/{updateId}",
 117            _logger,
 118            $"quest update {updateId}");
 119    }
 120}