226 lines
11 KiB
C#
226 lines
11 KiB
C#
using Blueberry.Redmine.Dto;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace Blueberry.Redmine
|
|
{
|
|
public class RedmineManager
|
|
{
|
|
private readonly TimeSpan DEFAULT_CACHE_DURATION = TimeSpan.FromHours(3);
|
|
private readonly RedmineConfig _config;
|
|
private readonly ILogger _logger;
|
|
private readonly RedmineApiClient _apiClient;
|
|
private readonly RedmineCache<StatusList.IssueStatus> _statusCache;
|
|
private readonly RedmineCache<PriorityList.IssuePriority> _priorityCache;
|
|
private readonly RedmineCache<CustomFieldList.CustomField> _customFieldCache;
|
|
private readonly RedmineCache<ProjectList.Project> _projectCache;
|
|
private readonly RedmineCache<UserInfo.User> _userCache;
|
|
|
|
public RedmineManager(RedmineConfig config, HttpClient client, ILoggerFactory loggerFactory)
|
|
{
|
|
_config = config;
|
|
_apiClient = new RedmineApiClient(config, loggerFactory.CreateLogger<RedmineApiClient>(), client);
|
|
|
|
_statusCache = new RedmineCache<StatusList.IssueStatus>(
|
|
DEFAULT_CACHE_DURATION, loggerFactory.CreateLogger<RedmineCache<StatusList.IssueStatus>>(), cacheFilePath: $"{_config.CacheFilePath}Statuses.json");
|
|
|
|
_priorityCache = new RedmineCache<PriorityList.IssuePriority>(
|
|
DEFAULT_CACHE_DURATION, loggerFactory.CreateLogger<RedmineCache<PriorityList.IssuePriority>>(), cacheFilePath: $"{_config.CacheFilePath}Priorities.json");
|
|
|
|
_customFieldCache = new RedmineCache<CustomFieldList.CustomField>(
|
|
DEFAULT_CACHE_DURATION, loggerFactory.CreateLogger<RedmineCache<CustomFieldList.CustomField>>(), cacheFilePath: $"{_config.CacheFilePath}CustomFields.json");
|
|
|
|
_projectCache = new RedmineCache<ProjectList.Project>(
|
|
DEFAULT_CACHE_DURATION, loggerFactory.CreateLogger<RedmineCache<ProjectList.Project>>(), cacheFilePath: $"{_config.CacheFilePath}Projects.json");
|
|
|
|
_userCache = new RedmineCache<UserInfo.User>(
|
|
DEFAULT_CACHE_DURATION, loggerFactory.CreateLogger<RedmineCache<UserInfo.User>>(), cacheFilePath: $"{_config.CacheFilePath}Users.json");
|
|
|
|
_logger = loggerFactory.CreateLogger<RedmineManager>();
|
|
_logger.LogDebug("Initialized caches");
|
|
}
|
|
|
|
public async Task<bool> IsRedmineAvailable(CancellationToken? token = null)
|
|
{
|
|
try
|
|
{
|
|
await _apiClient.GetUserAsync(token: token);
|
|
return true;
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public async Task<IReadOnlyList<StatusList.IssueStatus>> GetStatusesAsync(CancellationToken? token = null)
|
|
{
|
|
if (_statusCache.IsCacheValid())
|
|
{
|
|
return await _statusCache.GetItemsAsync();
|
|
}
|
|
var statuses = await _apiClient.GetStatusesAsync(token);
|
|
await _statusCache.RefreshCacheAsync(statuses);
|
|
return statuses;
|
|
}
|
|
|
|
public async Task<IReadOnlyList<PriorityList.IssuePriority>> GetPrioritiesAsync(CancellationToken? token = null)
|
|
{
|
|
if (_priorityCache.IsCacheValid())
|
|
{
|
|
return await _priorityCache.GetItemsAsync();
|
|
}
|
|
var priorities = await _apiClient.GetPrioritiesAsync(token);
|
|
await _priorityCache.RefreshCacheAsync(priorities);
|
|
return priorities;
|
|
}
|
|
|
|
public async Task<IReadOnlyList<CustomFieldList.CustomField>> GetCustomFieldsAsync(CancellationToken? token = null)
|
|
{
|
|
if (_customFieldCache.IsCacheValid())
|
|
{
|
|
return await _customFieldCache.GetItemsAsync();
|
|
}
|
|
var fields = await _apiClient.GetCustomFieldsAsync(token);
|
|
await _customFieldCache.RefreshCacheAsync(fields);
|
|
return fields;
|
|
}
|
|
|
|
public async Task<IReadOnlyList<ProjectList.Project>> GetProjectsAsync(int limit = 50, IProgress<(int, int)>? progress = null, CancellationToken? token = null)
|
|
{
|
|
if (_projectCache.IsCacheValid())
|
|
{
|
|
return await _projectCache.GetItemsAsync();
|
|
}
|
|
var projects = await _apiClient.GetProjectsAsync(limit, progress, token);
|
|
await _projectCache.RefreshCacheAsync(projects);
|
|
return projects;
|
|
}
|
|
|
|
public async Task<IReadOnlyList<UserInfo.User>> GetUsersAsync(int limit = 50, IProgress<(int, int)>? progress = null, CancellationToken? token = null)
|
|
{
|
|
if (_userCache.IsCacheValid())
|
|
{
|
|
return await _userCache.GetItemsAsync();
|
|
}
|
|
var users = await _apiClient.GetUsersAsync(limit, progress, token);
|
|
await _userCache.RefreshCacheAsync(users);
|
|
return users;
|
|
}
|
|
|
|
public async Task<UserInfo.User> GetCurrentUserAsync(CancellationToken? token = null)
|
|
{
|
|
var user = await _apiClient.GetUserAsync(token: token);
|
|
return user;
|
|
}
|
|
|
|
public async Task<UserInfo.User> GetUserAsync(int userId, CancellationToken? token = null)
|
|
{
|
|
var user = await _apiClient.GetUserAsync(userId, token: token);
|
|
return user;
|
|
}
|
|
|
|
public async Task<List<IssueList.Issue>> GetCurrentUserOpenIssuesAsync(int limit = 50, IProgress<(int, int)>? progress = null, CancellationToken? token = null)
|
|
{
|
|
var user = await GetCurrentUserAsync(token);
|
|
return await _apiClient.GetOpenIssuesByAssigneeAsync(user.Id, limit, progress, token);
|
|
}
|
|
|
|
public async Task<List<IssueList.Issue>> GetUserOpenIssuesAsync(int userId, int limit = 50, IProgress<(int, int)>? progress = null, CancellationToken? token = null)
|
|
{
|
|
return await _apiClient.GetOpenIssuesByAssigneeAsync(userId, limit, progress, token);
|
|
}
|
|
|
|
public async Task<List<IssueList.Issue>> GetIssuesAsync(
|
|
int? userId = null,
|
|
string? projectId = null,
|
|
int? statusId = null,
|
|
bool? isOpen = null,
|
|
// Changed single dates to From/To pairs
|
|
DateTime? createdFrom = null,
|
|
DateTime? createdTo = null,
|
|
DateTime? updatedFrom = null,
|
|
DateTime? updatedTo = null,
|
|
int limit = 50,
|
|
IProgress<(int, int)>? progress = null,
|
|
CancellationToken? token = null)
|
|
{
|
|
return await _apiClient.GetIssuesAsync(userId, projectId, statusId, isOpen, createdFrom, createdTo, updatedFrom, updatedTo, limit, progress, token);
|
|
}
|
|
|
|
public async Task AddComment(int issueId, string comment, bool isPrivate = false, CancellationToken? token = null)
|
|
{
|
|
await _apiClient.AddCommentToIssueAsync(issueId, comment, isPrivate, token);
|
|
}
|
|
|
|
public async Task<double> GetCurrentUserTimeAsync(DateTime start, DateTime end, int limit = 50, IProgress<(int, int)>? progress = null, CancellationToken? token = null)
|
|
{
|
|
var user = await GetCurrentUserAsync(token);
|
|
return await _apiClient.GetTotalTimeForUserAsync(user.Id, start, end, limit, progress, token);
|
|
}
|
|
|
|
public async Task<double> GetUserTimeAsync(int userId, DateTime start, DateTime end, int limit = 50, IProgress<(int, int)>? progress = null, CancellationToken? token = null)
|
|
{
|
|
return await _apiClient.GetTotalTimeForUserAsync(userId, start, end, limit, progress, token);
|
|
}
|
|
|
|
public async Task<DetailedIssue.Issue> GetIssueAsync(int issueId, CancellationToken? token = null)
|
|
{
|
|
return await _apiClient.GetIssueAsync(issueId, token);
|
|
}
|
|
|
|
public async Task<IssueList.Issue> GetSimpleIssueAsync(int issueId, CancellationToken? token = null)
|
|
{
|
|
return await _apiClient.GetSimpleIssueAsync(issueId, token);
|
|
}
|
|
|
|
public async Task<List<ProjectTrackers.Tracker>> GetProjectTrackersAsync(int projectId, CancellationToken? token = null)
|
|
{
|
|
return await _apiClient.GetTrackersForProjectAsync(projectId.ToString(), token);
|
|
}
|
|
|
|
public async Task<List<TimeOnIssue.TimeEntry>> GetTimeOnIssue(int issueId, int limit = 25, IProgress<(int, int)>? progress = null, CancellationToken? token = null)
|
|
{
|
|
var result = await _apiClient.GetTimeOnIssueAsync(issueId, limit, progress, token);
|
|
return result;
|
|
}
|
|
|
|
public async Task SetIssueStatusAsync(int issueId, int statusId, CancellationToken? token = null)
|
|
{
|
|
await _apiClient.SetIssueStatusAsync(issueId, statusId, token);
|
|
}
|
|
|
|
public async Task LogTimeAsync(int issueId, double hours, string comments, DateTime? date = null, int? activityId = null, CancellationToken? token = null)
|
|
{
|
|
await _apiClient.LogTimeAsync(issueId, hours, comments, date, activityId, token);
|
|
}
|
|
|
|
public async Task<int> CreateIssueAsync(int projectId, int trackerId, string subject, string description,
|
|
double estimatedHours, int priorityId, int? assigneeId = null, int? parentIssueId = null, CancellationToken? token = null)
|
|
{
|
|
return await _apiClient.CreateNewIssueAsync(projectId, trackerId, subject, description, estimatedHours, priorityId, assigneeId, parentIssueId, token);
|
|
}
|
|
|
|
public async Task<double> GetCurrentUserTimeTodayAsync(int limit = 50, IProgress<(int, int)>? progress = null, CancellationToken? token = null)
|
|
{
|
|
return await GetCurrentUserTimeAsync(DateTime.Today, DateTime.Today, limit, progress, token);
|
|
}
|
|
|
|
public async Task<double> GetCurrentUserTimeYesterdayAsync(int limit = 50, IProgress<(int, int)>? progress = null, CancellationToken? token = null)
|
|
{
|
|
return await GetCurrentUserTimeAsync(DateTime.Today.AddDays(-1), DateTime.Today.AddDays(-1), limit, progress, token);
|
|
}
|
|
|
|
public async Task<double> GetCurrentUserTimeThisMonthAsync(int limit = 50, IProgress<(int, int)>? progress = null, CancellationToken? token = null)
|
|
{
|
|
var start = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1);
|
|
var end = start.AddMonths(1).AddDays(-1);
|
|
return await GetCurrentUserTimeAsync(start, end, limit, progress, token);
|
|
}
|
|
|
|
public async Task<List<UserTime.TimeEntry>> GetTimeForUserAsync(int userId, DateTime start, DateTime end, int limit = 50, IProgress<(int, int)>? progress = null, CancellationToken? token = null)
|
|
{
|
|
return await _apiClient.GetTimeForUserAsync(userId, start, end, limit, progress, token);
|
|
}
|
|
}
|
|
}
|