Codemaru 1.0.0.0
QR 코드, 모바일 랜딩 페이지, vCard 연락처 저장과 명함 디자인을 한 화면에서 제공하는 디지털 명함 서비스입니다.
로딩중...
검색중...
일치하는것 없음
LandingPagePublisher.cs
이 파일의 문서화 페이지로 가기
2using Microsoft.Extensions.Options;
3using System.IO;
4
5namespace Codemaru.Services;
6
15public sealed record LandingPagePublishResult(string FilePath, string PublicPath, string PublicUrl);
16
25public sealed class LandingPagePublishOptions
26{
35 public string WebRootPath { get; set; } = string.Empty;
36}
37
46public sealed class LandingPagePublisher
47{
56 private readonly string _webRootPath;
57
74 public LandingPagePublisher(IOptions<LandingPagePublishOptions> options)
75 {
76 var configuredPath = options.Value.WebRootPath;
77 _webRootPath = string.IsNullOrWhiteSpace(configuredPath)
78 ? Path.Combine(AppContext.BaseDirectory, "wwwroot")
79 : Path.GetFullPath(configuredPath);
80 }
81
130 public Task<LandingPagePublishResult> PublishIndexAsync(
131 CardProfile profile,
132 string html,
133 CancellationToken cancellationToken = default)
134 {
135 ArgumentNullException.ThrowIfNull(profile);
136
137 if (string.IsNullOrWhiteSpace(html))
138 {
139 throw new InvalidOperationException("저장할 HTML이 없습니다.");
140 }
141
142 var slugSegments = NormalizeSlug(profile.LandingSlug);
143 if (slugSegments.Length == 0)
144 {
145 throw new InvalidOperationException("랜딩 슬러그를 입력해 주세요.");
146 }
147
148 var targetDirectory = _webRootPath;
149 foreach (var segment in slugSegments)
150 {
151 targetDirectory = Path.Combine(targetDirectory, segment);
152 }
153 Directory.CreateDirectory(targetDirectory);
154
155 var filePath = Path.Combine(targetDirectory, "index.html");
156 return WriteAsync(profile, html, filePath, slugSegments, cancellationToken);
157 }
158
215 private static async Task<LandingPagePublishResult> WriteAsync(
216 CardProfile profile,
217 string html,
218 string filePath,
219 string[] slugSegments,
220 CancellationToken cancellationToken)
221 {
222 await File.WriteAllTextAsync(filePath, html, cancellationToken).ConfigureAwait(false);
223
224 var publicPath = "/" + string.Join("/", slugSegments) + "/index.html";
225 var publicUrl = BuildPublicUrl(profile, slugSegments);
226
227 return new LandingPagePublishResult(filePath, publicPath, publicUrl);
228 }
229
254 private static string[] NormalizeSlug(string slug)
255 {
256 return CardLandingPath.Split(slug)
257 .Select(CardLandingPath.Slugify)
258 .Where(static segment => !string.IsNullOrWhiteSpace(segment))
259 .ToArray();
260 }
261
294 private static string BuildPublicUrl(CardProfile profile, string[] slugSegments)
295 {
296 var website = string.IsNullOrWhiteSpace(profile.Website)
297 ? string.Empty
298 : profile.Website.Trim().TrimEnd('/');
299
300 var slug = string.Join("/", slugSegments);
301 if (string.IsNullOrWhiteSpace(website))
302 {
303 return "/" + slug + "/";
304 }
305
306 return website.EndsWith($"/{slug}", StringComparison.OrdinalIgnoreCase)
307 ? website + "/"
308 : $"{website}/{slug}/";
309 }
310}
record CardProfile(string Brand, string Tagline, string BackBrand, string BackTagline, string Category, string Name, string Role, string Email, string Phone, string Address, string Website, string LandingSlug, string AccentColor, string ShortBio, string LandingDescription, string VCardNote, string InternalMemo, string? LogoImageDataUrl, bool RemoveLogoBackground, double CardWidthMm, double CardHeightMm, string FrontFontFamily, string BackFontFamily, double FrontBrandFontSize, double FrontTaglineFontSize, double FrontCategoryFontSize, double FrontEmailFontSize, double BackBrandFontSize, double BackTaglineFontSize, double BackNameFontSize, double BackRoleFontSize, string LandingTheme, bool IncludePhoneInVCard, bool IncludeAddressInVCard, string? ImportedFrontImageDataUrl, string? ImportedBackImageDataUrl)
record LandingPagePublishResult(string FilePath, string PublicPath, string PublicUrl)
static string[] Split(string slug)
static string Slugify(string value)
Task< LandingPagePublishResult > PublishIndexAsync(CardProfile profile, string html, CancellationToken cancellationToken=default)
LandingPagePublisher(IOptions< LandingPagePublishOptions > options)
static string BuildPublicUrl(CardProfile profile, string[] slugSegments)
static async Task< LandingPagePublishResult > WriteAsync(CardProfile profile, string html, string filePath, string[] slugSegments, CancellationToken cancellationToken)
static string[] NormalizeSlug(string slug)