Dreamine.Web 1.0.0.0
WPF와 Blazor를 한 코드 흐름으로 연결하고 반복적인 MVVM 코드를 줄이는 오픈소스 FullKit 공식 웹 애플리케이션입니다.
로딩중...
검색중...
일치하는것 없음
AdminViewModel.cs
이 파일의 문서화 페이지로 가기
1using Dreamine.MVVM.ViewModels;
4
6
15public class AdminViewModel : ViewModelBase
16{
25 private readonly ILibraryStore _store;
43 private readonly DreamineOptions _opts;
52 private readonly XmlDocAutoLinker _autoLinker;
88 private readonly AdminAuthService _auth;
89
98 public bool IsAuthenticated { get; private set; }
107 public string LoginPassword { get; set; } = string.Empty;
116 public string StatusMessage { get; set; } = string.Empty;
117
126 public List<LibraryInfo> Libraries { get; private set; } = [];
127
128 // 라이브러리 편집
137 public LibraryInfo? Editing { get; private set; }
146 public bool IsEditing => Editing is not null;
147
148 // 사이트 설정 편집
157 public SiteSettings SiteEdit { get; private set; } = new();
166 public bool IsSiteEditing { get; private set; }
167
168 // 체험(Playground) 데모
177 public List<PlaygroundDemo> Demos { get; private set; } = [];
186 public PlaygroundDemo? EditingDemo { get; private set; }
195 public bool IsDemoEditing => EditingDemo is not null;
196
197 // 패스워드 변경
206 public string PwCurrent { get; set; } = string.Empty;
215 public string PwNew { get; set; } = string.Empty;
224 public string PwConfirm { get; set; } = string.Empty;
225
299 ILibraryStore store,
300 IPlaygroundStore playgroundStore,
301 DreamineOptions opts,
302 XmlDocAutoLinker autoLinker,
303 LibraryCatalogSyncService catalogSync,
304 VersionSyncService versionSync,
305 SiteSettingsService siteSettings,
306 AdminAuthService auth)
307 {
308 _store = store;
309 _playgroundStore = playgroundStore;
310 _opts = opts;
311 _autoLinker = autoLinker;
312 _catalogSync = catalogSync;
313 _versionSync = versionSync;
314 _siteSettings = siteSettings;
315 _auth = auth;
316 }
317
334 public Task<bool> LoginAsync()
335 {
336 if (_auth.Verify(LoginPassword))
337 {
338 IsAuthenticated = true;
339 StatusMessage = string.Empty;
340 return Task.FromResult(true);
341 }
342 StatusMessage = "비밀번호가 올바르지 않습니다.";
343 return Task.FromResult(false);
344 }
345
362 public async Task<string?> ChangePasswordAsync()
363 {
364 if (!_auth.Verify(PwCurrent))
365 return "현재 비밀번호가 올바르지 않습니다.";
366 if (string.IsNullOrWhiteSpace(PwNew) || PwNew.Length < 8)
367 return "새 비밀번호는 8자 이상이어야 합니다.";
368 if (PwNew != PwConfirm)
369 return "새 비밀번호와 확인이 일치하지 않습니다.";
370
371 await _auth.ChangePasswordAsync(PwNew);
372 PwCurrent = PwNew = PwConfirm = string.Empty;
373 return null; // null = success
374 }
375
392 public async Task LoadAsync()
393 {
394 Libraries = await _store.GetAllAsync();
395 Demos = await _playgroundStore.GetAllAsync();
396 StatusMessage = string.Empty;
397 }
398
399 // ── 라이브러리 편집 ──────────────────────────────────────────
400
409 public void StartNew()
410 {
411 Editing = new LibraryInfo { Id = Guid.NewGuid().ToString("N")[..8] };
412 IsSiteEditing = false;
413 EditingDemo = null;
414 }
415
432 public void StartEdit(LibraryInfo lib)
433 {
434 Editing = new LibraryInfo
435 {
436 Id = lib.Id,
437 Name = lib.Name,
438 Description = lib.Description,
439 DescriptionEn = lib.DescriptionEn,
440 Category = lib.Category,
441 Status = lib.Status,
442 Version = lib.Version,
443 NuGetId = lib.NuGetId,
444 RepoUrl = lib.RepoUrl,
445 XmlDocPath = lib.XmlDocPath,
446 SourceProjectPath = lib.SourceProjectPath,
447 TargetFramework = lib.TargetFramework,
448 Dependencies = [.. lib.Dependencies],
449 Tags = [.. lib.Tags],
450 SortOrder = lib.SortOrder,
451 IsVisible = lib.IsVisible
452 };
453 IsSiteEditing = false;
454 EditingDemo = null;
455 }
456
465 public void CancelEdit() => Editing = null;
466
483 public async Task SaveEditAsync()
484 {
485 if (Editing is null) return;
486 await _store.SaveAsync(Editing);
487 Editing = null;
488 await LoadAsync();
489 StatusMessage = "✅ 저장됐습니다.";
490 }
491
516 public async Task DeleteAsync(string id)
517 {
518 await _store.DeleteAsync(id);
519 await LoadAsync();
520 StatusMessage = "✅ 삭제됐습니다.";
521 }
522
539 public async Task AutoLinkXmlAsync()
540 {
541 var count = await _autoLinker.LinkAsync();
542 await LoadAsync();
543 StatusMessage = count > 0
544 ? $"✅ XML 문서 {count}개 자동 연결됐습니다."
545 : "XML 파일을 찾지 못했습니다. 빌드 여부를 확인하세요.";
546 }
547
564 public async Task SyncVersionsAsync()
565 {
566 var count = await _versionSync.SyncAsync();
567 await LoadAsync();
568 StatusMessage = count switch
569 {
570 -1 => "LibrarySourceRoot 경로가 설정되지 않았거나 존재하지 않습니다.",
571 0 => "모든 버전이 최신입니다.",
572 _ => $"✅ {count}개 라이브러리 버전이 동기화됐습니다."
573 };
574 }
575
592 public async Task SyncCatalogAsync()
593 {
594 var result = await _catalogSync.SyncAsync();
595 await LoadAsync();
596 StatusMessage = result.Added switch
597 {
598 -1 => "LibrarySourceRoot 경로가 설정되지 않았거나 존재하지 않습니다.",
599 _ when result.Added == 0 && result.Updated == 0 => $"프로젝트 {result.ScannedProjects}개 확인 완료. 변경 사항은 없습니다.",
600 _ => $"✅ 프로젝트 {result.ScannedProjects}개 스캔: 신규 {result.Added}개, 갱신 {result.Updated}개 반영됐습니다."
601 };
602 }
603
620 public void SetEditingTags(string raw)
621 {
622 if (Editing is null) return;
623 Editing.Tags = raw.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
624 }
625
626 // ── 체험(Playground) 데모 편집 ──────────────────────────────
627
636 public void StartNewDemo()
637 {
639 {
640 Id = Guid.NewGuid().ToString("N")[..8],
641 SortOrder = (Demos.Count == 0 ? 0 : Demos.Max(d => d.SortOrder)) + 10
642 };
643 Editing = null;
644 IsSiteEditing = false;
645 }
646
664 {
666 {
667 Id = demo.Id,
668 Title = demo.Title,
669 TitleEn = demo.TitleEn,
670 Description = demo.Description,
671 DescriptionEn = demo.DescriptionEn,
672 SortOrder = demo.SortOrder,
673 IsVisible = demo.IsVisible,
674 NavLabel = demo.NavLabel,
675 BlazorCode = demo.BlazorCode,
676 WpfCode = demo.WpfCode,
677 WinFormsCode = demo.WinFormsCode,
678 MauiCode = demo.MauiCode,
679 VmCode = demo.VmCode,
680 WpfShot = demo.WpfShot,
681 WinFormsShot = demo.WinFormsShot,
682 MauiShot = demo.MauiShot
683 };
684 Editing = null;
685 IsSiteEditing = false;
686 }
687
696 public void CancelDemoEdit() => EditingDemo = null;
697
714 public async Task SaveDemoEditAsync()
715 {
716 if (EditingDemo is null) return;
717 await _playgroundStore.SaveAsync(EditingDemo);
718 EditingDemo = null;
719 await LoadAsync();
720 StatusMessage = "✅ 체험 데모가 저장됐습니다.";
721 }
722
747 public async Task DeleteDemoAsync(string id)
748 {
749 await _playgroundStore.DeleteAsync(id);
750 await LoadAsync();
751 StatusMessage = "✅ 체험 데모가 삭제됐습니다.";
752 }
753
754 // ── 사이트 설정 ──────────────────────────────────────────────
755
764 public void StartSiteEdit()
765 {
766 var cur = _siteSettings.Current;
768 {
769 Title = cur.Title,
770 Description = cur.Description,
771 IconUrl = cur.IconUrl,
772 GitHubUrl = cur.GitHubUrl,
773 OgTitle = cur.OgTitle,
774 OgDescription = cur.OgDescription,
775 OgImageUrl = cur.OgImageUrl,
776 OgSiteName = cur.OgSiteName,
777 OgUrl = cur.OgUrl,
778 TwitterCard = cur.TwitterCard,
779 };
780 IsSiteEditing = true;
781 Editing = null;
782 EditingDemo = null;
783 }
784
793 public void CancelSiteEdit() => IsSiteEditing = false;
794
811 public async Task SaveSiteSettingsAsync()
812 {
813 await _siteSettings.SaveAsync(SiteEdit);
814 IsSiteEditing = false;
815 StatusMessage = "✅ 사이트 설정이 저장됐습니다.";
816 }
817}
void StartEditDemo(PlaygroundDemo demo)
readonly SiteSettingsService _siteSettings
readonly VersionSyncService _versionSync
readonly AdminAuthService _auth
readonly XmlDocAutoLinker _autoLinker
readonly LibraryCatalogSyncService _catalogSync
async Task< string?> ChangePasswordAsync()
AdminViewModel(ILibraryStore store, IPlaygroundStore playgroundStore, DreamineOptions opts, XmlDocAutoLinker autoLinker, LibraryCatalogSyncService catalogSync, VersionSyncService versionSync, SiteSettingsService siteSettings, AdminAuthService auth)
readonly IPlaygroundStore _playgroundStore