Request.cs 29 KB

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