forked from votrongdao/FlowX
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLabelCapabilities.cs
More file actions
97 lines (82 loc) · 3.35 KB
/
Copy pathLabelCapabilities.cs
File metadata and controls
97 lines (82 loc) · 3.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
using FlowX;
namespace Crm;
/// <summary>
/// Renames one thing for one tenant, without renaming it for anybody else.
/// </summary>
/// <remarks>
/// <para>
/// <strong>The identifier never moves.</strong> A rename changes the label and nothing else: the
/// object's name, the field's name and the entity's kind stay what they were, because they are in
/// saved views, in guards, in roll-up filters, in jsonb keys and in whatever a client cached last
/// week. A settings screen that renamed the identifier would be a settings screen that silently
/// broke every one of those.
/// </para>
/// <para>
/// <strong><c>crm.admin</c>.</strong> Renaming what everybody in a tenant sees is not a thing one
/// representative does on their own screen.
/// </para>
/// </remarks>
[Capability("crm.label.set", Version = "1.0.0",
Authorization = Authorization.Permission, Permission = "crm.admin")]
public sealed class SetCrmLabel : ICapability<SetLabel, LabelSet>
{
private readonly LabelStore _labels;
/// <summary>Creates the capability.</summary>
/// <param name="labels">Writes the label.</param>
/// <exception cref="ArgumentNullException"><paramref name="labels"/> is null.</exception>
public SetCrmLabel(LabelStore labels)
{
ArgumentNullException.ThrowIfNull(labels);
_labels = labels;
}
/// <inheritdoc />
public async ValueTask<Result<LabelSet>> ExecuteAsync(
SetLabel input,
CapabilityContext ctx,
CancellationToken ct)
{
ArgumentNullException.ThrowIfNull(input);
ArgumentNullException.ThrowIfNull(ctx);
var subjects = (input.Target is null ? 0 : 1)
+ (input.Field is null ? 0 : 1)
+ (input.Entity is null ? 0 : 1);
if (subjects != 1)
{
return Result.Fail<LabelSet>(LabelErrors.NameOneSubject());
}
if (input.Column is { Length: > 0 } && input.Entity is null)
{
return Result.Fail<LabelSet>(LabelErrors.ColumnNeedsItsEntity());
}
if (input.Label is not { Length: > 0 and <= LabelLimits.MaxLength })
{
return Result.Fail<LabelSet>(LabelErrors.LabelIsNotUsable(input.Label ?? string.Empty));
}
if (input.Entity is { } kind)
{
var column = input.Column ?? LabelLimits.TheEntityItself;
// Checked against the closed list, so a settings screen cannot accumulate labels for
// columns that do not exist — rows nothing reads and nobody knows to delete.
if (column.Length > 0
&& !EntityColumns.Of(kind).Contains(column, StringComparer.Ordinal))
{
return Result.Fail<LabelSet>(LabelErrors.ColumnIsNotOfEntity(kind, column));
}
await _labels
.SetEntityLabelAsync(ctx.TenantId, kind, column, input.Label, ct)
.ConfigureAwait(false);
return Result.Ok(new LabelSet(input.Label));
}
var renamed = await _labels
.RenameAsync(
ctx.TenantId,
input.Target ?? input.Field!.Value,
input.Target is not null,
input.Label,
ct)
.ConfigureAwait(false);
return renamed
? Result.Ok(new LabelSet(input.Label))
: Result.Fail<LabelSet>(LabelErrors.SubjectNotFound());
}
}