Skip to content

Commit

Permalink
squash
Browse files Browse the repository at this point in the history
  • Loading branch information
oskogstad committed Jul 1, 2024
1 parent 3d4df02 commit 285035b
Show file tree
Hide file tree
Showing 24 changed files with 1,531 additions and 97 deletions.
6 changes: 3 additions & 3 deletions docs/schema/V1/schema.verified.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ type GuiAction {

type Localization {
value: String!
cultureCode: String!
languageCode: String!
}

type Queries @authorize(policy: "enduser") {
Expand Down Expand Up @@ -205,8 +205,8 @@ input SearchDialogInput {
dueBefore: DateTime
"Search string for free text search. Will attempt to fuzzily match in all free text fields in the aggregate"
search: String
"Limit free text search to texts with this culture code, e.g. \"nb-NO\". Default: search all culture codes"
searchCultureCode: String
"Limit free text search to texts with this language code, e.g. 'no', 'en'. Culture codes will be normalized to neutral language codes (ISO 639). Default: search all culture codes"
searchLanguageCode: String
}

enum ActivityType {
Expand Down
24 changes: 12 additions & 12 deletions docs/schema/V1/swagger.verified.json
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@
"Value": [
{
"Value": "Some Title",
"CultureCode": "en-us"
"LanguageCode": "en"
}
],
"MediaType": null
Expand All @@ -237,7 +237,7 @@
"Value": [
{
"Value": "Some Summary",
"CultureCode": "en-us"
"LanguageCode": "en"
}
],
"MediaType": null
Expand All @@ -257,7 +257,7 @@
"DisplayName": [
{
"Value": "Some display name",
"CultureCode": "en-us"
"LanguageCode": "en"
}
],
"Urls": [
Expand All @@ -282,11 +282,11 @@
"Title": [
{
"Value": "GUI action title",
"CultureCode": "en-us"
"LanguageCode": "en"
},
{
"Value": "GUI action-tittel",
"CultureCode": "nb-no"
"LanguageCode": "nb"
}
],
"Prompt": null
Expand Down Expand Up @@ -323,11 +323,11 @@
"Description": [
{
"Value": "Some description",
"CultureCode": "en-us"
"LanguageCode": "en"
},
{
"Value": "En beskrivelse",
"CultureCode": "nb-no"
"LanguageCode": "nb"
}
]
}
Expand Down Expand Up @@ -786,9 +786,9 @@
}
},
{
"name": "searchCultureCode",
"name": "searchLanguageCode",
"in": "query",
"description": "Limit free text search to texts with this culture code, e.g. \\\"nb-NO\\\". Default: search all culture codes",
"description": "Limit free text search to texts with this language code, e.g. 'no', 'en'. Culture codes will be normalized to neutral language codes (ISO 639). Default: search all culture codes",
"schema": {
"type": "string",
"nullable": true
Expand Down Expand Up @@ -1503,9 +1503,9 @@
}
},
{
"name": "searchCultureCode",
"name": "searchLanguageCode",
"in": "query",
"description": "Limit free text search to texts with this culture code, e.g. \\\"nb-NO\\\". Default: search all culture codes",
"description": "Limit free text search to texts with this language code, e.g. 'no', 'en'. Culture codes will be normalized to neutral language codes (ISO 639). Default: search all culture codes",
"schema": {
"type": "string",
"nullable": true
Expand Down Expand Up @@ -2024,7 +2024,7 @@
"value": {
"type": "string"
},
"cultureCode": {
"languageCode": {
"type": "string"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ internal static Expression<Func<T, bool>> Or<T>(Expression<Func<T, bool>> expr1,
return Expression.Lambda<Func<T, bool>>(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
}

internal static Expression<Func<Localization, bool>> LocalizedSearchExpression(string? search, string? cultureCode)
internal static Expression<Func<Localization, bool>> LocalizedSearchExpression(string? search, string? languageCode)
{
return localization =>
(cultureCode == null || localization.CultureCode == cultureCode) &&
(languageCode == null || localization.LanguageCode == languageCode) &&
EF.Functions.ILike(localization.Value, $"%{search}%");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ namespace Digdir.Domain.Dialogporten.Application.Features.V1.Common.Localization

public sealed class LocalizationDto
{
private readonly string _cultureCode = null!;
private readonly string _languageCode = null!;

public required string Value { get; init; }
public required string CultureCode
public required string LanguageCode
{
get => _cultureCode;
init => _cultureCode = Localization.NormalizeCultureCode(value)!;
get => _languageCode;
init => _languageCode = Localization.NormalizeCultureCode(value)!;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,58 @@

namespace Digdir.Domain.Dialogporten.Application.Features.V1.Common.Localizations;

internal static class LocalizationValidatorContants
{
public const int MaximumLength = 255;

public const string NormalizationErrorMessage =
"Culture specific codes like 'en_GB' and 'en-US' are normalized to 'en' (ISO 639).";

public const string InvalidCultureCodeErrorMessageWithNorwegianHint =
InvalidCultureCodeErrorMessage + "Use 'nb' or 'nn' for Norwegian. ";

public const string InvalidCultureCodeErrorMessage =
"'{PropertyName}' '{PropertyValue}' is not a valid language code. ";
}

internal sealed class LocalizationDtosValidator : AbstractValidator<IEnumerable<LocalizationDto>>
{
public LocalizationDtosValidator(int maximumLength = 255)
public LocalizationDtosValidator(int maximumLength = LocalizationValidatorContants.MaximumLength)
{
RuleFor(x => x)
.UniqueBy(x => x.CultureCode)
.UniqueBy(x => x.LanguageCode)
.WithMessage(localizations =>
{
var duplicates = localizations
.GroupBy(y => y.LanguageCode)
.Where(g => g.Count() > 1)
.Select(g => g.Key);

return $"Can not contain duplicate items: [{string.Join(", ", duplicates)}]. " +
$"{LocalizationValidatorContants.NormalizationErrorMessage}";
})
.ForEach(x => x.SetValidator(new LocalizationDtoValidator(maximumLength)));
}
}

internal sealed class LocalizationDtoValidator : AbstractValidator<LocalizationDto>
{
public LocalizationDtoValidator(int maximumLength = 255)
public LocalizationDtoValidator(int maximumLength = LocalizationValidatorContants.MaximumLength)
{
RuleFor(x => x).NotNull();
RuleFor(x => x)
.NotNull();

RuleFor(x => x.Value)
.NotEmpty()
.NotNull()
.MaximumLength(maximumLength);

RuleFor(x => x.CultureCode)
RuleFor(x => x.LanguageCode)
.NotEmpty()
.Must(x => x is null || Localization.IsValidCultureCode(x))
.WithMessage("'{PropertyName}' must be a valid culture code.");
.Must(Localization.IsValidCultureCode)
.WithMessage(localization =>
(localization.LanguageCode == "no"
? LocalizationValidatorContants.InvalidCultureCodeErrorMessageWithNorwegianHint
: LocalizationValidatorContants.InvalidCultureCodeErrorMessage) +
LocalizationValidatorContants.NormalizationErrorMessage);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ internal sealed class LocalizationSetConverter<TLocalizationSet> : ITypeConverte
set ??= new TLocalizationSet();
set.Localizations.Merge(
sources: concreteDtos,
destinationKeySelector: x => x.CultureCode,
sourceKeySelector: x => x.CultureCode,
destinationKeySelector: x => x.LanguageCode,
sourceKeySelector: x => x.LanguageCode,
create: context.Mapper.Map<List<Localization>>,
update: context.Mapper.Update,
delete: DeleteDelegate.NoOp,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public MappingProfile()
CreateMap<LocalizationSet?, List<LocalizationDto>?>()
.ConvertUsing(src => src == null ? null :
src.Localizations
.Select(x => new LocalizationDto { CultureCode = x.CultureCode, Value = x.Value })
.Select(x => new LocalizationDto { LanguageCode = x.LanguageCode, Value = x.Value })
.ToList());

// In
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,15 @@ public async Task<GetDialogResult> Handle(GetDialogQuery request, CancellationTo
// layer behaviours in an expected manner. Therefore, we need to be a bit more verbose about it.
var dialog = await _db.Dialogs
.Include(x => x.Content.OrderBy(x => x.Id).ThenBy(x => x.CreatedAt))
.ThenInclude(x => x.Value.Localizations.OrderBy(x => x.CreatedAt).ThenBy(x => x.CultureCode))
.ThenInclude(x => x.Value.Localizations.OrderBy(x => x.CreatedAt).ThenBy(x => x.LanguageCode))
.Include(x => x.Attachments.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id))
.ThenInclude(x => x.DisplayName!.Localizations.OrderBy(x => x.CreatedAt).ThenBy(x => x.CultureCode))
.ThenInclude(x => x.DisplayName!.Localizations.OrderBy(x => x.CreatedAt).ThenBy(x => x.LanguageCode))
.Include(x => x.Attachments.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id))
.ThenInclude(x => x.Urls.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id))
.Include(x => x.GuiActions.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id))
.ThenInclude(x => x.Title!.Localizations.OrderBy(x => x.CreatedAt).ThenBy(x => x.CultureCode))
.ThenInclude(x => x.Title!.Localizations.OrderBy(x => x.CreatedAt).ThenBy(x => x.LanguageCode))
.Include(x => x.GuiActions.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id))
.ThenInclude(x => x!.Prompt!.Localizations.OrderBy(x => x.CreatedAt).ThenBy(x => x.CultureCode))
.ThenInclude(x => x!.Prompt!.Localizations.OrderBy(x => x.CreatedAt).ThenBy(x => x.LanguageCode))
.Include(x => x.ApiActions.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id))
.ThenInclude(x => x.Endpoints.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id))
.Include(x => x.Activities).ThenInclude(x => x.Description!.Localizations)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace Digdir.Domain.Dialogporten.Application.Features.V1.EndUser.Dialogs.Que

public sealed class SearchDialogQuery : SortablePaginationParameter<SearchDialogQueryOrderDefinition, SearchDialogDto>, IRequest<SearchDialogResult>
{
private readonly string? _searchCultureCode;
private readonly string? _searchLanguageCode;

/// <summary>
/// Filter by one or more service owner codes
Expand Down Expand Up @@ -87,12 +87,12 @@ public sealed class SearchDialogQuery : SortablePaginationParameter<SearchDialog
public string? Search { get; init; }

/// <summary>
/// Limit free text search to texts with this culture code, e.g. \"nb-NO\". Default: search all culture codes
/// Limit free text search to texts with this language code, e.g. 'no', 'en'. Culture codes will be normalized to neutral language codes (ISO 639). Default: search all culture codes
/// </summary>
public string? SearchCultureCode
public string? SearchLanguageCode
{
get => _searchCultureCode;
init => _searchCultureCode = Localization.NormalizeCultureCode(value);
get => _searchLanguageCode;
init => _searchLanguageCode = Localization.NormalizeCultureCode(value);
}
}

Expand Down Expand Up @@ -138,7 +138,7 @@ public async Task<SearchDialogResult> Handle(SearchDialogQuery request, Cancella
{
var currentUserInfo = await _userRegistry.GetCurrentUserInformation(cancellationToken);

var searchExpression = Expressions.LocalizedSearchExpression(request.Search, request.SearchCultureCode);
var searchExpression = Expressions.LocalizedSearchExpression(request.Search, request.SearchLanguageCode);
var authorizedResources = await _altinnAuthorization.GetAuthorizedResourcesForSearch(
request.Party ?? [],
request.ServiceResource ?? [],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Digdir.Domain.Dialogporten.Application.Common.Extensions.Enumerables;
using Digdir.Domain.Dialogporten.Application.Common.Extensions.FluentValidation;
using Digdir.Domain.Dialogporten.Application.Common.Pagination;
using Digdir.Domain.Dialogporten.Application.Features.V1.Common.Localizations;
using Digdir.Domain.Dialogporten.Domain.Localizations;
using FluentValidation;

Expand All @@ -15,9 +16,13 @@ public SearchDialogQueryValidator()
.MinimumLength(3)
.When(x => x.Search is not null);

RuleFor(x => x.SearchCultureCode)
RuleFor(x => x.SearchLanguageCode)
.Must(x => x is null || Localization.IsValidCultureCode(x))
.WithMessage("'{PropertyName}' must be a valid culture code.");
.WithMessage(searchQuery =>
(searchQuery.SearchLanguageCode == "no"
? LocalizationValidatorContants.InvalidCultureCodeErrorMessageWithNorwegianHint
: LocalizationValidatorContants.InvalidCultureCodeErrorMessage) +
LocalizationValidatorContants.NormalizationErrorMessage);

RuleFor(x => x)
.Must(x => !x.ServiceResource.IsNullOrEmpty() || !x.Party.IsNullOrEmpty())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,16 @@ public async Task<GetDialogResult> Handle(GetDialogQuery request, CancellationTo
// layer behaviours in an expected manner. Therefore we need to be a bit more verbose about it.
var dialog = await _db.Dialogs
.Include(x => x.Content.OrderBy(x => x.Id).ThenBy(x => x.CreatedAt))
.ThenInclude(x => x.Value.Localizations.OrderBy(x => x.CreatedAt).ThenBy(x => x.CultureCode))
.ThenInclude(x => x.Value.Localizations.OrderBy(x => x.CreatedAt).ThenBy(x => x.LanguageCode))
.Include(x => x.SearchTags.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id))
.Include(x => x.Attachments.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id))
.ThenInclude(x => x.DisplayName!.Localizations.OrderBy(x => x.CreatedAt).ThenBy(x => x.CultureCode))
.ThenInclude(x => x.DisplayName!.Localizations.OrderBy(x => x.CreatedAt).ThenBy(x => x.LanguageCode))
.Include(x => x.Attachments.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id))
.ThenInclude(x => x.Urls.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id))
.Include(x => x.GuiActions.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id))
.ThenInclude(x => x.Title!.Localizations.OrderBy(x => x.CreatedAt).ThenBy(x => x.CultureCode))
.ThenInclude(x => x.Title!.Localizations.OrderBy(x => x.CreatedAt).ThenBy(x => x.LanguageCode))
.Include(x => x.GuiActions.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id))
.ThenInclude(x => x!.Prompt!.Localizations.OrderBy(x => x.CreatedAt).ThenBy(x => x.CultureCode))
.ThenInclude(x => x!.Prompt!.Localizations.OrderBy(x => x.CreatedAt).ThenBy(x => x.LanguageCode))
.Include(x => x.ApiActions.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id))
.ThenInclude(x => x.Endpoints.OrderBy(x => x.CreatedAt).ThenBy(x => x.Id))
.Include(x => x.Activities).ThenInclude(x => x.Description!.Localizations)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace Digdir.Domain.Dialogporten.Application.Features.V1.ServiceOwner.Dialog

public sealed class SearchDialogQuery : SortablePaginationParameter<SearchDialogQueryOrderDefinition, SearchDialogDto>, IRequest<SearchDialogResult>
{
private string? _searchCultureCode;
private string? _searchLanguageCode;

/// <summary>
/// Filter by one or more service resources
Expand Down Expand Up @@ -95,12 +95,12 @@ public sealed class SearchDialogQuery : SortablePaginationParameter<SearchDialog
public string? Search { get; init; }

/// <summary>
/// Limit free text search to texts with this culture code, e.g. \"nb-NO\". Default: search all culture codes
/// Limit free text search to texts with this language code, e.g. 'no', 'en'. Culture codes will be normalized to neutral language codes (ISO 639). Default: search all culture codes
/// </summary>
public string? SearchCultureCode
public string? SearchLanguageCode
{
get => _searchCultureCode;
init => _searchCultureCode = Localization.NormalizeCultureCode(value);
get => _searchLanguageCode;
init => _searchLanguageCode = Localization.NormalizeCultureCode(value);
}
}
public sealed class SearchDialogQueryOrderDefinition : IOrderDefinition<SearchDialogDto>
Expand Down Expand Up @@ -141,7 +141,7 @@ public SearchDialogQueryHandler(
public async Task<SearchDialogResult> Handle(SearchDialogQuery request, CancellationToken cancellationToken)
{
var resourceIds = await _userResourceRegistry.GetCurrentUserResourceIds(cancellationToken);
var searchExpression = Expressions.LocalizedSearchExpression(request.Search, request.SearchCultureCode);
var searchExpression = Expressions.LocalizedSearchExpression(request.Search, request.SearchLanguageCode);

var query = _db.Dialogs
.WhereIf(!request.ServiceResource.IsNullOrEmpty(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Digdir.Domain.Dialogporten.Application.Common.Extensions.Enumerables;
using Digdir.Domain.Dialogporten.Application.Common.Extensions.FluentValidation;
using Digdir.Domain.Dialogporten.Application.Common.Pagination;
using Digdir.Domain.Dialogporten.Application.Features.V1.Common.Localizations;
using Digdir.Domain.Dialogporten.Domain.Localizations;
using Digdir.Domain.Dialogporten.Domain.Parties;
using Digdir.Domain.Dialogporten.Domain.Parties.Abstractions;
Expand All @@ -17,9 +18,13 @@ public SearchDialogQueryValidator()
.MinimumLength(3)
.When(x => x.Search is not null);

RuleFor(x => x.SearchCultureCode)
RuleFor(x => x.SearchLanguageCode)
.Must(x => x is null || Localization.IsValidCultureCode(x))
.WithMessage("'{PropertyName}' must be a valid culture code.");
.WithMessage(searchQuery =>
(searchQuery.SearchLanguageCode == "no"
? LocalizationValidatorContants.InvalidCultureCodeErrorMessageWithNorwegianHint
: LocalizationValidatorContants.InvalidCultureCodeErrorMessage) +
LocalizationValidatorContants.NormalizationErrorMessage);

RuleFor(x => x)
.Must(x => PartyIdentifier.TryParse(x.EndUserId, out var id) && id is NorwegianPersonIdentifier or SystemUserIdentifier)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ private static ReadOnlyCollection<string> ToPaths(this IEnumerable<AggregateNode
}

private static IEnumerable<string> ToLocalizationPathStrings(this LocalizationSet localizationSet, string parentPath) =>
localizationSet.Localizations.Select(x => $"{parentPath}/{x.CultureCode}");
localizationSet.Localizations.Select(x => $"{parentPath}/{x.LanguageCode}");

private static string ToName(this object obj) => obj switch
{
Expand Down
Loading

0 comments on commit 285035b

Please sign in to comment.