Response.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. using Microsoft.AspNetCore.Http;
  2. using System.ComponentModel;
  3. namespace Application.Features.Config.Get;
  4. public sealed class Response
  5. {
  6. public int ID { get; init; }
  7. // set: 공개 /api/config 엔드포인트가 민감 필드(SMTP 자격증명·RootID·IP 화이트리스트) 제거용 sanitized 사본으로 교체 가능하도록.
  8. public BasicConfigDto Basic { get; set; } = new();
  9. public ImagesConfigDto Images { get; init; } = new();
  10. public MetaConfigDto Meta { get; init; } = new();
  11. public CompanyConfigDto Company { get; init; } = new();
  12. public AccountConfigDto Account { get; init; } = new();
  13. public EmailTemplateConfigDto EmailTemplate { get; init; } = new();
  14. public ExternalApiConfigDto External { get; init; } = new();
  15. public TossConfigDto Toss { get; init; } = new();
  16. public AttendanceConfigDto Attendance { get; init; } = new();
  17. public SignupRewardConfigDto SignupReward { get; init; } = new();
  18. public RewardConfigDto Reward { get; init; } = new();
  19. public PaperConfigDto Paper { get; init; } = new();
  20. public DataCollectionConfigDto DataCollection { get; init; } = new();
  21. public sealed class BasicConfigDto
  22. {
  23. [DisplayName("사이트 이름")]
  24. public string? SiteName { get; init; }
  25. [DisplayName("사이트 주소")]
  26. public string? SiteURL { get; init; }
  27. [DisplayName("최고 관리자 ID")]
  28. public string? RootID { get; init; }
  29. [DisplayName("송수신 이메일")]
  30. public string? FromEmail { get; init; }
  31. [DisplayName("송수신자 이름")]
  32. public string? FromName { get; init; }
  33. [DisplayName("SMTP Server")]
  34. public string? SmtpServer { get; init; }
  35. [DisplayName("SMTP Port")]
  36. public int? SmtpPort { get; set; }
  37. [DisplayName("SMTP Enable SSL")]
  38. public bool SmtpEnableSSL { get; init; } = false;
  39. [DisplayName("SMTP Username")]
  40. public string? SmtpUsername { get; init; }
  41. [DisplayName("SMTP Password")]
  42. public string? SmtpPassword { get; init; }
  43. [DisplayName("관리자단 접근 가능 IP")]
  44. public string? AdminWhiteIPList { get; init; }
  45. [DisplayName("사용자단 접근 가능 IP")]
  46. public string? FrontWhiteIPList { get; init; }
  47. [DisplayName("차단 시 안내문 제목")]
  48. public string? BlockAlertTitle { get; init; }
  49. [DisplayName("차단 시 안내문 내용")]
  50. public string? BlockAlertContent { get; init; }
  51. [DisplayName("점검 여부")]
  52. public bool IsMaintenance { get; init; } = false;
  53. [DisplayName("점검 내용")]
  54. public string? MaintenanceContent { get; init; }
  55. [DisplayName("쪽지 일일 발송 제한")]
  56. public int NoteDailySendLimit { get; init; } = 3;
  57. }
  58. public sealed class ImagesConfigDto
  59. {
  60. // ====== DB의 저장/표시용 경로(문자열) ======
  61. [DisplayName("Favicon")]
  62. public string? FaviconPath { get; init; }
  63. [DisplayName("Logo-square")]
  64. public string? LogoSquarePath { get; init; }
  65. [DisplayName("Logo-horizontal")]
  66. public string? LogoHorizontalPath { get; init; }
  67. [DisplayName("og-default")]
  68. public string? OgDefaultPath { get; init; }
  69. [DisplayName("Twitter-image")]
  70. public string? TwitterImagePath { get; init; }
  71. [DisplayName("Apple-touch-icon")]
  72. public string? AppleTouchIconPath { get; init; }
  73. [DisplayName("App-icon-192")]
  74. public string? AppIcon192Path { get; init; }
  75. [DisplayName("App-icon-512")]
  76. public string? AppIcon512Path { get; init; }
  77. // ====== 파일업로드 입력(새 업로드용) ======
  78. [DisplayName("Favicon 업로드")]
  79. public IFormFile? FaviconFile { get; init; }
  80. [DisplayName("Logo-square 업로드")]
  81. public IFormFile? LogoSquareFile { get; init; }
  82. [DisplayName("Logo-horizontal 업로드")]
  83. public IFormFile? LogoHorizontalFile { get; init; }
  84. [DisplayName("og-default 업로드")]
  85. public IFormFile? OgDefaultFile { get; init; }
  86. [DisplayName("Twitter-image 업로드")]
  87. public IFormFile? TwitterImageFile { get; init; }
  88. [DisplayName("Apple-touch-icon 업로드")]
  89. public IFormFile? AppleTouchIconFile { get; init; }
  90. [DisplayName("App-icon-192 업로드")]
  91. public IFormFile? AppIcon192File { get; init; }
  92. [DisplayName("App-icon-512 업로드")]
  93. public IFormFile? AppIcon512File { get; init; }
  94. }
  95. public sealed class MetaConfigDto
  96. {
  97. [DisplayName("Meta Keywords")]
  98. public string? Keywords { get; init; }
  99. [DisplayName("Meta Description")]
  100. public string? Description { get; init; }
  101. [DisplayName("Meta Author")]
  102. public string? Author { get; init; }
  103. [DisplayName("Meta Viewport")]
  104. public string? Viewport { get; init; }
  105. [DisplayName("Meta ApplicationName")]
  106. public string? ApplicationName { get; init; }
  107. [DisplayName("Meta Generator")]
  108. public string? Generator { get; init; }
  109. [DisplayName("Meta Robots")]
  110. public string? Robots { get; init; }
  111. [DisplayName("Meta Adds")]
  112. public string? Adds { get; init; }
  113. }
  114. public sealed class CompanyConfigDto
  115. {
  116. [DisplayName("상호 명")]
  117. public string? Name { get; init; }
  118. [DisplayName("사업자 등록 번호")]
  119. public string? RegNo { get; init; }
  120. [DisplayName("사업장 소재지")]
  121. public string? Address { get; init; }
  122. [DisplayName("우편번호")]
  123. public string? ZipCode { get; init; }
  124. [DisplayName("대표자 명")]
  125. public string? Owner { get; init; }
  126. [DisplayName("대표 전화번호")]
  127. public string? Tel { get; init; }
  128. [DisplayName("FAX")]
  129. public string? Fax { get; init; }
  130. [DisplayName("통신판매업 신고번호")]
  131. public string? RetailSaleNo { get; init; }
  132. [DisplayName("부가통신 사업자번호")]
  133. public string? AddedSaleNo { get; init; }
  134. [DisplayName("호스팅 서비스")]
  135. public string? Hosting { get; init; }
  136. [DisplayName("정보관리책임자")]
  137. public string? AdminName { get; init; }
  138. [DisplayName("정보관리책임자 이메일")]
  139. public string? AdminEmail { get; init; }
  140. [DisplayName("사이트 주소")]
  141. public string? SiteUrl { get; init; }
  142. [DisplayName("입금계좌 - 은행")]
  143. public string? BankCode { get; init; }
  144. [DisplayName("입금계좌 - 예금주")]
  145. public string? BankOwner { get; init; }
  146. [DisplayName("입금계좌 - 계좌번호")]
  147. public string? BankNumber { get; init; }
  148. }
  149. public sealed class AccountConfigDto
  150. {
  151. [DisplayName("회원가입 시 - 차단 여부")]
  152. public bool IsRegisterBlock { get; init; }
  153. [DisplayName("회원가입 시 - 이메일 인증 여부")]
  154. public bool IsRegisterEmailAuth { get; init; }
  155. [DisplayName("회원가입 시 - 비밀번호 최소 길이")]
  156. public ushort? PasswordMinLength { get; init; }
  157. [DisplayName("회원가입 시 - 비밀번호 대문자 최소 수")]
  158. public ushort? PasswordUppercaseLength { get; init; }
  159. [DisplayName("회원가입 시 - 비밀번호 숫자 최소 수")]
  160. public ushort? PasswordNumbersLength { get; init; }
  161. [DisplayName("회원가입 시 - 비밀번호 특수문자 최소 수")]
  162. public ushort? PasswordSpecialcharsLength { get; init; }
  163. [DisplayName("회원가입 시 - 금지 이메일")]
  164. public string? DeniedEmailList { get; init; }
  165. [DisplayName("회원가입 시 - 금지 별명")]
  166. public string? DeniedNameList { get; init; }
  167. [DisplayName("회원가입 시 - 이메일 변경 주기")]
  168. public ushort? ChangeEmailDay { get; init; }
  169. [DisplayName("회원가입 시 - 별명 변경 주기")]
  170. public ushort? ChangeNameDay { get; init; }
  171. [DisplayName("회원가입 시 - 한마디 변경 주기")]
  172. public ushort? ChangeSummaryDay { get; init; }
  173. [DisplayName("회원가입 시 - 자기소개 변경 주기")]
  174. public ushort? ChangeIntroDay { get; init; }
  175. [DisplayName("회원가입 시 - 프로필 이미지 변경 주기")]
  176. public ushort? ChangeThumbDay { get; init; }
  177. [DisplayName("회원가입 시 - 비밀번호 변경 주기")]
  178. public ushort? ChangePasswordDay { get; init; }
  179. [DisplayName("로그인 시 - 이메일 인증 필요")]
  180. public bool IsLoginEmailVerifiedOnly { get; init; }
  181. [DisplayName("로그인 시 - 로그인 시도(회)")]
  182. public ushort? MaxLoginTryCount { get; init; }
  183. [DisplayName("로그인 시 - 로그인 제한(초)")]
  184. public ushort? MaxLoginTryLimitSecond { get; init; }
  185. }
  186. public sealed class EmailTemplateConfigDto
  187. {
  188. [DisplayName("회원가입 시 - 제목")]
  189. public string? RegisterEmailFormTitle { get; init; }
  190. [DisplayName("회원가입 시 - 내용")]
  191. public string? RegisterEmailFormContent { get; init; }
  192. [DisplayName("회원가입 완료 - 제목")]
  193. public string? RegistrationEmailFormTitle { get; init; }
  194. [DisplayName("회원가입 완료 - 내용")]
  195. public string? RegistrationEmailFormContent { get; init; }
  196. [DisplayName("비밀번호 재설정 - 제목")]
  197. public string? ResetPasswordEmailFormTitle { get; init; }
  198. [DisplayName("비밀번호 재설정 - 내용")]
  199. public string? ResetPasswordEmailFormContent { get; init; }
  200. [DisplayName("비밀번호 변경 완료 - 제목")]
  201. public string? ChangedPasswordEmailFormTitle { get; init; }
  202. [DisplayName("비밀번호 변경 완료 - 내용")]
  203. public string? ChangedPasswordEmailFormContent { get; init; }
  204. [DisplayName("회원탈퇴 시 - 제목")]
  205. public string? WithdrawEmailFormTitle { get; init; }
  206. [DisplayName("회원탈퇴 시 - 내용")]
  207. public string? WithdrawEmailFormContent { get; init; }
  208. [DisplayName("회원탈퇴 인증 - 제목")]
  209. public string? WithdrawVerifyEmailFormTitle { get; init; }
  210. [DisplayName("회원탈퇴 인증 - 내용")]
  211. public string? WithdrawVerifyEmailFormContent { get; init; }
  212. [DisplayName("이메일 변경 시 - 제목")]
  213. public string? EmailVerifyFormTitle { get; init; }
  214. [DisplayName("이메일 변경 시 - 내용")]
  215. public string? EmailVerifyFormContent { get; init; }
  216. [DisplayName("이메일 변경 완료 - 제목")]
  217. public string? ChangedEmailFormTitle { get; init; }
  218. [DisplayName("이메일 변경 완료 - 내용")]
  219. public string? ChangedEmailFormContent { get; init; }
  220. }
  221. public sealed class ExternalApiConfigDto
  222. {
  223. [DisplayName("YouTube - API Name")]
  224. public string? YouTubeApiKeyEnc { get; init; }
  225. [DisplayName("YouTube - API Key")]
  226. public string? YouTubeApiName { get; init; }
  227. [DisplayName("Google - Client ID")]
  228. public string? GoogleClientId { get; init; }
  229. [DisplayName("Google - Client Secret")]
  230. public string? GoogleClientSecretEnc { get; init; }
  231. [DisplayName("Google - App ID")]
  232. public string? GoogleAppId { get; init; }
  233. // 소셜 로그인 on/off (Admin 체크박스) — 익명 공개 안전(비밀 아님)
  234. [DisplayName("네이버 로그인 사용")]
  235. public bool NaverLoginEnabled { get; init; } = true;
  236. [DisplayName("카카오 로그인 사용")]
  237. public bool KakaoLoginEnabled { get; init; } = true;
  238. [DisplayName("구글 로그인 사용")]
  239. public bool GoogleLoginEnabled { get; init; } = true;
  240. // OAuth — 관리자 확인용으로 키/시크릿 원문(복호화)까지 노출 (사용자 승인 — /api/config 익명 공개 포함)
  241. [DisplayName("네이버 - Client ID")]
  242. public string? NaverClientId { get; init; }
  243. [DisplayName("네이버 - Client Secret")]
  244. public string? NaverClientSecret { get; init; }
  245. [DisplayName("카카오 - REST API 키")]
  246. public string? KakaoRestApiKey { get; init; }
  247. [DisplayName("카카오 - JavaScript 키")]
  248. public string? KakaoJavascriptKey { get; init; }
  249. [DisplayName("카카오 - Admin 키")]
  250. public string? KakaoAdminKey { get; init; }
  251. [DisplayName("네이버검색 - Client ID")]
  252. public string? NaverSearchClientId { get; init; }
  253. [DisplayName("네이버검색 - Client Secret")]
  254. public string? NaverSearchClientSecret { get; init; }
  255. }
  256. // 데이터 수집 — 공개(/api/config)에는 암호문(enc) 그대로 노출 — 복호화 평문은 Admin 화면에서만
  257. public sealed class DataCollectionConfigDto
  258. {
  259. public string? DataGoKrServiceKey { get; init; }
  260. public string? KrxApiKey { get; init; }
  261. public string? OpenDartApiKey { get; init; }
  262. public string? KoreaEximExchangeKey { get; init; }
  263. public string? KoreaEximLoanRateKey { get; init; }
  264. public string? KoreaEximIntlRateKey { get; init; }
  265. public string? SeibroApiKey { get; init; }
  266. public string? KosisApiKey { get; init; }
  267. public bool StockDataMasterSync { get; init; }
  268. public bool StockDataDailyPriceSync { get; init; }
  269. public bool KrxIndexSync { get; init; }
  270. public bool KrxBondIndexSync { get; init; }
  271. public bool KrxStockSync { get; init; }
  272. public bool KrxEtpSync { get; init; }
  273. public bool KrxWarrantSync { get; init; }
  274. public bool KrxBondSync { get; init; }
  275. public bool KrxDerivativeSync { get; init; }
  276. public bool KrxCommoditySync { get; init; }
  277. public bool KrxEsgSync { get; init; }
  278. public bool OpenDartDisclosureSync { get; init; }
  279. public bool KoreaEximMacroSync { get; init; }
  280. public bool KosisSync { get; init; }
  281. public bool WorldIndexEnabled { get; init; }
  282. public bool MarketQuoteEnabled { get; init; }
  283. public bool SeibroIssuerSync { get; init; }
  284. public bool SeibroDividendSync { get; init; }
  285. public bool SeibroSupplySync { get; init; }
  286. public bool SeibroCorpActionSync { get; init; }
  287. public bool SeibroBondSync { get; init; }
  288. public bool SeibroDerivSync { get; init; }
  289. public bool SeibroForeignSync { get; init; }
  290. }
  291. // 토스페이먼츠 결제 설정 — 키 원문/암호문은 응답에 싣지 않는다 (설정 여부만 노출)
  292. public sealed class TossConfigDto
  293. {
  294. [DisplayName("토스 - 결제 환경")]
  295. public string? TossPayMode { get; init; }
  296. [DisplayName("토스 - Test Client Key 설정 여부")]
  297. public bool HasTestClientKey { get; init; }
  298. [DisplayName("토스 - Test Secret Key 설정 여부")]
  299. public bool HasTestSecretKey { get; init; }
  300. [DisplayName("토스 - Live Client Key 설정 여부")]
  301. public bool HasLiveClientKey { get; init; }
  302. [DisplayName("토스 - Live Secret Key 설정 여부")]
  303. public bool HasLiveSecretKey { get; init; }
  304. }
  305. public sealed class AttendanceConfigDto
  306. {
  307. [DisplayName("출석 기능 활성화")]
  308. public bool IsEnabled { get; init; } = false;
  309. [DisplayName("기본 경험치")]
  310. public int BaseExp { get; init; } = 0;
  311. [DisplayName("기본 코인")]
  312. public int BasePoint { get; init; } = 0;
  313. [DisplayName("연속 출석 가중치 사용")]
  314. public bool UseStreakBonus { get; init; } = false;
  315. [DisplayName("1일당 추가 경험치")]
  316. public int StreakBonusPerDay { get; init; } = 0;
  317. [DisplayName("1일당 추가 코인")]
  318. public int StreakBonusPointPerDay { get; init; } = 0;
  319. [DisplayName("가중치 최대 적용 일수")]
  320. public int StreakBonusMaxDays { get; init; } = 0;
  321. [DisplayName("순위 보상 사용")]
  322. public bool UseRankBonus { get; init; } = false;
  323. [DisplayName("순위별 보상 설정 (JSON)")]
  324. public string? RankBonusConfig { get; init; }
  325. }
  326. public sealed class SignupRewardConfigDto
  327. {
  328. [DisplayName("가입 축하 보상 활성화")]
  329. public bool Enabled { get; init; } = false;
  330. [DisplayName("지급 코인")]
  331. public int CoinAmount { get; init; } = 0;
  332. [DisplayName("지급 캐시")]
  333. public int CashAmount { get; init; } = 0;
  334. [DisplayName("지급 경험치")]
  335. public int ExpAmount { get; init; } = 0;
  336. }
  337. public sealed class RewardConfigDto
  338. {
  339. [DisplayName("게시글 경험치")]
  340. public int PostExp { get; init; } = 0;
  341. [DisplayName("게시글 토큰")]
  342. public int PostPoint { get; init; } = 0;
  343. [DisplayName("댓글 경험치")]
  344. public int CommentExp { get; init; } = 0;
  345. [DisplayName("댓글 토큰")]
  346. public int CommentPoint { get; init; } = 0;
  347. [DisplayName("추천(누른 쪽) 경험치")]
  348. public int LikeGivenExp { get; init; } = 0;
  349. [DisplayName("추천(받은 쪽) 토큰")]
  350. public int LikeReceivedPoint { get; init; } = 0;
  351. [DisplayName("최소 게시글 길이")]
  352. public int MinPostLength { get; init; } = 0;
  353. [DisplayName("최소 댓글 길이")]
  354. public int MinCommentLength { get; init; } = 0;
  355. [DisplayName("신규 회원 보상 유예(일)")]
  356. public int NewMemberHoldDays { get; init; } = 0;
  357. [DisplayName("게시글 일일 횟수 상한")]
  358. public int PostDailyCount { get; init; } = 0;
  359. [DisplayName("게시글 일일 경험치 상한")]
  360. public int PostDailyExp { get; init; } = 0;
  361. [DisplayName("게시글 일일 토큰 상한")]
  362. public int PostDailyPoint { get; init; } = 0;
  363. [DisplayName("댓글 일일 횟수 상한")]
  364. public int CommentDailyCount { get; init; } = 0;
  365. [DisplayName("댓글 일일 경험치 상한")]
  366. public int CommentDailyExp { get; init; } = 0;
  367. [DisplayName("댓글 일일 토큰 상한")]
  368. public int CommentDailyPoint { get; init; } = 0;
  369. [DisplayName("추천(누른 쪽) 일일 횟수 상한")]
  370. public int LikeGivenDailyCount { get; init; } = 0;
  371. [DisplayName("추천(누른 쪽) 일일 경험치 상한")]
  372. public int LikeGivenDailyExp { get; init; } = 0;
  373. [DisplayName("추천(받은 쪽) 일일 횟수 상한")]
  374. public int LikeReceivedDailyCount { get; init; } = 0;
  375. [DisplayName("추천(받은 쪽) 일일 토큰 상한")]
  376. public int LikeReceivedDailyPoint { get; init; } = 0;
  377. [DisplayName("채팅 일일 횟수 상한")]
  378. public int ChatDailyCount { get; init; } = 0;
  379. [DisplayName("채팅 일일 경험치 상한")]
  380. public int ChatDailyExp { get; init; } = 0;
  381. [DisplayName("응원 수수료율(%)")]
  382. public int CheerFeePercent { get; init; } = 20;
  383. [DisplayName("응원 최소 금액")]
  384. public int CheerMinAmount { get; init; } = 100;
  385. [DisplayName("응원 일일 발신 총액 상한(0=무제한)")]
  386. public int CheerDailyMax { get; init; } = 0;
  387. }
  388. public sealed class PaperConfigDto
  389. {
  390. [DisplayName("모의투자 활성화")]
  391. public bool Enabled { get; init; } = true;
  392. [DisplayName("매매 수수료(Bp)")]
  393. public int FeeRateBp { get; init; } = 15;
  394. [DisplayName("거래세(Bp)")]
  395. public int TaxRateBp { get; init; } = 18;
  396. [DisplayName("최소 입금 토큰")]
  397. public int MinDeposit { get; init; } = 10000;
  398. [DisplayName("최대 보유 토큰(0=무제한)")]
  399. public int MaxHolding { get; init; } = 0;
  400. [DisplayName("출금 수익 소각(Bp, 0=사용안함)")]
  401. public int WithdrawProfitBurnBp { get; init; } = 0;
  402. [DisplayName("1주문 상한(Bp, 3000=30%)")]
  403. public int OrderMaxPctBp { get; init; } = 3000;
  404. [DisplayName("리더보드 등재 최소 체결수")]
  405. public int MinFillsForRank { get; init; } = 3;
  406. }
  407. }