Request.cs 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956
  1. using Microsoft.AspNetCore.Http;
  2. using System.ComponentModel;
  3. using System.ComponentModel.DataAnnotations;
  4. namespace Application.Features.Config.Update;
  5. public sealed class Request
  6. {
  7. public int ID { get; set; }
  8. public BasicConfigDto Basic { get; set; } = new();
  9. public ImagesConfigDto Images { get; set; } = new();
  10. public MetaConfigDto Meta { get; set; } = new();
  11. public CompanyConfigDto Company { get; set; } = new();
  12. public AccountConfigDto Account { get; set; } = new();
  13. public EmailTemplateConfigDto EmailTemplate { get; set; } = new();
  14. public ExternalApiConfigDto External { get; set; } = new();
  15. public TossConfigDto Toss { get; set; } = new();
  16. public AttendanceConfigDto? Attendance { get; set; }
  17. public SignupRewardConfigDto? SignupReward { get; set; }
  18. public RewardConfigDto? Reward { get; set; }
  19. public PaperConfigDto? Paper { get; set; }
  20. public DataCollectionConfigDto? DataCollection { get; set; }
  21. // 기본 설정
  22. public sealed class BasicConfigDto
  23. {
  24. [MaxLength(100)]
  25. [DisplayName("사이트 이름")]
  26. public string? SiteName { get; set; }
  27. [MaxLength(100)]
  28. [DataType(DataType.Url)]
  29. [DisplayName("사이트 주소")]
  30. public string? SiteURL { get; set; }
  31. [DisplayName("최고 관리자 ID")]
  32. public string? RootID { get; set; }
  33. [MaxLength(100)]
  34. [DataType(DataType.EmailAddress)]
  35. [DisplayName("발송자 이메일")]
  36. public string? FromEmail { get; set; }
  37. [MaxLength(30)]
  38. [DisplayName("발송자 이름")]
  39. public string? FromName { get; set; }
  40. [MaxLength(200)]
  41. [DisplayName("SMTP Server")]
  42. public string? SmtpServer { get; set; }
  43. [Range(1, 65535)]
  44. [DisplayName("SMTP Port")]
  45. public int? SmtpPort { get; set; }
  46. [DisplayName("SMTP Enable SSL")]
  47. public bool SmtpEnableSSL { get; set; } = false;
  48. [MaxLength(100)]
  49. [DisplayName("SMTP Username")]
  50. public string? SmtpUsername { get; set; }
  51. [MaxLength(200)]
  52. [DataType(DataType.Password)]
  53. [DisplayName("SMTP Password")]
  54. public string? SmtpPassword { get; set; }
  55. [MaxLength(200)]
  56. [DataType(DataType.MultilineText)]
  57. [DisplayName("관리자단 접근 가능 IP")]
  58. public string? AdminWhiteIPList { get; set; }
  59. [MaxLength(200)]
  60. [DataType(DataType.MultilineText)]
  61. [DisplayName("사용자단 접근 가능 IP")]
  62. public string? FrontWhiteIPList { get; set; }
  63. [MaxLength(200)]
  64. [DisplayName("차단 시 안내문 제목")]
  65. public string? BlockAlertTitle { get; set; }
  66. [MaxLength(5000)]
  67. [DataType(DataType.MultilineText)]
  68. [DisplayName("차단 시 안내문 내용")]
  69. public string? BlockAlertContent { get; set; }
  70. [DisplayName("점검 여부")]
  71. public bool IsMaintenance { get; set; } = false;
  72. [MaxLength(5000)]
  73. [DataType(DataType.MultilineText)]
  74. [DisplayName("점검 내용")]
  75. public string? MaintenanceContent { get; set; }
  76. [Range(0, 100)]
  77. [DisplayName("쪽지 일일 발송 제한")]
  78. public int NoteDailySendLimit { get; set; } = 3;
  79. }
  80. // 이미지 경로 및 업로드 입력
  81. public sealed class ImagesConfigDto
  82. {
  83. // ====== DB에 저장/표기할 경로(문자열) ======
  84. [MaxLength(255)]
  85. [DisplayName("Favicon")]
  86. public string? FaviconPath { get; set; }
  87. [MaxLength(255)]
  88. [DisplayName("Logo-square")]
  89. public string? LogoSquarePath { get; set; }
  90. [MaxLength(255)]
  91. [DisplayName("Logo-horizontal")]
  92. public string? LogoHorizontalPath { get; set; }
  93. [MaxLength(255)]
  94. [DisplayName("og-default")]
  95. public string? OgDefaultPath { get; set; }
  96. [MaxLength(255)]
  97. [DisplayName("Twitter-image")]
  98. public string? TwitterImagePath { get; set; }
  99. [MaxLength(255)]
  100. [DisplayName("Apple-touch-icon")]
  101. public string? AppleTouchIconPath { get; set; }
  102. [MaxLength(255)]
  103. [DisplayName("App-icon-192")]
  104. public string? AppIcon192Path { get; set; }
  105. [MaxLength(255)]
  106. [DisplayName("App-icon-512")]
  107. public string? AppIcon512Path { get; set; }
  108. // ====== 업로드 입력(새 업로드용) ======
  109. [DataType(DataType.Upload)]
  110. [DisplayName("Favicon 업로드")]
  111. public IFormFile? FaviconFile { get; set; }
  112. [DataType(DataType.Upload)]
  113. [DisplayName("Logo-square 업로드")]
  114. public IFormFile? LogoSquareFile { get; set; }
  115. [DataType(DataType.Upload)]
  116. [DisplayName("Logo-horizontal 업로드")]
  117. public IFormFile? LogoHorizontalFile { get; set; }
  118. [DataType(DataType.Upload)]
  119. [DisplayName("og-default 업로드")]
  120. public IFormFile? OgDefaultFile { get; set; }
  121. [DataType(DataType.Upload)]
  122. [DisplayName("Twitter-image 업로드")]
  123. public IFormFile? TwitterImageFile { get; set; }
  124. [DataType(DataType.Upload)]
  125. [DisplayName("Apple-touch-icon 업로드")]
  126. public IFormFile? AppleTouchIconFile { get; set; }
  127. [DataType(DataType.Upload)]
  128. [DisplayName("App-icon-192 업로드")]
  129. public IFormFile? AppIcon192File { get; set; }
  130. [DataType(DataType.Upload)]
  131. [DisplayName("App-icon-512 업로드")]
  132. public IFormFile? AppIcon512File { get; set; }
  133. }
  134. // 메타 태그
  135. public sealed class MetaConfigDto
  136. {
  137. [MaxLength(255)]
  138. [DisplayName("Meta Keywords")]
  139. public string? Keywords { get; set; }
  140. [MaxLength(255)]
  141. [DisplayName("Meta Description")]
  142. public string? Description { get; set; }
  143. [MaxLength(255)]
  144. [DisplayName("Meta Author")]
  145. public string? Author { get; set; }
  146. [MaxLength(255)]
  147. [DisplayName("Meta Viewport")]
  148. public string? Viewport { get; set; }
  149. [MaxLength(255)]
  150. [DisplayName("Meta ApplicationName")]
  151. public string? ApplicationName { get; set; }
  152. [MaxLength(255)]
  153. [DisplayName("Meta Generator")]
  154. public string? Generator { get; set; }
  155. [MaxLength(255)]
  156. [DisplayName("Meta Robots")]
  157. public string? Robots { get; set; }
  158. [MaxLength(3000)]
  159. [DataType(DataType.MultilineText)]
  160. [DisplayName("Meta Adds")]
  161. public string? Adds { get; set; }
  162. }
  163. // 회사 정보
  164. public sealed class CompanyConfigDto
  165. {
  166. [MaxLength(70)]
  167. [DisplayName("상호 명")]
  168. public string? Name { get; set; }
  169. [MaxLength(100)]
  170. [DisplayName("사업자 등록 번호")]
  171. public string? RegNo { get; set; }
  172. [MaxLength(255)]
  173. [DisplayName("사업장 소재지")]
  174. public string? Address { get; set; }
  175. [MaxLength(8)]
  176. [DataType(DataType.PostalCode)]
  177. [DisplayName("우편번호")]
  178. public string? ZipCode { get; set; }
  179. [MaxLength(50)]
  180. [DisplayName("대표자 명")]
  181. public string? Owner { get; set; }
  182. [MaxLength(20)]
  183. [DisplayName("대표 전화번호")]
  184. public string? Tel { get; set; }
  185. [MaxLength(20)]
  186. [DisplayName("FAX")]
  187. public string? Fax { get; set; }
  188. [MaxLength(20)]
  189. [DisplayName("통신판매업 신고번호")]
  190. public string? RetailSaleNo { get; set; }
  191. [MaxLength(20)]
  192. [DisplayName("부가통신 사업자번호")]
  193. public string? AddedSaleNo { get; set; }
  194. [MaxLength(100)]
  195. [DisplayName("호스팅 서비스")]
  196. public string? Hosting { get; set; }
  197. [MaxLength(70)]
  198. [DisplayName("정보관리책임자")]
  199. public string? AdminName { get; set; }
  200. [MaxLength(100)]
  201. [DataType(DataType.EmailAddress)]
  202. [DisplayName("정보관리책임자 이메일")]
  203. public string? AdminEmail { get; set; }
  204. [MaxLength(200)]
  205. [DataType(DataType.Url)]
  206. [DisplayName("사이트 주소")]
  207. public string? SiteUrl { get; set; }
  208. [MaxLength(10)]
  209. [DisplayName("입금계좌 - 은행")]
  210. public string? BankCode { get; set; }
  211. [MaxLength(70)]
  212. [DisplayName("입금계좌 - 예금주")]
  213. public string? BankOwner { get; set; }
  214. [MaxLength(100)]
  215. [DisplayName("입금계좌 - 계좌번호")]
  216. public string? BankNumber { get; set; }
  217. }
  218. // 회원 설정
  219. public sealed class AccountConfigDto
  220. {
  221. [DisplayName("회원가입 시 - 가입 차단")]
  222. public bool IsRegisterBlock { get; set; } = false;
  223. [DisplayName("회원가입 시 - 이메일 인증 여부")]
  224. public bool IsRegisterEmailAuth { get; set; } = false;
  225. [Range(0, 100)]
  226. [DisplayName("회원가입 시 - 비밀번호 최소 길이")]
  227. public ushort? PasswordMinLength { get; set; }
  228. [Range(0, 100)]
  229. [DisplayName("회원가입 시 - 비밀번호 대문자 최소 길이")]
  230. public ushort? PasswordUppercaseLength { get; set; }
  231. [Range(0, 100)]
  232. [DisplayName("회원가입 시 - 비밀번호 숫자 최소 길이")]
  233. public ushort? PasswordNumbersLength { get; set; }
  234. [Range(0, 100)]
  235. [DisplayName("회원가입 시 - 비밀번호 특수문자 최소 길이")]
  236. public ushort? PasswordSpecialcharsLength { get; set; }
  237. [MaxLength(4000)]
  238. [DisplayName("회원가입 시 - 금지 이메일")]
  239. public string? DeniedEmailList { get; set; }
  240. [MaxLength(4000)]
  241. [DisplayName("회원가입 시 - 금지 별명")]
  242. public string? DeniedNameList { get; set; }
  243. [Range(0, 365)]
  244. [DisplayName("회원가입 시 - 이메일 갱신 주기")]
  245. public ushort? ChangeEmailDay { get; set; }
  246. [Range(0, 365)]
  247. [DisplayName("회원가입 시 - 별명 갱신 주기")]
  248. public ushort? ChangeNameDay { get; set; }
  249. [Range(0, 365)]
  250. [DisplayName("회원가입 시 - 한마디 갱신 주기")]
  251. public ushort? ChangeSummaryDay { get; set; }
  252. [Range(0, 365)]
  253. [DisplayName("회원가입 시 - 자기소개 갱신 주기")]
  254. public ushort? ChangeIntroDay { get; set; }
  255. [Range(0, 365)]
  256. [DisplayName("회원가입 시 - 비밀번호 갱신 주기")]
  257. public ushort? ChangePasswordDay { get; set; }
  258. [DisplayName("로그인 시 - 이메일 인증 필요")]
  259. public bool IsLoginEmailVerifiedOnly { get; set; } = false;
  260. [Range(0, 100)]
  261. [DisplayName("로그인 시 - 로그인 시도(회)")]
  262. public ushort? MaxLoginTryCount { get; set; }
  263. [Range(0, 86400)]
  264. [DisplayName("로그인 시 - 로그인 제한(초)")]
  265. public ushort? MaxLoginTryLimitSecond { get; set; }
  266. }
  267. // 알림 발송 양식
  268. public sealed class EmailTemplateConfigDto
  269. {
  270. [MaxLength(4000)]
  271. [DisplayName("회원가입 시 - 제목")]
  272. public string? RegisterEmailFormTitle { get; set; }
  273. [MaxLength(4000)]
  274. [DisplayName("회원가입 시 - 내용")]
  275. public string? RegisterEmailFormContent { get; set; }
  276. [MaxLength(4000)]
  277. [DisplayName("회원가입 완료 - 제목")]
  278. public string? RegistrationEmailFormTitle { get; set; }
  279. [MaxLength(4000)]
  280. [DisplayName("회원가입 완료 - 내용")]
  281. public string? RegistrationEmailFormContent { get; set; }
  282. [MaxLength(4000)]
  283. [DisplayName("비밀번호 재설정 - 제목")]
  284. public string? ResetPasswordEmailFormTitle { get; set; }
  285. [MaxLength(4000)]
  286. [DisplayName("비밀번호 재설정 - 내용")]
  287. public string? ResetPasswordEmailFormContent { get; set; }
  288. [MaxLength(4000)]
  289. [DisplayName("비밀번호 변경 완료 - 제목")]
  290. public string? ChangedPasswordEmailFormTitle { get; set; }
  291. [MaxLength(4000)]
  292. [DisplayName("비밀번호 변경 완료 - 내용")]
  293. public string? ChangedPasswordEmailFormContent { get; set; }
  294. [MaxLength(4000)]
  295. [DisplayName("회원탈퇴 시 - 제목")]
  296. public string? WithdrawEmailFormTitle { get; set; }
  297. [MaxLength(4000)]
  298. [DisplayName("회원탈퇴 시 - 내용")]
  299. public string? WithdrawEmailFormContent { get; set; }
  300. [MaxLength(4000)]
  301. [DisplayName("회원탈퇴 인증 - 제목")]
  302. public string? WithdrawVerifyEmailFormTitle { get; set; }
  303. [MaxLength(4000)]
  304. [DisplayName("회원탈퇴 인증 - 내용")]
  305. public string? WithdrawVerifyEmailFormContent { get; set; }
  306. [MaxLength(4000)]
  307. [DisplayName("이메일 변경 시 - 제목")]
  308. public string? EmailVerifyFormTitle { get; set; }
  309. [MaxLength(4000)]
  310. [DisplayName("이메일 변경 시 - 내용")]
  311. public string? EmailVerifyFormContent { get; set; }
  312. [MaxLength(4000)]
  313. [DisplayName("이메일 변경 완료 - 제목")]
  314. public string? ChangedEmailFormTitle { get; set; }
  315. [MaxLength(4000)]
  316. [DisplayName("이메일 변경 완료 - 내용")]
  317. public string? ChangedEmailFormContent { get; set; }
  318. }
  319. // API 정보
  320. public sealed class ExternalApiConfigDto
  321. {
  322. [MaxLength(500)]
  323. [DisplayName("YouTube - API Name")]
  324. public string? YouTubeApiKeyEnc { get; set; }
  325. [MaxLength(500)]
  326. [DisplayName("YouTube - API Key")]
  327. public string? YouTubeApiName { get; set; }
  328. [MaxLength(500)]
  329. [DisplayName("Google - Client ID")]
  330. public string? GoogleClientId { get; set; }
  331. [MaxLength(500)]
  332. [DisplayName("Google - Client Secret")]
  333. public string? GoogleClientSecretEnc { get; set; }
  334. [MaxLength(500)]
  335. [DisplayName("Google - App ID")]
  336. public string? GoogleAppId { get; set; }
  337. // 소셜 로그인 on/off (Admin 체크박스)
  338. [DisplayName("네이버 로그인 사용")]
  339. public bool NaverLoginEnabled { get; set; } = true;
  340. [DisplayName("카카오 로그인 사용")]
  341. public bool KakaoLoginEnabled { get; set; } = true;
  342. [DisplayName("구글 로그인 사용")]
  343. public bool GoogleLoginEnabled { get; set; } = true;
  344. // 소셜 로그인 (OAuth) — 비밀 키는 빈 값 제출 시 기존 유지(입력 시 암호화 저장), ID/JS 키는 직접 저장
  345. [MaxLength(500)]
  346. [DisplayName("네이버 - Client ID")]
  347. public string? NaverClientId { get; set; }
  348. [MaxLength(500)]
  349. [DisplayName("네이버 - Client Secret")]
  350. public string? NaverClientSecret { get; set; }
  351. [MaxLength(500)]
  352. [DisplayName("카카오 - REST API 키")]
  353. public string? KakaoRestApiKey { get; set; }
  354. [MaxLength(500)]
  355. [DisplayName("카카오 - JavaScript 키")]
  356. public string? KakaoJavascriptKey { get; set; }
  357. [MaxLength(500)]
  358. [DisplayName("카카오 - Admin 키")]
  359. public string? KakaoAdminKey { get; set; }
  360. [MaxLength(500)]
  361. [DisplayName("네이버검색 - Client ID")]
  362. public string? NaverSearchClientId { get; set; }
  363. [MaxLength(500)]
  364. [DisplayName("네이버검색 - Client Secret")]
  365. public string? NaverSearchClientSecret { get; set; }
  366. }
  367. // 데이터 수집 API 키 + 수집기 활성화. 키는 빈 값 제출 시 기존 유지(입력 시 암호화 저장), 플래그는 수집기 on/off.
  368. public sealed class DataCollectionConfigDto
  369. {
  370. [MaxLength(1000)]
  371. [DisplayName("금융위 data.go.kr ServiceKey")]
  372. public string? DataGoKrServiceKey { get; set; }
  373. [MaxLength(1000)]
  374. [DisplayName("KRX AUTH_KEY")]
  375. public string? KrxApiKey { get; set; }
  376. [MaxLength(1000)]
  377. [DisplayName("OpenDART crtfc_key")]
  378. public string? OpenDartApiKey { get; set; }
  379. [MaxLength(1000)]
  380. [DisplayName("수출입은행 환율(AP01) authkey")]
  381. public string? KoreaEximExchangeKey { get; set; }
  382. [MaxLength(1000)]
  383. [DisplayName("수출입은행 대출금리(AP02) authkey")]
  384. public string? KoreaEximLoanRateKey { get; set; }
  385. [MaxLength(1000)]
  386. [DisplayName("수출입은행 국제금리(AP03) authkey")]
  387. public string? KoreaEximIntlRateKey { get; set; }
  388. [MaxLength(1000)]
  389. [DisplayName("SEIBro key")]
  390. public string? SeibroApiKey { get; set; }
  391. [MaxLength(1000)]
  392. [DisplayName("KOSIS apiKey")]
  393. public string? KosisApiKey { get; set; }
  394. // 수집기 활성화 플래그
  395. public bool StockDataMasterSync { get; set; }
  396. public bool StockDataDailyPriceSync { get; set; }
  397. public bool KrxIndexSync { get; set; }
  398. public bool KrxBondIndexSync { get; set; }
  399. public bool KrxStockSync { get; set; }
  400. public bool KrxEtpSync { get; set; }
  401. public bool KrxWarrantSync { get; set; }
  402. public bool KrxBondSync { get; set; }
  403. public bool KrxDerivativeSync { get; set; }
  404. public bool KrxCommoditySync { get; set; }
  405. public bool KrxEsgSync { get; set; }
  406. public bool OpenDartDisclosureSync { get; set; }
  407. public bool KoreaEximMacroSync { get; set; }
  408. public bool KosisSync { get; set; }
  409. public bool WorldIndexEnabled { get; set; }
  410. public bool MarketQuoteEnabled { get; set; }
  411. public bool SeibroIssuerSync { get; set; }
  412. public bool SeibroDividendSync { get; set; }
  413. public bool SeibroSupplySync { get; set; }
  414. public bool SeibroCorpActionSync { get; set; }
  415. public bool SeibroBondSync { get; set; }
  416. public bool SeibroDerivSync { get; set; }
  417. public bool SeibroForeignSync { get; set; }
  418. }
  419. // 토스페이먼츠 결제 설정 (결제 설정 화면 전용)
  420. // 키 입력값은 저장 시 암호화되며, 빈 값으로 제출하면 기존 저장 키를 유지한다.
  421. public sealed class TossConfigDto
  422. {
  423. [DisplayName("토스 - 결제 환경")]
  424. public string? TossPayMode { get; set; }
  425. [MaxLength(500)]
  426. [DisplayName("토스 - Test Client Key")]
  427. public string? TestClientKey { get; set; }
  428. [MaxLength(500)]
  429. [DisplayName("토스 - Test Secret Key")]
  430. public string? TestSecretKey { get; set; }
  431. [MaxLength(500)]
  432. [DisplayName("토스 - Live Client Key")]
  433. public string? LiveClientKey { get; set; }
  434. [MaxLength(500)]
  435. [DisplayName("토스 - Live Secret Key")]
  436. public string? LiveSecretKey { get; set; }
  437. }
  438. // 출석 설정
  439. public sealed class AttendanceConfigDto
  440. {
  441. [DisplayName("출석 기능 활성화")]
  442. public bool IsEnabled { get; set; } = false;
  443. [Range(0, 100000)]
  444. [DisplayName("기본 경험치")]
  445. public int BaseExp { get; set; } = 0;
  446. [Range(0, 100000)]
  447. [DisplayName("기본 코인")]
  448. public int BasePoint { get; set; } = 0;
  449. [DisplayName("연속 출석 가중치 사용")]
  450. public bool UseStreakBonus { get; set; } = false;
  451. [Range(0, 10000)]
  452. [DisplayName("1일당 추가 경험치")]
  453. public int StreakBonusPerDay { get; set; } = 0;
  454. [Range(0, 10000)]
  455. [DisplayName("1일당 추가 코인")]
  456. public int StreakBonusPointPerDay { get; set; } = 0;
  457. [Range(0, 365)]
  458. [DisplayName("가중치 최대 적용 일수")]
  459. public int StreakBonusMaxDays { get; set; } = 0;
  460. [DisplayName("순위 보상 사용")]
  461. public bool UseRankBonus { get; set; } = false;
  462. [MaxLength(2000)]
  463. [DisplayName("순위별 보상 설정 (JSON)")]
  464. public string? RankBonusConfig { get; set; }
  465. }
  466. // 가입 축하 보상 설정
  467. public sealed class SignupRewardConfigDto
  468. {
  469. [DisplayName("가입 축하 보상 활성화")]
  470. public bool Enabled { get; set; } = false;
  471. [Range(0, 100000000)]
  472. [DisplayName("지급 코인")]
  473. public int CoinAmount { get; set; } = 0;
  474. [Range(0, 100000000)]
  475. [DisplayName("지급 캐시")]
  476. public int CashAmount { get; set; } = 0;
  477. [Range(0, 100000)]
  478. [DisplayName("지급 경험치")]
  479. public int ExpAmount { get; set; } = 0;
  480. }
  481. // 보상 엔진 설정 (Reward) — d3 M2. ActivityToken 대체·통합.
  482. public sealed class RewardConfigDto
  483. {
  484. [Range(0, 100000000)]
  485. [DisplayName("게시글 경험치")]
  486. public int PostExp { get; set; } = 0;
  487. [Range(0, 100000000)]
  488. [DisplayName("게시글 토큰")]
  489. public int PostPoint { get; set; } = 0;
  490. [Range(0, 100000000)]
  491. [DisplayName("댓글 경험치")]
  492. public int CommentExp { get; set; } = 0;
  493. [Range(0, 100000000)]
  494. [DisplayName("댓글 토큰")]
  495. public int CommentPoint { get; set; } = 0;
  496. [Range(0, 100000000)]
  497. [DisplayName("추천(누른 쪽) 경험치")]
  498. public int LikeGivenExp { get; set; } = 0;
  499. [Range(0, 100000000)]
  500. [DisplayName("추천(받은 쪽) 토큰")]
  501. public int LikeReceivedPoint { get; set; } = 0;
  502. [Range(0, 100000)]
  503. [DisplayName("최소 게시글 길이")]
  504. public int MinPostLength { get; set; } = 0;
  505. [Range(0, 100000)]
  506. [DisplayName("최소 댓글 길이")]
  507. public int MinCommentLength { get; set; } = 0;
  508. [Range(0, 3650)]
  509. [DisplayName("신규 회원 보상 유예(일)")]
  510. public int NewMemberHoldDays { get; set; } = 0;
  511. [Range(0, 100000000)]
  512. [DisplayName("게시글 일일 횟수 상한")]
  513. public int PostDailyCount { get; set; } = 0;
  514. [Range(0, 100000000)]
  515. [DisplayName("게시글 일일 경험치 상한")]
  516. public int PostDailyExp { get; set; } = 0;
  517. [Range(0, 100000000)]
  518. [DisplayName("게시글 일일 토큰 상한")]
  519. public int PostDailyPoint { get; set; } = 0;
  520. [Range(0, 100000000)]
  521. [DisplayName("댓글 일일 횟수 상한")]
  522. public int CommentDailyCount { get; set; } = 0;
  523. [Range(0, 100000000)]
  524. [DisplayName("댓글 일일 경험치 상한")]
  525. public int CommentDailyExp { get; set; } = 0;
  526. [Range(0, 100000000)]
  527. [DisplayName("댓글 일일 토큰 상한")]
  528. public int CommentDailyPoint { get; set; } = 0;
  529. [Range(0, 100000000)]
  530. [DisplayName("추천(누른 쪽) 일일 횟수 상한")]
  531. public int LikeGivenDailyCount { get; set; } = 0;
  532. [Range(0, 100000000)]
  533. [DisplayName("추천(누른 쪽) 일일 경험치 상한")]
  534. public int LikeGivenDailyExp { get; set; } = 0;
  535. [Range(0, 100000000)]
  536. [DisplayName("추천(받은 쪽) 일일 횟수 상한")]
  537. public int LikeReceivedDailyCount { get; set; } = 0;
  538. [Range(0, 100000000)]
  539. [DisplayName("추천(받은 쪽) 일일 토큰 상한")]
  540. public int LikeReceivedDailyPoint { get; set; } = 0;
  541. [Range(0, 100000000)]
  542. [DisplayName("채팅 일일 횟수 상한")]
  543. public int ChatDailyCount { get; set; } = 0;
  544. [Range(0, 100000000)]
  545. [DisplayName("채팅 일일 경험치 상한")]
  546. public int ChatDailyExp { get; set; } = 0;
  547. [Range(0, 100)]
  548. [DisplayName("응원 수수료율(%)")]
  549. public int CheerFeePercent { get; set; } = 20;
  550. [Range(0, 100000000)]
  551. [DisplayName("응원 최소 금액")]
  552. public int CheerMinAmount { get; set; } = 100;
  553. [Range(0, 2000000000)]
  554. [DisplayName("응원 일일 발신 총액 상한(0=무제한)")]
  555. public int CheerDailyMax { get; set; } = 0;
  556. }
  557. // 모의투자 설정 (Paper) — d4 §④
  558. public sealed class PaperConfigDto
  559. {
  560. [DisplayName("모의투자 활성화")]
  561. public bool Enabled { get; set; } = true;
  562. [Range(0, 100000)]
  563. [DisplayName("매매 수수료(Bp)")]
  564. public int FeeRateBp { get; set; } = 15;
  565. [Range(0, 100000)]
  566. [DisplayName("거래세(Bp)")]
  567. public int TaxRateBp { get; set; } = 18;
  568. [Range(0, 1000000000)]
  569. [DisplayName("최소 입금 토큰")]
  570. public int MinDeposit { get; set; } = 10000;
  571. [Range(0, 2000000000)]
  572. [DisplayName("최대 보유 토큰(0=무제한)")]
  573. public int MaxHolding { get; set; } = 0;
  574. [Range(0, 10000)]
  575. [DisplayName("출금 수익 소각(Bp, 0=사용안함)")]
  576. public int WithdrawProfitBurnBp { get; set; } = 0;
  577. [Range(0, 10000)]
  578. [DisplayName("1주문 상한(Bp, 3000=30%)")]
  579. public int OrderMaxPctBp { get; set; } = 3000;
  580. [Range(0, 100000)]
  581. [DisplayName("리더보드 등재 최소 체결수")]
  582. public int MinFillsForRank { get; set; } = 3;
  583. }
  584. public static Request From(Get.Response src) => new()
  585. {
  586. ID = src.ID,
  587. Basic = new BasicConfigDto
  588. {
  589. SiteName = src.Basic.SiteName,
  590. SiteURL = src.Basic.SiteURL,
  591. RootID = src.Basic.RootID,
  592. FromEmail = src.Basic.FromEmail,
  593. FromName = src.Basic.FromName,
  594. SmtpServer = src.Basic.SmtpServer,
  595. SmtpPort = src.Basic.SmtpPort,
  596. SmtpEnableSSL = src.Basic.SmtpEnableSSL,
  597. SmtpUsername = src.Basic.SmtpUsername,
  598. SmtpPassword = src.Basic.SmtpPassword,
  599. AdminWhiteIPList = src.Basic.AdminWhiteIPList,
  600. FrontWhiteIPList = src.Basic.FrontWhiteIPList,
  601. BlockAlertTitle = src.Basic.BlockAlertTitle,
  602. BlockAlertContent = src.Basic.BlockAlertContent,
  603. IsMaintenance = src.Basic.IsMaintenance,
  604. MaintenanceContent = src.Basic.MaintenanceContent,
  605. NoteDailySendLimit = src.Basic.NoteDailySendLimit
  606. },
  607. Images = new ImagesConfigDto
  608. {
  609. FaviconPath = src.Images.FaviconPath,
  610. LogoSquarePath = src.Images.LogoSquarePath,
  611. LogoHorizontalPath = src.Images.LogoHorizontalPath,
  612. OgDefaultPath = src.Images.OgDefaultPath,
  613. TwitterImagePath = src.Images.TwitterImagePath,
  614. AppleTouchIconPath = src.Images.AppleTouchIconPath,
  615. AppIcon192Path = src.Images.AppIcon192Path,
  616. AppIcon512Path = src.Images.AppIcon512Path
  617. },
  618. Meta = new MetaConfigDto
  619. {
  620. Keywords = src.Meta.Keywords,
  621. Description = src.Meta.Description,
  622. Author = src.Meta.Author,
  623. Viewport = src.Meta.Viewport,
  624. ApplicationName = src.Meta.ApplicationName,
  625. Generator = src.Meta.Generator,
  626. Robots = src.Meta.Robots,
  627. Adds = src.Meta.Adds
  628. },
  629. Company = new CompanyConfigDto
  630. {
  631. Name = src.Company.Name,
  632. RegNo = src.Company.RegNo,
  633. Address = src.Company.Address,
  634. ZipCode = src.Company.ZipCode,
  635. Owner = src.Company.Owner,
  636. Tel = src.Company.Tel,
  637. Fax = src.Company.Fax,
  638. RetailSaleNo = src.Company.RetailSaleNo,
  639. AddedSaleNo = src.Company.AddedSaleNo,
  640. Hosting = src.Company.Hosting,
  641. AdminName = src.Company.AdminName,
  642. AdminEmail = src.Company.AdminEmail,
  643. SiteUrl = src.Company.SiteUrl,
  644. BankCode = src.Company.BankCode,
  645. BankOwner = src.Company.BankOwner,
  646. BankNumber = src.Company.BankNumber
  647. },
  648. Account = new AccountConfigDto
  649. {
  650. IsRegisterBlock = src.Account.IsRegisterBlock,
  651. IsRegisterEmailAuth = src.Account.IsRegisterEmailAuth,
  652. PasswordMinLength = src.Account.PasswordMinLength,
  653. PasswordUppercaseLength = src.Account.PasswordUppercaseLength,
  654. PasswordNumbersLength = src.Account.PasswordNumbersLength,
  655. PasswordSpecialcharsLength = src.Account.PasswordSpecialcharsLength,
  656. DeniedEmailList = src.Account.DeniedEmailList,
  657. DeniedNameList = src.Account.DeniedNameList,
  658. ChangeEmailDay = src.Account.ChangeEmailDay,
  659. ChangeNameDay = src.Account.ChangeNameDay,
  660. ChangeSummaryDay = src.Account.ChangeSummaryDay,
  661. ChangeIntroDay = src.Account.ChangeIntroDay,
  662. ChangePasswordDay = src.Account.ChangePasswordDay,
  663. IsLoginEmailVerifiedOnly = src.Account.IsLoginEmailVerifiedOnly,
  664. MaxLoginTryCount = src.Account.MaxLoginTryCount,
  665. MaxLoginTryLimitSecond = src.Account.MaxLoginTryLimitSecond
  666. },
  667. EmailTemplate = new EmailTemplateConfigDto
  668. {
  669. RegisterEmailFormTitle = src.EmailTemplate.RegisterEmailFormTitle,
  670. RegisterEmailFormContent = src.EmailTemplate.RegisterEmailFormContent,
  671. RegistrationEmailFormTitle = src.EmailTemplate.RegistrationEmailFormTitle,
  672. RegistrationEmailFormContent = src.EmailTemplate.RegistrationEmailFormContent,
  673. ResetPasswordEmailFormTitle = src.EmailTemplate.ResetPasswordEmailFormTitle,
  674. ResetPasswordEmailFormContent = src.EmailTemplate.ResetPasswordEmailFormContent,
  675. ChangedPasswordEmailFormTitle = src.EmailTemplate.ChangedPasswordEmailFormTitle,
  676. ChangedPasswordEmailFormContent = src.EmailTemplate.ChangedPasswordEmailFormContent,
  677. WithdrawEmailFormTitle = src.EmailTemplate.WithdrawEmailFormTitle,
  678. WithdrawEmailFormContent = src.EmailTemplate.WithdrawEmailFormContent,
  679. WithdrawVerifyEmailFormTitle = src.EmailTemplate.WithdrawVerifyEmailFormTitle,
  680. WithdrawVerifyEmailFormContent = src.EmailTemplate.WithdrawVerifyEmailFormContent,
  681. EmailVerifyFormTitle = src.EmailTemplate.EmailVerifyFormTitle,
  682. EmailVerifyFormContent = src.EmailTemplate.EmailVerifyFormContent,
  683. ChangedEmailFormTitle = src.EmailTemplate.ChangedEmailFormTitle,
  684. ChangedEmailFormContent = src.EmailTemplate.ChangedEmailFormContent
  685. },
  686. External = new ExternalApiConfigDto
  687. {
  688. YouTubeApiKeyEnc = src.External.YouTubeApiKeyEnc,
  689. YouTubeApiName = src.External.YouTubeApiName,
  690. GoogleClientId = src.External.GoogleClientId,
  691. GoogleClientSecretEnc = src.External.GoogleClientSecretEnc,
  692. GoogleAppId = src.External.GoogleAppId,
  693. NaverLoginEnabled = src.External.NaverLoginEnabled,
  694. KakaoLoginEnabled = src.External.KakaoLoginEnabled,
  695. GoogleLoginEnabled = src.External.GoogleLoginEnabled,
  696. NaverClientId = src.External.NaverClientId,
  697. KakaoJavascriptKey = src.External.KakaoJavascriptKey,
  698. NaverSearchClientId = src.External.NaverSearchClientId
  699. // 비밀 키(Secret)는 화면에 되돌리지 않음 — 빈 값 = 기존 유지
  700. },
  701. // 토스 키는 화면에 되돌리지 않는다 (암호문 재제출로 인한 이중 암호화 방지 — 빈 값 = 기존 유지)
  702. Toss = new TossConfigDto
  703. {
  704. TossPayMode = src.Toss.TossPayMode
  705. },
  706. Attendance = new AttendanceConfigDto
  707. {
  708. IsEnabled = src.Attendance.IsEnabled,
  709. BaseExp = src.Attendance.BaseExp,
  710. BasePoint = src.Attendance.BasePoint,
  711. UseStreakBonus = src.Attendance.UseStreakBonus,
  712. StreakBonusPerDay = src.Attendance.StreakBonusPerDay,
  713. StreakBonusPointPerDay = src.Attendance.StreakBonusPointPerDay,
  714. StreakBonusMaxDays = src.Attendance.StreakBonusMaxDays,
  715. UseRankBonus = src.Attendance.UseRankBonus,
  716. RankBonusConfig = src.Attendance.RankBonusConfig
  717. },
  718. SignupReward = new SignupRewardConfigDto
  719. {
  720. Enabled = src.SignupReward.Enabled,
  721. CoinAmount = src.SignupReward.CoinAmount,
  722. CashAmount = src.SignupReward.CashAmount,
  723. ExpAmount = src.SignupReward.ExpAmount
  724. },
  725. Reward = new RewardConfigDto
  726. {
  727. PostExp = src.Reward.PostExp,
  728. PostPoint = src.Reward.PostPoint,
  729. CommentExp = src.Reward.CommentExp,
  730. CommentPoint = src.Reward.CommentPoint,
  731. LikeGivenExp = src.Reward.LikeGivenExp,
  732. LikeReceivedPoint = src.Reward.LikeReceivedPoint,
  733. MinPostLength = src.Reward.MinPostLength,
  734. MinCommentLength = src.Reward.MinCommentLength,
  735. NewMemberHoldDays = src.Reward.NewMemberHoldDays,
  736. PostDailyCount = src.Reward.PostDailyCount,
  737. PostDailyExp = src.Reward.PostDailyExp,
  738. PostDailyPoint = src.Reward.PostDailyPoint,
  739. CommentDailyCount = src.Reward.CommentDailyCount,
  740. CommentDailyExp = src.Reward.CommentDailyExp,
  741. CommentDailyPoint = src.Reward.CommentDailyPoint,
  742. LikeGivenDailyCount = src.Reward.LikeGivenDailyCount,
  743. LikeGivenDailyExp = src.Reward.LikeGivenDailyExp,
  744. LikeReceivedDailyCount = src.Reward.LikeReceivedDailyCount,
  745. LikeReceivedDailyPoint = src.Reward.LikeReceivedDailyPoint,
  746. ChatDailyCount = src.Reward.ChatDailyCount,
  747. ChatDailyExp = src.Reward.ChatDailyExp,
  748. CheerFeePercent = src.Reward.CheerFeePercent,
  749. CheerMinAmount = src.Reward.CheerMinAmount,
  750. CheerDailyMax = src.Reward.CheerDailyMax
  751. },
  752. Paper = new PaperConfigDto
  753. {
  754. Enabled = src.Paper.Enabled,
  755. FeeRateBp = src.Paper.FeeRateBp,
  756. TaxRateBp = src.Paper.TaxRateBp,
  757. MinDeposit = src.Paper.MinDeposit,
  758. MaxHolding = src.Paper.MaxHolding,
  759. WithdrawProfitBurnBp = src.Paper.WithdrawProfitBurnBp,
  760. OrderMaxPctBp = src.Paper.OrderMaxPctBp,
  761. MinFillsForRank = src.Paper.MinFillsForRank
  762. },
  763. // 키는 화면에 되돌리지 않음(빈 값=유지) — 플래그만 현재값 반영
  764. DataCollection = new DataCollectionConfigDto
  765. {
  766. StockDataMasterSync = src.DataCollection.StockDataMasterSync,
  767. StockDataDailyPriceSync = src.DataCollection.StockDataDailyPriceSync,
  768. KrxIndexSync = src.DataCollection.KrxIndexSync,
  769. KrxBondIndexSync = src.DataCollection.KrxBondIndexSync,
  770. KrxStockSync = src.DataCollection.KrxStockSync,
  771. KrxEtpSync = src.DataCollection.KrxEtpSync,
  772. KrxWarrantSync = src.DataCollection.KrxWarrantSync,
  773. KrxBondSync = src.DataCollection.KrxBondSync,
  774. KrxDerivativeSync = src.DataCollection.KrxDerivativeSync,
  775. KrxCommoditySync = src.DataCollection.KrxCommoditySync,
  776. KrxEsgSync = src.DataCollection.KrxEsgSync,
  777. OpenDartDisclosureSync = src.DataCollection.OpenDartDisclosureSync,
  778. KoreaEximMacroSync = src.DataCollection.KoreaEximMacroSync,
  779. KosisSync = src.DataCollection.KosisSync,
  780. WorldIndexEnabled = src.DataCollection.WorldIndexEnabled,
  781. MarketQuoteEnabled = src.DataCollection.MarketQuoteEnabled,
  782. SeibroIssuerSync = src.DataCollection.SeibroIssuerSync,
  783. SeibroDividendSync = src.DataCollection.SeibroDividendSync,
  784. SeibroSupplySync = src.DataCollection.SeibroSupplySync,
  785. SeibroCorpActionSync = src.DataCollection.SeibroCorpActionSync,
  786. SeibroBondSync = src.DataCollection.SeibroBondSync,
  787. SeibroDerivSync = src.DataCollection.SeibroDerivSync,
  788. SeibroForeignSync = src.DataCollection.SeibroForeignSync
  789. }
  790. };
  791. }