209 lines
6.8 KiB
C#
209 lines
6.8 KiB
C#
using CarneiroTech.Models;
|
|
using Microsoft.Extensions.Caching.Memory;
|
|
using System.Globalization;
|
|
|
|
namespace CarneiroTech.Services;
|
|
|
|
public class CaseService : ICaseService
|
|
{
|
|
private readonly IMarkdownService _markdownService;
|
|
private readonly IMemoryCache _cache;
|
|
private readonly IWebHostEnvironment _environment;
|
|
private readonly ILanguageService _languageService;
|
|
private readonly IHttpContextAccessor _httpContextAccessor;
|
|
private readonly string _casesBasePath;
|
|
private const string CACHE_KEY_PREFIX = "cases_";
|
|
private const int CACHE_MINUTES = 60;
|
|
|
|
public CaseService(IMarkdownService markdownService, IMemoryCache cache, IWebHostEnvironment environment,
|
|
ILanguageService languageService, IHttpContextAccessor httpContextAccessor)
|
|
{
|
|
_markdownService = markdownService;
|
|
_cache = cache;
|
|
_environment = environment;
|
|
_languageService = languageService;
|
|
_httpContextAccessor = httpContextAccessor;
|
|
_casesBasePath = Path.Combine(_environment.ContentRootPath, "Content", "Cases");
|
|
}
|
|
|
|
private string GetCurrentLanguage()
|
|
{
|
|
if (_httpContextAccessor.HttpContext != null)
|
|
{
|
|
return _languageService.GetCurrentLanguage(_httpContextAccessor.HttpContext);
|
|
}
|
|
return "pt"; // Default fallback
|
|
}
|
|
|
|
private string GetCasesPath(string language)
|
|
{
|
|
return Path.Combine(_casesBasePath, language);
|
|
}
|
|
|
|
public async Task<List<CaseModel>> GetAllCasesAsync()
|
|
{
|
|
var language = GetCurrentLanguage();
|
|
var cacheKey = $"{CACHE_KEY_PREFIX}{language}";
|
|
|
|
if (_cache.TryGetValue(cacheKey, out List<CaseModel>? cachedCases) && cachedCases != null)
|
|
{
|
|
return cachedCases;
|
|
}
|
|
|
|
var cases = new List<CaseModel>();
|
|
var casesPath = GetCasesPath(language);
|
|
|
|
if (!Directory.Exists(casesPath))
|
|
{
|
|
// Try Portuguese as fallback
|
|
casesPath = GetCasesPath("pt");
|
|
if (!Directory.Exists(casesPath))
|
|
{
|
|
Directory.CreateDirectory(casesPath);
|
|
return cases;
|
|
}
|
|
}
|
|
|
|
var markdownFiles = Directory.GetFiles(casesPath, "*.md");
|
|
|
|
foreach (var file in markdownFiles)
|
|
{
|
|
var caseModel = await ParseCaseFileAsync(file);
|
|
if (caseModel != null)
|
|
{
|
|
cases.Add(caseModel);
|
|
}
|
|
}
|
|
|
|
// Sort by order (ascending) and date (descending)
|
|
cases = cases.OrderBy(c => c.Metadata.Order)
|
|
.ThenByDescending(c => c.Metadata.Date)
|
|
.ToList();
|
|
|
|
_cache.Set(cacheKey, cases, TimeSpan.FromMinutes(CACHE_MINUTES));
|
|
|
|
return cases;
|
|
}
|
|
|
|
public async Task<List<CaseModel>> GetFeaturedCasesAsync()
|
|
{
|
|
var allCases = await GetAllCasesAsync();
|
|
return allCases.Where(c => c.Metadata.Featured).ToList();
|
|
}
|
|
|
|
public async Task<CaseModel?> GetCaseBySlugAsync(string slug)
|
|
{
|
|
var allCases = await GetAllCasesAsync();
|
|
return allCases.FirstOrDefault(c => c.Metadata.Slug.Equals(slug, StringComparison.OrdinalIgnoreCase));
|
|
}
|
|
|
|
public async Task<List<string>> GetAllTagsAsync()
|
|
{
|
|
var allCases = await GetAllCasesAsync();
|
|
var tags = allCases.SelectMany(c => c.Metadata.Tags)
|
|
.Distinct()
|
|
.OrderBy(t => t)
|
|
.ToList();
|
|
return tags;
|
|
}
|
|
|
|
public async Task<List<CaseModel>> GetCasesByTagAsync(string tag)
|
|
{
|
|
var allCases = await GetAllCasesAsync();
|
|
return allCases.Where(c => c.Metadata.Tags.Contains(tag, StringComparer.OrdinalIgnoreCase))
|
|
.ToList();
|
|
}
|
|
|
|
private async Task<CaseModel?> ParseCaseFileAsync(string filePath)
|
|
{
|
|
try
|
|
{
|
|
var content = await File.ReadAllTextAsync(filePath);
|
|
var frontMatter = _markdownService.ParseFrontMatter(content, out string bodyContent);
|
|
|
|
var metadata = new CaseMetadata
|
|
{
|
|
Title = GetStringValue(frontMatter, "title"),
|
|
Slug = GetStringValue(frontMatter, "slug"),
|
|
Summary = GetStringValue(frontMatter, "summary"),
|
|
Client = GetStringValue(frontMatter, "client"),
|
|
Industry = GetStringValue(frontMatter, "industry"),
|
|
Timeline = GetStringValue(frontMatter, "timeline"),
|
|
Role = GetStringValue(frontMatter, "role"),
|
|
Image = GetStringValue(frontMatter, "image"),
|
|
Tags = GetListValue(frontMatter, "tags"),
|
|
Featured = GetBoolValue(frontMatter, "featured"),
|
|
Order = GetIntValue(frontMatter, "order"),
|
|
Date = GetDateValue(frontMatter, "date"),
|
|
SeoTitle = GetStringValue(frontMatter, "seo_title"),
|
|
SeoDescription = GetStringValue(frontMatter, "seo_description"),
|
|
SeoKeywords = GetStringValue(frontMatter, "seo_keywords")
|
|
};
|
|
|
|
var htmlContent = _markdownService.ConvertToHtml(bodyContent);
|
|
|
|
return new CaseModel
|
|
{
|
|
Metadata = metadata,
|
|
ContentHtml = htmlContent,
|
|
ContentMarkdown = bodyContent
|
|
};
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// Log error here if needed
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private string GetStringValue(Dictionary<string, object> dict, string key)
|
|
{
|
|
return dict.ContainsKey(key) ? dict[key]?.ToString() ?? string.Empty : string.Empty;
|
|
}
|
|
|
|
private List<string> GetListValue(Dictionary<string, object> dict, string key)
|
|
{
|
|
if (!dict.ContainsKey(key)) return new List<string>();
|
|
|
|
if (dict[key] is List<object> list)
|
|
{
|
|
return list.Select(item => item?.ToString() ?? string.Empty).ToList();
|
|
}
|
|
|
|
return new List<string>();
|
|
}
|
|
|
|
private bool GetBoolValue(Dictionary<string, object> dict, string key)
|
|
{
|
|
if (!dict.ContainsKey(key)) return false;
|
|
|
|
var value = dict[key]?.ToString()?.ToLower();
|
|
return value == "true" || value == "yes" || value == "1";
|
|
}
|
|
|
|
private int GetIntValue(Dictionary<string, object> dict, string key)
|
|
{
|
|
if (!dict.ContainsKey(key)) return 0;
|
|
|
|
if (int.TryParse(dict[key]?.ToString(), out int result))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
private DateTime GetDateValue(Dictionary<string, object> dict, string key)
|
|
{
|
|
if (!dict.ContainsKey(key)) return DateTime.MinValue;
|
|
|
|
var dateString = dict[key]?.ToString();
|
|
if (DateTime.TryParse(dateString, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime result))
|
|
{
|
|
return result;
|
|
}
|
|
|
|
return DateTime.MinValue;
|
|
}
|
|
}
|