feat: FAQ 목록 API 구현 (#82)
All checks were successful
SPMS_API/pipeline/head This commit looks good
All checks were successful
SPMS_API/pipeline/head This commit looks good
Reviewed-on: https://git.ipstein.myds.me/SPMS/SPMS_API/pulls/83
This commit is contained in:
commit
0ead7a4bcb
32
SPMS.API/Controllers/FaqController.cs
Normal file
32
SPMS.API/Controllers/FaqController.cs
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Swashbuckle.AspNetCore.Annotations;
|
||||||
|
using SPMS.Application.DTOs.Faq;
|
||||||
|
using SPMS.Application.Interfaces;
|
||||||
|
using SPMS.Domain.Common;
|
||||||
|
|
||||||
|
namespace SPMS.API.Controllers;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("v1/in/public/faq")]
|
||||||
|
[ApiExplorerSettings(GroupName = "public")]
|
||||||
|
public class FaqController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IFaqService _faqService;
|
||||||
|
|
||||||
|
public FaqController(IFaqService faqService)
|
||||||
|
{
|
||||||
|
_faqService = faqService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("list")]
|
||||||
|
[SwaggerOperation(Summary = "FAQ 목록", Description = "활성화된 FAQ 목록을 조회합니다. category로 필터링 가능.")]
|
||||||
|
public async Task<IActionResult> GetListAsync([FromBody] FaqListRequestDto request)
|
||||||
|
{
|
||||||
|
var serviceCode = Request.Headers["X-Service-Code"].FirstOrDefault();
|
||||||
|
if (string.IsNullOrWhiteSpace(serviceCode))
|
||||||
|
return BadRequest(ApiResponse.Fail(ErrorCodes.BadRequest, "X-Service-Code 헤더가 필요합니다."));
|
||||||
|
|
||||||
|
var result = await _faqService.GetListAsync(serviceCode, request);
|
||||||
|
return Ok(ApiResponse<FaqListResponseDto>.Success(result));
|
||||||
|
}
|
||||||
|
}
|
||||||
6
SPMS.Application/DTOs/Faq/FaqListRequestDto.cs
Normal file
6
SPMS.Application/DTOs/Faq/FaqListRequestDto.cs
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
namespace SPMS.Application.DTOs.Faq;
|
||||||
|
|
||||||
|
public class FaqListRequestDto
|
||||||
|
{
|
||||||
|
public string? Category { get; set; }
|
||||||
|
}
|
||||||
30
SPMS.Application/DTOs/Faq/FaqListResponseDto.cs
Normal file
30
SPMS.Application/DTOs/Faq/FaqListResponseDto.cs
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace SPMS.Application.DTOs.Faq;
|
||||||
|
|
||||||
|
public class FaqListResponseDto
|
||||||
|
{
|
||||||
|
[JsonPropertyName("items")]
|
||||||
|
public List<FaqItemDto> Items { get; set; } = new();
|
||||||
|
|
||||||
|
[JsonPropertyName("total_count")]
|
||||||
|
public int TotalCount { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FaqItemDto
|
||||||
|
{
|
||||||
|
[JsonPropertyName("faq_id")]
|
||||||
|
public long FaqId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("category")]
|
||||||
|
public string? Category { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("question")]
|
||||||
|
public string Question { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonPropertyName("answer")]
|
||||||
|
public string Answer { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonPropertyName("sort_order")]
|
||||||
|
public int SortOrder { get; set; }
|
||||||
|
}
|
||||||
|
|
@ -14,6 +14,7 @@ public static class DependencyInjection
|
||||||
services.AddScoped<IServiceManagementService, ServiceManagementService>();
|
services.AddScoped<IServiceManagementService, ServiceManagementService>();
|
||||||
services.AddScoped<INoticeService, NoticeService>();
|
services.AddScoped<INoticeService, NoticeService>();
|
||||||
services.AddScoped<IBannerService, BannerService>();
|
services.AddScoped<IBannerService, BannerService>();
|
||||||
|
services.AddScoped<IFaqService, FaqService>();
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
8
SPMS.Application/Interfaces/IFaqService.cs
Normal file
8
SPMS.Application/Interfaces/IFaqService.cs
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
using SPMS.Application.DTOs.Faq;
|
||||||
|
|
||||||
|
namespace SPMS.Application.Interfaces;
|
||||||
|
|
||||||
|
public interface IFaqService
|
||||||
|
{
|
||||||
|
Task<FaqListResponseDto> GetListAsync(string serviceCode, FaqListRequestDto request);
|
||||||
|
}
|
||||||
41
SPMS.Application/Services/FaqService.cs
Normal file
41
SPMS.Application/Services/FaqService.cs
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
using SPMS.Application.DTOs.Faq;
|
||||||
|
using SPMS.Application.Interfaces;
|
||||||
|
using SPMS.Domain.Common;
|
||||||
|
using SPMS.Domain.Exceptions;
|
||||||
|
using SPMS.Domain.Interfaces;
|
||||||
|
|
||||||
|
namespace SPMS.Application.Services;
|
||||||
|
|
||||||
|
public class FaqService : IFaqService
|
||||||
|
{
|
||||||
|
private readonly IFaqRepository _faqRepository;
|
||||||
|
private readonly IServiceRepository _serviceRepository;
|
||||||
|
|
||||||
|
public FaqService(IFaqRepository faqRepository, IServiceRepository serviceRepository)
|
||||||
|
{
|
||||||
|
_faqRepository = faqRepository;
|
||||||
|
_serviceRepository = serviceRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<FaqListResponseDto> GetListAsync(string serviceCode, FaqListRequestDto request)
|
||||||
|
{
|
||||||
|
var service = await _serviceRepository.GetByServiceCodeAsync(serviceCode);
|
||||||
|
if (service == null)
|
||||||
|
throw new SpmsException(ErrorCodes.NotFound, "존재하지 않는 서비스입니다.", 404);
|
||||||
|
|
||||||
|
var items = await _faqRepository.GetActiveListAsync(service.Id, request.Category);
|
||||||
|
|
||||||
|
return new FaqListResponseDto
|
||||||
|
{
|
||||||
|
Items = items.Select(f => new FaqItemDto
|
||||||
|
{
|
||||||
|
FaqId = f.Id,
|
||||||
|
Category = f.Category,
|
||||||
|
Question = f.Question,
|
||||||
|
Answer = f.Answer,
|
||||||
|
SortOrder = f.SortOrder
|
||||||
|
}).ToList(),
|
||||||
|
TotalCount = items.Count
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
8
SPMS.Domain/Interfaces/IFaqRepository.cs
Normal file
8
SPMS.Domain/Interfaces/IFaqRepository.cs
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
using SPMS.Domain.Entities;
|
||||||
|
|
||||||
|
namespace SPMS.Domain.Interfaces;
|
||||||
|
|
||||||
|
public interface IFaqRepository : IRepository<Faq>
|
||||||
|
{
|
||||||
|
Task<IReadOnlyList<Faq>> GetActiveListAsync(long serviceId, string? category = null);
|
||||||
|
}
|
||||||
|
|
@ -29,6 +29,7 @@ public static class DependencyInjection
|
||||||
services.AddScoped<IAdminRepository, AdminRepository>();
|
services.AddScoped<IAdminRepository, AdminRepository>();
|
||||||
services.AddScoped<INoticeRepository, NoticeRepository>();
|
services.AddScoped<INoticeRepository, NoticeRepository>();
|
||||||
services.AddScoped<IBannerRepository, BannerRepository>();
|
services.AddScoped<IBannerRepository, BannerRepository>();
|
||||||
|
services.AddScoped<IFaqRepository, FaqRepository>();
|
||||||
|
|
||||||
// External Services
|
// External Services
|
||||||
services.AddScoped<IJwtService, JwtService>();
|
services.AddScoped<IJwtService, JwtService>();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using SPMS.Domain.Entities;
|
||||||
|
using SPMS.Domain.Interfaces;
|
||||||
|
|
||||||
|
namespace SPMS.Infrastructure.Persistence.Repositories;
|
||||||
|
|
||||||
|
public class FaqRepository : Repository<Faq>, IFaqRepository
|
||||||
|
{
|
||||||
|
public FaqRepository(AppDbContext context) : base(context) { }
|
||||||
|
|
||||||
|
public async Task<IReadOnlyList<Faq>> GetActiveListAsync(long serviceId, string? category = null)
|
||||||
|
{
|
||||||
|
var query = _dbSet.Where(f => f.ServiceId == serviceId && f.IsActive);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(category))
|
||||||
|
query = query.Where(f => f.Category == category);
|
||||||
|
|
||||||
|
return await query
|
||||||
|
.OrderBy(f => f.SortOrder)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user