improvement: 서비스 목록/상세 응답에 플랫폼 상태 판정 추가 (#216) #217
|
|
@ -103,7 +103,7 @@ public class ServiceController : ControllerBase
|
||||||
[HttpPost("list")]
|
[HttpPost("list")]
|
||||||
[SwaggerOperation(
|
[SwaggerOperation(
|
||||||
Summary = "서비스 목록 조회",
|
Summary = "서비스 목록 조회",
|
||||||
Description = "등록된 서비스 목록을 조회합니다. 페이징, 검색, 상태 필터를 지원합니다.")]
|
Description = "등록된 서비스 목록을 조회합니다. 페이징, 검색, 상태 필터를 지원합니다. 각 항목에 platforms 필드로 Android/iOS 자격증명 상태(credentialStatus: ok/warn/error)를 포함합니다.")]
|
||||||
[SwaggerResponse(200, "조회 성공", typeof(ApiResponse<ServiceListResponseDto>))]
|
[SwaggerResponse(200, "조회 성공", typeof(ApiResponse<ServiceListResponseDto>))]
|
||||||
[SwaggerResponse(401, "인증되지 않은 요청")]
|
[SwaggerResponse(401, "인증되지 않은 요청")]
|
||||||
[SwaggerResponse(403, "권한 없음")]
|
[SwaggerResponse(403, "권한 없음")]
|
||||||
|
|
@ -116,7 +116,7 @@ public class ServiceController : ControllerBase
|
||||||
[HttpPost("{serviceCode}")]
|
[HttpPost("{serviceCode}")]
|
||||||
[SwaggerOperation(
|
[SwaggerOperation(
|
||||||
Summary = "서비스 상세 조회",
|
Summary = "서비스 상세 조회",
|
||||||
Description = "특정 서비스의 상세 정보를 조회합니다.")]
|
Description = "특정 서비스의 상세 정보를 조회합니다. apnsAuthType(p8/p12)과 platforms 필드로 각 플랫폼의 자격증명 상태(credentialStatus: ok/warn/error), 만료일(expiresAt) 정보를 포함합니다.")]
|
||||||
[SwaggerResponse(200, "조회 성공", typeof(ApiResponse<ServiceResponseDto>))]
|
[SwaggerResponse(200, "조회 성공", typeof(ApiResponse<ServiceResponseDto>))]
|
||||||
[SwaggerResponse(401, "인증되지 않은 요청")]
|
[SwaggerResponse(401, "인증되지 않은 요청")]
|
||||||
[SwaggerResponse(403, "권한 없음")]
|
[SwaggerResponse(403, "권한 없음")]
|
||||||
|
|
|
||||||
33
SPMS.Application/DTOs/Service/PlatformSummaryDto.cs
Normal file
33
SPMS.Application/DTOs/Service/PlatformSummaryDto.cs
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
namespace SPMS.Application.DTOs.Service;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 서비스의 플랫폼(Android/iOS) 자격증명 상태 요약
|
||||||
|
/// </summary>
|
||||||
|
public class PlatformSummaryDto
|
||||||
|
{
|
||||||
|
public PlatformCredentialSummaryDto? Android { get; set; }
|
||||||
|
public PlatformCredentialSummaryDto? Ios { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 개별 플랫폼 자격증명 상태
|
||||||
|
/// </summary>
|
||||||
|
public class PlatformCredentialSummaryDto
|
||||||
|
{
|
||||||
|
public bool Registered { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 자격증명 상태: ok | warn | error | none
|
||||||
|
/// </summary>
|
||||||
|
public string CredentialStatus { get; set; } = "none";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 상태 사유 (warn/error 시 표시)
|
||||||
|
/// </summary>
|
||||||
|
public string? StatusReason { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// p12 인증서 만료일 (p12 타입만 해당)
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? ExpiresAt { get; set; }
|
||||||
|
}
|
||||||
|
|
@ -18,4 +18,5 @@ public class ServiceSummaryDto
|
||||||
public string Status { get; set; } = string.Empty;
|
public string Status { get; set; } = string.Empty;
|
||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
public int DeviceCount { get; set; }
|
public int DeviceCount { get; set; }
|
||||||
|
public PlatformSummaryDto? Platforms { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,10 @@ public class ServiceResponseDto
|
||||||
public string? ApnsBundleId { get; set; }
|
public string? ApnsBundleId { get; set; }
|
||||||
public string? ApnsKeyId { get; set; }
|
public string? ApnsKeyId { get; set; }
|
||||||
public string? ApnsTeamId { get; set; }
|
public string? ApnsTeamId { get; set; }
|
||||||
|
public string? ApnsAuthType { get; set; }
|
||||||
public bool HasApnsKey { get; set; }
|
public bool HasApnsKey { get; set; }
|
||||||
public bool HasFcmCredentials { get; set; }
|
public bool HasFcmCredentials { get; set; }
|
||||||
|
public PlatformSummaryDto? Platforms { get; set; }
|
||||||
public string? WebhookUrl { get; set; }
|
public string? WebhookUrl { get; set; }
|
||||||
public string? Tags { get; set; }
|
public string? Tags { get; set; }
|
||||||
public string SubTier { get; set; } = string.Empty;
|
public string SubTier { get; set; } = string.Empty;
|
||||||
|
|
|
||||||
|
|
@ -886,7 +886,8 @@ public class ServiceManagementService : IServiceManagementService
|
||||||
SubTier = service.SubTier.ToString(),
|
SubTier = service.SubTier.ToString(),
|
||||||
Status = service.Status.ToString(),
|
Status = service.Status.ToString(),
|
||||||
CreatedAt = service.CreatedAt,
|
CreatedAt = service.CreatedAt,
|
||||||
DeviceCount = service.Devices?.Count ?? 0
|
DeviceCount = service.Devices?.Count ?? 0,
|
||||||
|
Platforms = BuildPlatformSummary(service)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -902,8 +903,10 @@ public class ServiceManagementService : IServiceManagementService
|
||||||
ApnsBundleId = service.ApnsBundleId,
|
ApnsBundleId = service.ApnsBundleId,
|
||||||
ApnsKeyId = service.ApnsKeyId,
|
ApnsKeyId = service.ApnsKeyId,
|
||||||
ApnsTeamId = service.ApnsTeamId,
|
ApnsTeamId = service.ApnsTeamId,
|
||||||
|
ApnsAuthType = service.ApnsAuthType,
|
||||||
HasApnsKey = !string.IsNullOrEmpty(service.ApnsPrivateKey),
|
HasApnsKey = !string.IsNullOrEmpty(service.ApnsPrivateKey),
|
||||||
HasFcmCredentials = !string.IsNullOrEmpty(service.FcmCredentials),
|
HasFcmCredentials = !string.IsNullOrEmpty(service.FcmCredentials),
|
||||||
|
Platforms = BuildPlatformSummary(service),
|
||||||
WebhookUrl = service.WebhookUrl,
|
WebhookUrl = service.WebhookUrl,
|
||||||
Tags = service.Tags,
|
Tags = service.Tags,
|
||||||
SubTier = service.SubTier.ToString(),
|
SubTier = service.SubTier.ToString(),
|
||||||
|
|
@ -916,4 +919,87 @@ public class ServiceManagementService : IServiceManagementService
|
||||||
AllowedIps = service.ServiceIps?.Select(ip => ip.IpAddress).ToList() ?? new List<string>()
|
AllowedIps = service.ServiceIps?.Select(ip => ip.IpAddress).ToList() ?? new List<string>()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 서비스의 플랫폼 자격증명 상태를 판정하여 PlatformSummaryDto를 반환합니다.
|
||||||
|
/// Android: FcmCredentials 유무로 판정
|
||||||
|
/// iOS: ApnsAuthType(p8/p12)에 따라 만료 상태 포함 판정
|
||||||
|
/// </summary>
|
||||||
|
private static PlatformSummaryDto? BuildPlatformSummary(Service service)
|
||||||
|
{
|
||||||
|
var android = BuildAndroidSummary(service);
|
||||||
|
var ios = BuildIosSummary(service);
|
||||||
|
|
||||||
|
// 양쪽 다 null이면 null 반환
|
||||||
|
if (android == null && ios == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return new PlatformSummaryDto
|
||||||
|
{
|
||||||
|
Android = android,
|
||||||
|
Ios = ios
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PlatformCredentialSummaryDto? BuildAndroidSummary(Service service)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(service.FcmCredentials))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return new PlatformCredentialSummaryDto
|
||||||
|
{
|
||||||
|
Registered = true,
|
||||||
|
CredentialStatus = "ok"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PlatformCredentialSummaryDto? BuildIosSummary(Service service)
|
||||||
|
{
|
||||||
|
// APNs 미등록
|
||||||
|
if (string.IsNullOrEmpty(service.ApnsBundleId))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var summary = new PlatformCredentialSummaryDto
|
||||||
|
{
|
||||||
|
Registered = true
|
||||||
|
};
|
||||||
|
|
||||||
|
if (service.ApnsAuthType == "p12")
|
||||||
|
{
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
|
||||||
|
if (service.ApnsCertExpiresAt.HasValue)
|
||||||
|
{
|
||||||
|
if (service.ApnsCertExpiresAt.Value < now)
|
||||||
|
{
|
||||||
|
summary.CredentialStatus = "error";
|
||||||
|
summary.StatusReason = "p12 인증서가 만료되었습니다.";
|
||||||
|
}
|
||||||
|
else if (service.ApnsCertExpiresAt.Value < now.AddDays(30))
|
||||||
|
{
|
||||||
|
summary.CredentialStatus = "warn";
|
||||||
|
summary.StatusReason = "p12 인증서 만료가 30일 이내입니다.";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
summary.CredentialStatus = "ok";
|
||||||
|
}
|
||||||
|
|
||||||
|
summary.ExpiresAt = service.ApnsCertExpiresAt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// p12인데 만료일 정보 없음 (비정상)
|
||||||
|
summary.CredentialStatus = "warn";
|
||||||
|
summary.StatusReason = "p12 인증서 만료일 정보가 없습니다.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// p8 또는 레거시(AuthType null + PrivateKey 존재)
|
||||||
|
summary.CredentialStatus = "ok";
|
||||||
|
}
|
||||||
|
|
||||||
|
return summary;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user