improvement: 관리자 기기 목록 API 확장 (#237)

- DeviceListRequestDto: keyword, marketing_agreed 필터 추가
- DeviceSummaryDto: 8개 응답 필드 추가 (device_token, service_name, service_code, os_version, app_version, marketing_agreed, is_active, created_at)
- DeviceRepository: keyword/marketingAgreed 필터 + Include(Service) 추가
- DeviceService: 새 필터 전달 + 응답 매핑 확장

Closes #237
This commit is contained in:
SEAN 2026-02-25 16:56:59 +09:00
parent 016550e3b9
commit afaeb6d116
5 changed files with 59 additions and 5 deletions

View File

@ -21,4 +21,10 @@ public class DeviceListRequestDto
[JsonPropertyName("is_active")]
public bool? IsActive { get; set; }
[JsonPropertyName("keyword")]
public string? Keyword { get; set; }
[JsonPropertyName("marketing_agreed")]
public bool? MarketingAgreed { get; set; }
}

View File

@ -31,4 +31,28 @@ public class DeviceSummaryDto
[JsonPropertyName("last_active_at")]
public DateTime? LastActiveAt { get; set; }
[JsonPropertyName("device_token")]
public string DeviceToken { get; set; } = string.Empty;
[JsonPropertyName("service_name")]
public string ServiceName { get; set; } = string.Empty;
[JsonPropertyName("service_code")]
public string ServiceCode { get; set; } = string.Empty;
[JsonPropertyName("os_version")]
public string? OsVersion { get; set; }
[JsonPropertyName("app_version")]
public string? AppVersion { get; set; }
[JsonPropertyName("marketing_agreed")]
public bool MarketingAgreed { get; set; }
[JsonPropertyName("is_active")]
public bool IsActive { get; set; }
[JsonPropertyName("created_at")]
public DateTime CreatedAt { get; set; }
}

View File

@ -127,7 +127,8 @@ public class DeviceService : IDeviceService
var (items, totalCount) = await _deviceRepository.GetPagedAsync(
serviceId, request.Page, request.Size,
platform, request.PushAgreed, request.IsActive, request.Tags);
platform, request.PushAgreed, request.IsActive, request.Tags,
request.Keyword, request.MarketingAgreed);
var totalPages = (int)Math.Ceiling((double)totalCount / request.Size);
@ -140,7 +141,15 @@ public class DeviceService : IDeviceService
Model = d.DeviceModel,
PushAgreed = d.PushAgreed,
Tags = ParseTags(d.Tags),
LastActiveAt = d.UpdatedAt
LastActiveAt = d.UpdatedAt,
DeviceToken = d.DeviceToken,
ServiceName = d.Service?.ServiceName ?? string.Empty,
ServiceCode = d.Service?.ServiceCode ?? string.Empty,
OsVersion = d.OsVersion,
AppVersion = d.AppVersion,
MarketingAgreed = d.MarketingAgreed,
IsActive = d.IsActive,
CreatedAt = d.CreatedAt
}).ToList(),
Pagination = new DTOs.Notice.PaginationDto
{

View File

@ -12,5 +12,6 @@ public interface IDeviceRepository : IRepository<Device>
Task<(IReadOnlyList<Device> Items, int TotalCount)> GetPagedAsync(
long? serviceId, int page, int size,
Platform? platform = null, bool? pushAgreed = null,
bool? isActive = null, List<int>? tags = null);
bool? isActive = null, List<int>? tags = null,
string? keyword = null, bool? marketingAgreed = null);
}

View File

@ -34,9 +34,11 @@ public class DeviceRepository : Repository<Device>, IDeviceRepository
public async Task<(IReadOnlyList<Device> Items, int TotalCount)> GetPagedAsync(
long? serviceId, int page, int size,
Platform? platform = null, bool? pushAgreed = null,
bool? isActive = null, List<int>? tags = null)
bool? isActive = null, List<int>? tags = null,
string? keyword = null, bool? marketingAgreed = null)
{
IQueryable<Device> query = _dbSet;
IQueryable<Device> query = _dbSet.Include(d => d.Service);
if (serviceId.HasValue)
query = query.Where(d => d.ServiceId == serviceId.Value);
@ -49,6 +51,18 @@ public class DeviceRepository : Repository<Device>, IDeviceRepository
if (isActive.HasValue)
query = query.Where(d => d.IsActive == isActive.Value);
if (marketingAgreed.HasValue)
query = query.Where(d => d.MarketingAgreed == marketingAgreed.Value);
if (!string.IsNullOrWhiteSpace(keyword))
{
var trimmed = keyword.Trim();
if (long.TryParse(trimmed, out var deviceId))
query = query.Where(d => d.Id == deviceId || d.DeviceToken.Contains(trimmed));
else
query = query.Where(d => d.DeviceToken.Contains(trimmed));
}
if (tags != null && tags.Count > 0)
{
foreach (var tag in tags)