Browse Source

Confirm text for subscriptions and fixes to formatter.

pull/502/head
Sebastian 6 years ago
parent
commit
8b4e5cf765
  1. 25
      backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleEventFormatter.cs
  2. 4
      backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/ConfigAppLimitsPlan.cs
  3. 4
      backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/IAppLimitsPlan.cs
  4. 10
      backend/src/Squidex/Areas/Api/Controllers/Plans/Models/PlanDto.cs
  5. 20
      backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterTests.cs
  6. 12
      frontend/app/features/settings/pages/plans/plan.component.html
  7. 28
      frontend/app/shared/services/plans.service.spec.ts
  8. 4
      frontend/app/shared/services/plans.service.ts
  9. 4
      frontend/app/shared/state/plans.state.spec.ts

25
backend/src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleEventFormatter.cs

@ -12,12 +12,15 @@ using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using NodaTime;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Rules.EnrichedEvents;
using Squidex.Domain.Apps.Core.Scripting;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Json;
using Squidex.Infrastructure.Json.Objects;
using Squidex.Infrastructure.Security;
using Squidex.Shared.Identity;
using Squidex.Shared.Users;
namespace Squidex.Domain.Apps.Core.HandleRules
@ -27,8 +30,8 @@ namespace Squidex.Domain.Apps.Core.HandleRules
private const string Fallback = "null";
private const string ScriptSuffix = ")";
private const string ScriptPrefix = "Script(";
private static readonly Regex RegexPatternOld = new Regex(@"^(?<Type>[^_]*)_(?<Path>.*)", RegexOptions.Compiled);
private static readonly Regex RegexPatternNew = new Regex(@"^\{(?<Type>[^_]*)_(?<Path>.*)\}", RegexOptions.Compiled);
private static readonly Regex RegexPatternOld = new Regex(@"^(?<Type>[^_]*)_(?<Path>[^\s]*)", RegexOptions.Compiled);
private static readonly Regex RegexPatternNew = new Regex(@"^\{(?<Type>[^_]*)_(?<Path>[^\s]*)\}", RegexOptions.Compiled);
private readonly List<(char[] Pattern, Func<EnrichedEvent, string?> Replacer)> patterns = new List<(char[] Pattern, Func<EnrichedEvent, string?> Replacer)>();
private readonly IJsonSerializer jsonSerializer;
private readonly IUrlGenerator urlGenerator;
@ -324,6 +327,24 @@ namespace Squidex.Domain.Apps.Core.HandleRules
}
else if (current != null)
{
if (current is IUser user)
{
var type = segment;
if (string.Equals(type, "Name", StringComparison.OrdinalIgnoreCase))
{
type = SquidexClaimTypes.DisplayName;
}
var claim = user.Claims.FirstOrDefault(x => string.Equals(x.Type, type, StringComparison.OrdinalIgnoreCase));
if (claim != null)
{
current = claim.Value;
continue;
}
}
const BindingFlags bindingFlags =
BindingFlags.FlattenHierarchy |
BindingFlags.Public |

4
backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/ConfigAppLimitsPlan.cs

@ -15,10 +15,14 @@ namespace Squidex.Domain.Apps.Entities.Apps.Plans
public string Costs { get; set; }
public string? ConfirmText { get; set; }
public string? YearlyCosts { get; set; }
public string? YearlyId { get; set; }
public string? YearlyConfirmText { get; set; }
public long BlockingApiCalls { get; set; }
public long MaxApiCalls { get; set; }

4
backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/IAppLimitsPlan.cs

@ -15,10 +15,14 @@ namespace Squidex.Domain.Apps.Entities.Apps.Plans
string Costs { get; }
string? ConfirmText { get; }
string? YearlyCosts { get; }
string? YearlyId { get; }
string? YearlyConfirmText { get; }
long BlockingApiCalls { get; }
long MaxApiCalls { get; }

10
backend/src/Squidex/Areas/Api/Controllers/Plans/Models/PlanDto.cs

@ -31,6 +31,16 @@ namespace Squidex.Areas.Api.Controllers.Plans.Models
[Required]
public string Costs { get; set; }
/// <summary>
/// An optional confirm text for the monthly subscription.
/// </summary>
public string? ConfirmText { get; set; }
/// <summary>
/// An optional confirm text for the yearly subscription.
/// </summary>
public string? YearlyConfirmText { get; set; }
/// <summary>
/// The yearly costs of the plan.
/// </summary>

20
backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleEventFormatterTests.cs

@ -97,6 +97,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules
[Theory]
[InlineData("Name $APP_NAME has id $APP_ID")]
[InlineData("Name ${$EVENT_APPID.NAME} has id ${EVENT_APPID.ID}")]
[InlineData("Script(`Name ${event.appId.name} has id ${event.appId.id}`)")]
public void Should_format_app_information_from_event(string script)
{
@ -120,19 +121,32 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules
}
[Theory]
[InlineData("Date: $TIMESTAMP_DATE, Full: $TIMESTAMP_DATETIME")]
[InlineData("Script(`Date: ${formatDate(event.timestamp, 'yyyy-MM-dd')}, Full: ${formatDate(event.timestamp, 'yyyy-MM-dd-hh-mm-ss')}`)")]
[InlineData("Full: $TIMESTAMP_DATETIME")]
[InlineData("Script(`Full: ${formatDate(event.timestamp, 'yyyy-MM-dd-hh-mm-ss')}`)")]
public void Should_format_timestamp_information_from_event(string script)
{
var @event = new EnrichedContentEvent { Timestamp = now };
var result = sut.Format(script, @event);
Assert.Equal($"Date: {now:yyyy-MM-dd}, Full: {now:yyyy-MM-dd-hh-mm-ss}", result);
Assert.Equal($"Full: {now:yyyy-MM-dd-hh-mm-ss}", result);
}
[Theory]
[InlineData("Date: $TIMESTAMP_DATE")]
[InlineData("Script(`Date: ${formatDate(event.timestamp, 'yyyy-MM-dd')}`)")]
public void Should_format_timestamp_date_information_from_event(string script)
{
var @event = new EnrichedContentEvent { Timestamp = now };
var result = sut.Format(script, @event);
Assert.Equal($"Date: {now:yyyy-MM-dd}", result);
}
[Theory]
[InlineData("From $MENTIONED_NAME ($MENTIONED_EMAIL, $MENTIONED_ID)")]
[InlineData("From ${COMMENT_MENTIONEDUSER.NAME} (${COMMENT_MENTIONEDUSER.EMAIL}, ${COMMENT_MENTIONEDUSER.ID})")]
[InlineData("Script(`From ${event.mentionedUser.name} (${event.mentionedUser.email}, ${event.mentionedUser.id})`)")]
public void Should_format_email_and_display_name_from_mentioned_user(string script)
{

12
frontend/app/features/settings/pages/plans/plan.component.html

@ -22,7 +22,11 @@
&#10003; Selected
</button>
<button *ngIf="!planInfo.isSelected" class="btn btn-block btn-success" [disabled]="plansState.isDisabled | async" (click)="changeMonthly()">
<button *ngIf="!planInfo.isSelected" class="btn btn-block btn-success" [disabled]="plansState.isDisabled | async"
(sqxConfirmClick)="changeMonthly()"
[confirmTitle]="'Change subscription'"
[confirmText]="planInfo.plan.confirmText"
[confirmRequired]="planInfo.plan.confirmText">
Change
</button>
</div>
@ -37,7 +41,11 @@
&#10003; Selected
</button>
<button *ngIf="!planInfo.isYearlySelected" class="btn btn-block btn-success" [disabled]="plansState.isDisabled | async" (click)="changeYearly()">
<button *ngIf="!planInfo.isYearlySelected" class="btn btn-block btn-success" [disabled]="plansState.isDisabled | async"
(sqxConfirmClick)="changeYearly()"
[confirmTitle]="'Change subscription'"
[confirmText]="planInfo.plan.yearlyConfirmText"
[confirmRequired]="planInfo.plan.yearlyConfirmText">
Change
</button>
</div>

28
frontend/app/shared/services/plans.service.spec.ts

@ -60,18 +60,22 @@ describe('PlansService', () => {
id: 'free',
name: 'Free',
costs: '14 €',
confirmText: 'Change for 14 € per month?',
yearlyId: 'free_yearly',
yearlyCosts: '12 €',
yearlyCosts: '120 €',
yearlyConfirmText: 'Change for 120 € per year?',
maxApiCalls: 1000,
maxAssetSize: 1500,
maxContributors: 2500
},
{
id: 'prof',
name: 'Prof',
id: 'professional',
name: 'Professional',
costs: '18 €',
yearlyId: 'prof_yearly',
yearlyCosts: '16 €',
confirmText: 'Change for 18 € per month?',
yearlyId: 'professional_yearly',
yearlyCosts: '160 €',
yearlyConfirmText: 'Change for 160 € per year?',
maxApiCalls: 4000,
maxAssetSize: 5500,
maxContributors: 6500
@ -89,8 +93,18 @@ describe('PlansService', () => {
currentPlanId: '123',
planOwner: '456',
plans: [
new PlanDto('free', 'Free', '14 €', 'free_yearly', '12 €', 1000, 1500, 2500),
new PlanDto('prof', 'Prof', '18 €', 'prof_yearly', '16 €', 4000, 5500, 6500)
new PlanDto(
'free', 'Free', '14 €',
'Change for 14 € per month?',
'free_yearly', '120 €',
'Change for 120 € per year?',
1000, 1500, 2500),
new PlanDto(
'professional', 'Professional', '18 €',
'Change for 18 € per month?',
'professional_yearly', '160 €',
'Change for 160 € per year?',
4000, 5500, 6500)
],
hasPortal: true
},

4
frontend/app/shared/services/plans.service.ts

@ -32,8 +32,10 @@ export class PlanDto {
public readonly id: string,
public readonly name: string,
public readonly costs: string,
public readonly confirmText: string | undefined,
public readonly yearlyId: string,
public readonly yearlyCosts: string,
public readonly yearlyConfirmText: string | undefined,
public readonly maxApiCalls: number,
public readonly maxAssetSize: number,
public readonly maxContributors: number
@ -75,8 +77,10 @@ export class PlansService {
item.id,
item.name,
item.costs,
item.confirmText,
item.yearlyId,
item.yearlyCosts,
item.yearlyConfirmText,
item.maxApiCalls,
item.maxAssetSize,
item.maxContributors)),

4
frontend/app/shared/state/plans.state.spec.ts

@ -33,8 +33,8 @@ describe('PlansState', () => {
currentPlanId: 'id1',
planOwner: creator,
plans: [
new PlanDto('id1', 'name1', '100€', 'id1_yearly', '200€', 1, 1, 1),
new PlanDto('id2', 'name2', '400€', 'id2_yearly', '800€', 2, 2, 2)
new PlanDto('id1', 'name1', '100€', undefined, 'id1_yearly', '200€', undefined, 1, 1, 1),
new PlanDto('id2', 'name2', '400€', undefined, 'id2_yearly', '800€', undefined, 2, 2, 2)
],
hasPortal: true
};

Loading…
Cancel
Save