WeddingThankYou
1.0.0.0
결혼식 이후 감사 인사와 사진, 계좌 안내, 연락처를 모바일 페이지로 전달하는 감사장 서비스입니다.
Toggle main menu visibility
로딩중...
검색중...
일치하는것 없음
JsonTenantStore.cs
이 파일의 문서화 페이지로 가기
1
using
System;
2
using
System.Collections.Generic;
3
using
System.IO;
4
using
System.Text.Json;
5
using
System.Text.Json.Serialization;
6
using
System.Threading;
7
using
System.Threading.Tasks;
8
using
Wedding.Common;
9
using
WeddingThankYou.Models
;
10
11
namespace
WeddingThankYou.Services
;
12
21
public
sealed
class
JsonTenantStore
:
ITenantStore
22
{
31
private
readonly
string
_dataRoot
;
40
private
static
readonly SemaphoreSlim
_gate
=
new
(1, 1);
41
50
private
static
readonly JsonSerializerOptions
_jsonOpts
=
new
()
51
{
52
WriteIndented =
true
,
53
PropertyNameCaseInsensitive =
true
,
54
Converters = {
new
WeddingLayoutModeJsonConverter(),
new
JsonStringEnumConverter() }
55
};
56
73
public
JsonTenantStore
(
WeddingOptions
opts)
74
{
75
_dataRoot
= opts.
ResolvedDataPath
;
76
Directory.CreateDirectory(
_dataRoot
);
77
}
78
103
public
string
GetTenantDataPath
(
string
slug) =>
104
Path.Combine(
_dataRoot
,
Sanitize
(slug));
105
138
public
async Task<TenantConfig?>
GetAsync
(
string
slug, CancellationToken ct =
default
)
139
{
140
var path =
ConfigPath
(slug);
141
if
(!File.Exists(path))
return
null
;
142
143
await
_gate
.WaitAsync(ct).ConfigureAwait(
false
);
144
try
145
{
146
return
await
ReadTenantAsync
(path, ct).ConfigureAwait(
false
);
147
}
148
finally
{
_gate
.Release(); }
149
}
150
175
public
async Task<IReadOnlyList<TenantConfig>>
GetAllAsync
(CancellationToken ct =
default
)
176
{
177
var list =
new
List<TenantConfig>();
178
if
(!Directory.Exists(
_dataRoot
))
return
list;
179
180
foreach
(var dir
in
Directory.GetDirectories(
_dataRoot
))
181
{
182
var cfg = Path.Combine(dir,
"config.json"
);
183
if
(!File.Exists(cfg))
continue
;
184
185
await
_gate
.WaitAsync(ct).ConfigureAwait(
false
);
186
try
187
{
188
var t = await
ReadTenantAsync
(cfg, ct).ConfigureAwait(
false
);
189
if
(t !=
null
) list.Add(t);
190
}
191
catch
(JsonException ex)
192
{
193
LogTenantReadError
(cfg, ex);
194
}
195
finally
{
_gate
.Release(); }
196
}
197
return
list;
198
}
199
232
public
async Task
SaveAsync
(
TenantConfig
config, CancellationToken ct =
default
)
233
{
234
var dir =
GetTenantDataPath
(config.
Slug
);
235
Directory.CreateDirectory(dir);
236
Directory.CreateDirectory(Path.Combine(dir,
"gallery"
));
237
Directory.CreateDirectory(Path.Combine(dir,
"thumb"
));
238
239
var tmp =
ConfigPath
(config.
Slug
) +
".tmp"
;
240
await
_gate
.WaitAsync(ct).ConfigureAwait(
false
);
241
try
242
{
243
await
using
(var fs = File.Create(tmp))
244
await JsonSerializer.SerializeAsync(fs, config,
_jsonOpts
, ct).ConfigureAwait(
false
);
245
246
File.Copy(tmp,
ConfigPath
(config.
Slug
), overwrite:
true
);
247
File.Delete(tmp);
248
}
249
finally
{
_gate
.Release(); }
250
}
251
284
public
Task<bool>
ExistsAsync
(
string
slug, CancellationToken ct =
default
) =>
285
Task.FromResult(File.Exists(
ConfigPath
(slug)));
286
319
public
Task
DeleteAsync
(
string
slug, CancellationToken ct =
default
)
320
{
321
var dir =
GetTenantDataPath
(slug);
322
if
(Directory.Exists(dir))
323
Directory.Delete(dir, recursive:
true
);
324
return
Task.CompletedTask;
325
}
326
351
private
string
ConfigPath
(
string
slug) =>
352
Path.Combine(
GetTenantDataPath
(slug),
"config.json"
);
353
378
private
static
string
Sanitize
(
string
slug) =>
379
string
.Concat(slug.ToLowerInvariant().Split(Path.GetInvalidFileNameChars()));
380
413
private
static
async Task<TenantConfig?>
ReadTenantAsync
(
string
path, CancellationToken ct)
414
{
415
var json = await File.ReadAllTextAsync(path, ct).ConfigureAwait(
false
);
416
LogLegacyLayoutModeFallback
(path, json);
417
return
JsonSerializer.Deserialize<
TenantConfig
>(json,
_jsonOpts
);
418
}
419
444
private
static
void
LogLegacyLayoutModeFallback
(
string
path,
string
json)
445
{
446
var raw =
TryGetDesignLayoutMode
(json);
447
if
(raw is
null
||
IsCanonicalLayoutMode
(raw))
return
;
448
449
Console.Error.WriteLine($
"[JsonTenantStore] Legacy DesignSettings.LayoutMode '{raw}' in '{path}' was loaded with compatibility fallback."
);
450
}
451
476
private
static
string
?
TryGetDesignLayoutMode
(
string
json)
477
{
478
try
479
{
480
using
var doc = JsonDocument.Parse(json);
481
if
(!
TryGetProperty
(doc.RootElement,
"DesignSettings"
, out var design))
return
null
;
482
if
(!
TryGetProperty
(design,
"LayoutMode"
, out var layout))
return
null
;
483
484
return
layout.ValueKind
switch
485
{
486
JsonValueKind.String => layout.GetString(),
487
JsonValueKind.Null =>
""
,
488
JsonValueKind.Number => layout.GetRawText(),
489
_ => layout.GetRawText(),
490
};
491
}
492
catch
(JsonException)
493
{
494
return
null
;
495
}
496
}
497
538
private
static
bool
TryGetProperty
(JsonElement element,
string
name, out JsonElement value)
539
{
540
foreach
(var property
in
element.EnumerateObject())
541
{
542
if
(
string
.Equals(property.Name, name, StringComparison.OrdinalIgnoreCase))
543
{
544
value =
property
.Value;
545
return
true
;
546
}
547
}
548
549
value =
default
;
550
return
false
;
551
}
552
577
private
static
bool
IsCanonicalLayoutMode
(
string
? value) =>
578
value is not
null
579
&& (
string
.Equals(value,
"WebPage"
, StringComparison.Ordinal)
580
||
string
.Equals(value,
"TabMenu"
, StringComparison.Ordinal)
581
||
string
.Equals(value,
"Gallery"
, StringComparison.Ordinal)
582
||
string
.Equals(value,
"Story"
, StringComparison.Ordinal)
583
||
string
.Equals(value,
"Card"
, StringComparison.Ordinal)
584
||
string
.Equals(value,
"PhotoBook"
, StringComparison.Ordinal));
585
610
private
static
void
LogTenantReadError
(
string
path, JsonException ex)
611
{
612
Console.Error.WriteLine($
"[JsonTenantStore] Skipped invalid tenant JSON '{path}': {ex.Message}"
);
613
}
614
}
WeddingThankYou.Models
Definition
AccountInfo.cs:1
WeddingThankYou.Services
Definition
CsvGuestbookStorage.cs:12
WeddingThankYou.Models.TenantConfig
Definition
TenantConfig.cs:14
WeddingThankYou.Models.TenantConfig.Slug
string Slug
Definition
TenantConfig.cs:23
WeddingThankYou.Services.ITenantStore
Definition
ITenantStore.cs:14
WeddingThankYou.Services.JsonTenantStore.JsonTenantStore
JsonTenantStore(WeddingOptions opts)
Definition
JsonTenantStore.cs:73
WeddingThankYou.Services.JsonTenantStore.TryGetProperty
static bool TryGetProperty(JsonElement element, string name, out JsonElement value)
Definition
JsonTenantStore.cs:538
WeddingThankYou.Services.JsonTenantStore.LogTenantReadError
static void LogTenantReadError(string path, JsonException ex)
Definition
JsonTenantStore.cs:610
WeddingThankYou.Services.JsonTenantStore.GetAsync
async Task< TenantConfig?> GetAsync(string slug, CancellationToken ct=default)
Definition
JsonTenantStore.cs:138
WeddingThankYou.Services.JsonTenantStore.Sanitize
static string Sanitize(string slug)
Definition
JsonTenantStore.cs:378
WeddingThankYou.Services.JsonTenantStore.SaveAsync
async Task SaveAsync(TenantConfig config, CancellationToken ct=default)
Definition
JsonTenantStore.cs:232
WeddingThankYou.Services.JsonTenantStore.IsCanonicalLayoutMode
static bool IsCanonicalLayoutMode(string? value)
Definition
JsonTenantStore.cs:577
WeddingThankYou.Services.JsonTenantStore.TryGetDesignLayoutMode
static ? string TryGetDesignLayoutMode(string json)
Definition
JsonTenantStore.cs:476
WeddingThankYou.Services.JsonTenantStore._jsonOpts
static readonly JsonSerializerOptions _jsonOpts
Definition
JsonTenantStore.cs:50
WeddingThankYou.Services.JsonTenantStore.DeleteAsync
Task DeleteAsync(string slug, CancellationToken ct=default)
Definition
JsonTenantStore.cs:319
WeddingThankYou.Services.JsonTenantStore.ExistsAsync
Task< bool > ExistsAsync(string slug, CancellationToken ct=default)
Definition
JsonTenantStore.cs:284
WeddingThankYou.Services.JsonTenantStore.GetTenantDataPath
string GetTenantDataPath(string slug)
Definition
JsonTenantStore.cs:103
WeddingThankYou.Services.JsonTenantStore.LogLegacyLayoutModeFallback
static void LogLegacyLayoutModeFallback(string path, string json)
Definition
JsonTenantStore.cs:444
WeddingThankYou.Services.JsonTenantStore.ReadTenantAsync
static async Task< TenantConfig?> ReadTenantAsync(string path, CancellationToken ct)
Definition
JsonTenantStore.cs:413
WeddingThankYou.Services.JsonTenantStore._dataRoot
readonly string _dataRoot
Definition
JsonTenantStore.cs:31
WeddingThankYou.Services.JsonTenantStore._gate
static readonly SemaphoreSlim _gate
Definition
JsonTenantStore.cs:40
WeddingThankYou.Services.JsonTenantStore.ConfigPath
string ConfigPath(string slug)
Definition
JsonTenantStore.cs:351
WeddingThankYou.Services.JsonTenantStore.GetAllAsync
async Task< IReadOnlyList< TenantConfig > > GetAllAsync(CancellationToken ct=default)
Definition
JsonTenantStore.cs:175
WeddingThankYou.Services.WeddingOptions
Definition
WeddingOptions.cs:16
WeddingThankYou.Services.WeddingOptions.ResolvedDataPath
string ResolvedDataPath
Definition
WeddingOptions.cs:72
Services
JsonTenantStore.cs
다음에 의해 생성됨 :
1.17.0