Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,14 @@ public static SearchIndex Create(string indexName)
{
IsFilterable = true,
},
new SimpleField("userInfoApiKey", SearchFieldDataType.String)
{
IsFilterable = true,
},
new SimpleField("userInfoField", SearchFieldDataType.String)
{
IsFilterable = true,
},
};

foreach (var (field, analyzer) in FieldAnalyzers.Values)
Expand Down
42 changes: 37 additions & 5 deletions backend/extensions/Squidex.Extensions/Text/Azure/AzureTextIndex.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,20 +123,52 @@ private Task SearchBySchemaAsync(List<(DomainId, double)> result, string text, I
CancellationToken ct = default)
{
var searchField = GetServeField(scope);
var searchFilter = $"{string.Join(" or ", schemaIds.Select(x => $"schemaId eq '{x}'"))} and {searchField} eq true";

var filter = $"{string.Join(" or ", schemaIds.Select(x => $"schemaId eq '{x}'"))} and {searchField} eq true";

return SearchAsync(result, text, filter, take, factor, ct);
return SearchAsync(result, text, searchFilter, take, factor, ct);
}

private Task SearchByAppAsync(List<(DomainId, double)> result, string text, App app, SearchScope scope, int take, double factor,
CancellationToken ct = default)
{
var searchField = GetServeField(scope);
var searchFilter = $"appId eq '{app.Id}' and {searchField} eq true";

return SearchAsync(result, text, searchFilter, take, factor, ct);
}

public async Task<UserInfoResult?> FindUserInfo(App app, ApiKeyQuery query, SearchScope scope,
CancellationToken ct = default)
{
Guard.NotNull(app);
Guard.NotNull(query);

var searchField = GetServeField(scope);
var searchFilter = $"appId eq '{app.Id}' and {searchField} eq true and userApiKey eq '{query.ApiKey}'";
var searchOptions = new SearchOptions
{
Filter = searchFilter,
};

var filter = $"appId eq '{app.Id}' and {searchField} eq true";
searchOptions.Select.Add("contentId");
searchOptions.Select.Add("userInfoApiKey");
searchOptions.Select.Add("userInfoRole");
searchOptions.Size = 1;
searchOptions.QueryType = SearchQueryType.Full;

var results = await searchClient.SearchAsync<SearchDocument>(searchFilter, searchOptions, ct);

await foreach (var item in results.Value.GetResultsAsync().WithCancellation(ct))
{
if (item != null)
{
var id = DomainId.Create(item.Document["contentId"].ToString()!);

return new UserInfoResult(id, item.Document["userInfoRole"].ToString()!);
}
}

return SearchAsync(result, text, filter, take, factor, ct);
return null;
}

private async Task SearchAsync(List<(DomainId, double)> result, string text, string filter, int take, double factor,
Expand Down
22 changes: 22 additions & 0 deletions backend/extensions/Squidex.Extensions/Text/Azure/CommandFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,28 @@ private static void UpsertTextEntry(UpsertIndexEntry upsert, IList<IndexDocument
}
}

if (upsert.UserInfos != null)
{
foreach (var userInfo in upsert.UserInfos)
{
var geoDocument = new SearchDocument
{
["docId"] = upsert.ToDocId(),
["appId"] = upsert.UniqueContentId.AppId.ToString(),
["appName"] = string.Empty,
["contentId"] = upsert.UniqueContentId.ContentId.ToString(),
["schemaId"] = upsert.SchemaId.Id.ToString(),
["schemaName"] = upsert.SchemaId.Name,
["serveAll"] = upsert.ServeAll,
["servePublished"] = upsert.ServePublished,
["userInfoApiKey"] = userInfo,
["userInfoRole"] = userInfo.Role,
};

batch.Add(IndexDocumentsAction.MergeOrUpload(geoDocument));
}
}

if (upsert.Texts is { Count: > 0 })
{
var document = new SearchDocument
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,28 @@ void AddArgs(object arg)
}
}

if (upsert.UserInfos != null)
{
foreach (var userInfo in upsert.UserInfos)
{
var userInfoApiKey = userInfo.ApiKey;
var userInfoRole = userInfo.Role;

AddArgs(new
{
appId = upsert.UniqueContentId.AppId.ToString(),
appName = string.Empty,
contentId = upsert.UniqueContentId.ContentId.ToString(),
schemaId = upsert.SchemaId.Id.ToString(),
schemaName = upsert.SchemaId.Name,
serveAll = upsert.ServeAll,
servePublished = upsert.ServePublished,
userInfoApiKey,
userInfoRole,
});
}
}

if (upsert.Texts is { Count: > 0 })
{
var texts = new Dictionary<string, string>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ public static Task ApplyAsync(IElasticSearchClient client, string indexName,
{
type = "geo_point",
},
["userInfoApiKey"] = new
{
type = "text",
},
},
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@

namespace Squidex.Extensions.Text.ElasticSearch;

public sealed partial class ElasticSearchTextIndex(IElasticSearchClient elasticClient, string indexName, IJsonSerializer jsonSerializer) : ITextIndex, IInitializable
public sealed partial class ElasticSearchTextIndex(IElasticSearchClient elasticClient, string indexName, IJsonSerializer jsonSerializer)
: ITextIndex, IInitializable
{
private static readonly Regex RegexLanguageNormal = BuildLanguageRegexNormal();
private static readonly Regex RegexLanguageStart = BuildLanguageRegexStart();
Expand Down Expand Up @@ -198,13 +199,62 @@ public Task ExecuteAsync(IndexCommand[] commands,
return await SearchAsync(elasticQuery, ct);
}

public async Task<UserInfoResult?> FindUserInfo(App app, ApiKeyQuery query, SearchScope scope,
CancellationToken ct = default)
{
Guard.NotNull(app);
Guard.NotNull(query);

var serveField = GetServeField(scope);

var elasticQuery = new
{
query = new
{
@bool = new
{
filter = new object[]
{
new
{
term = new Dictionary<string, string>
{
[serveField] = "true",
},
},
new
{
term = new Dictionary<string, string>
{
["userInfoApiKey.keyword"] = query.ApiKey,
},
},
},
},
},
_source = new[]
{
"contentId",
"userInfoApiKey",
"userInfoRole",
},
size = 1,
};

var hits = await elasticClient.SearchAsync(indexName, elasticQuery, ct);
var hit = hits.FirstOrDefault();

return hit != null ?
new UserInfoResult(DomainId.Create(hit["_source"]["contentId"]), hit["_source"]["userInfoRole"]) :
null;
}

private async Task<List<DomainId>> SearchAsync(object query,
CancellationToken ct)
{
var hits = await elasticClient.SearchAsync(indexName, query, ct);

var ids = new List<DomainId>();

foreach (var item in hits)
{
ids.Add(DomainId.Create(item["_source"]["contentId"]));
Expand Down
5 changes: 5 additions & 0 deletions backend/i18n/frontend_de.json
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@
"common.administration": "Verwaltung",
"common.administrationPageTitle": "Verwaltung",
"common.api": "API",
"common.apiKey": "API Key",
"common.apps": "Apps",
"common.aspectRatio": "Seitenverhältnis",
"common.assets": "Assets",
Expand Down Expand Up @@ -523,6 +524,7 @@
"contents.unsetValueConfirmTitle": "Möchten Sie den Wert zurücksetzen?",
"contents.updated": "Inhalt erfolgreich aktualisiert.",
"contents.updateFailed": "Fehler beim Aktualisieren des Inhalts. Bitte neu laden.",
"contents.userInfo.instructions": "Connect as this user with the following header. The first part of the value is the app name.\n\nDo not miss the colon and remember the assign a restrictive role.",
"contents.validate": "Validieren",
"contents.validationHint": "Bitte denken Sie daran, alle Sprachen zu überprüfen, wenn Sie Validierungsfehler sehen.",
"contents.versionCompare": "Vergleichen",
Expand Down Expand Up @@ -984,6 +986,9 @@
"schemas.fieldTypes.tags.countMin": "Min. Elemente",
"schemas.fieldTypes.tags.description": "Spezialformat für Tags.",
"schemas.fieldTypes.ui.description": "Trennzeichen für die Bearbeitungsoberfläche.",
"schemas.fieldTypes.user.description": "User Credentials for custom Auth.",
"schemas.fieldTypes.userInfo.defaultRole": "Default Role",
"schemas.fieldTypes.userInfo.defaultRoleHint": "The default role. If a value is set a user info with a random API Key will be generated.",
"schemas.hideFieldFailed": "Fehler beim Ausblenden des Feldes. Bitte neu laden.",
"schemas.import": "Schema importieren",
"schemas.indexes.addIndex": "Index hinzufügen",
Expand Down
5 changes: 5 additions & 0 deletions backend/i18n/frontend_en.json
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@
"common.administration": "Administration",
"common.administrationPageTitle": "Administration",
"common.api": "API",
"common.apiKey": "API Key",
"common.apps": "Apps",
"common.aspectRatio": "AspectRatio",
"common.assets": "Assets",
Expand Down Expand Up @@ -523,6 +524,7 @@
"contents.unsetValueConfirmTitle": "Do you want to unset the value?",
"contents.updated": "Content updated successfully.",
"contents.updateFailed": "Failed to update content. Please reload.",
"contents.userInfo.instructions": "Connect as this user with the following header. The first part of the value is the app name.\n\nDo not miss the colon and remember the assign a restrictive role.",
"contents.validate": "Validate",
"contents.validationHint": "Please remember to check all languages when you see validation errors.",
"contents.versionCompare": "Compare",
Expand Down Expand Up @@ -984,6 +986,9 @@
"schemas.fieldTypes.tags.countMin": "Min Items",
"schemas.fieldTypes.tags.description": "Special format for tags.",
"schemas.fieldTypes.ui.description": "Separator for editing UI.",
"schemas.fieldTypes.user.description": "User Credentials for custom Auth.",
"schemas.fieldTypes.userInfo.defaultRole": "Default Role",
"schemas.fieldTypes.userInfo.defaultRoleHint": "The default role. If a value is set a user info with a random API Key will be generated.",
"schemas.hideFieldFailed": "Failed to hide field. Please reload.",
"schemas.import": "Import schema",
"schemas.indexes.addIndex": "Add Index",
Expand Down
5 changes: 5 additions & 0 deletions backend/i18n/frontend_fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@
"common.administration": "Administration",
"common.administrationPageTitle": "Administration",
"common.api": "API",
"common.apiKey": "API Key",
"common.apps": "applications",
"common.aspectRatio": "Ratio d'aspect",
"common.assets": "Actifs",
Expand Down Expand Up @@ -523,6 +524,7 @@
"contents.unsetValueConfirmTitle": "Voulez-vous annuler la valeur\u00A0?",
"contents.updated": "Contenu mis à jour avec succès.",
"contents.updateFailed": "Échec de la mise à jour du contenu. Veuillez recharger.",
"contents.userInfo.instructions": "Connect as this user with the following header. The first part of the value is the app name.\n\nDo not miss the colon and remember the assign a restrictive role.",
"contents.validate": "Valider",
"contents.validationHint": "N'oubliez pas de vérifier toutes les langues lorsque vous voyez des erreurs de validation.",
"contents.versionCompare": "Comparer",
Expand Down Expand Up @@ -984,6 +986,9 @@
"schemas.fieldTypes.tags.countMin": "Articles minimum",
"schemas.fieldTypes.tags.description": "Format spécial pour les balises.",
"schemas.fieldTypes.ui.description": "Séparateur pour l'édition de l'interface utilisateur.",
"schemas.fieldTypes.user.description": "User Credentials for custom Auth.",
"schemas.fieldTypes.userInfo.defaultRole": "Default Role",
"schemas.fieldTypes.userInfo.defaultRoleHint": "The default role. If a value is set a user info with a random API Key will be generated.",
"schemas.hideFieldFailed": "Impossible de masquer le champ. Veuillez recharger.",
"schemas.import": "Calendrier d'importation",
"schemas.indexes.addIndex": "Add Index",
Expand Down
5 changes: 5 additions & 0 deletions backend/i18n/frontend_it.json
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@
"common.administration": "Amministrazione",
"common.administrationPageTitle": "Amministrazione",
"common.api": "API",
"common.apiKey": "API Key",
"common.apps": "App",
"common.aspectRatio": "Proporzioni",
"common.assets": "Risorse",
Expand Down Expand Up @@ -523,6 +524,7 @@
"contents.unsetValueConfirmTitle": "Sei sicuro di voler annullare il valore impostato?",
"contents.updated": "Contenuto aggiornato con successo.",
"contents.updateFailed": "Non è stato possibile aggiornare il contenuto. Per favore ricarica.",
"contents.userInfo.instructions": "Connect as this user with the following header. The first part of the value is the app name.\n\nDo not miss the colon and remember the assign a restrictive role.",
"contents.validate": "Convalida",
"contents.validationHint": "Ricorda di verificare tutte le lingue quando vedi errori di validazione.",
"contents.versionCompare": "Confronta",
Expand Down Expand Up @@ -984,6 +986,9 @@
"schemas.fieldTypes.tags.countMin": "Numero min di Elementi",
"schemas.fieldTypes.tags.description": "Formato speciale per i tag.",
"schemas.fieldTypes.ui.description": "Separatore per il pannello delle modifiche della UI.",
"schemas.fieldTypes.user.description": "User Credentials for custom Auth.",
"schemas.fieldTypes.userInfo.defaultRole": "Default Role",
"schemas.fieldTypes.userInfo.defaultRoleHint": "The default role. If a value is set a user info with a random API Key will be generated.",
"schemas.hideFieldFailed": "Non è stato possibile nascondere il campo. Per favore ricarica.",
"schemas.import": "Importa uno schema",
"schemas.indexes.addIndex": "Add Index",
Expand Down
5 changes: 5 additions & 0 deletions backend/i18n/frontend_nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@
"common.administration": "Administratie",
"common.administrationPageTitle": "Administratie",
"common.api": "API",
"common.apiKey": "API Key",
"common.apps": "Apps",
"common.aspectRatio": "AspectRatio",
"common.assets": "Bestanden",
Expand Down Expand Up @@ -523,6 +524,7 @@
"contents.unsetValueConfirmTitle": "Weet je zeker dat je de waarde leeg wilt maken?",
"contents.updated": "Inhoud succesvol bijgewerkt.",
"contents.updateFailed": "Bijwerken van inhoud is mislukt. Laad opnieuw.",
"contents.userInfo.instructions": "Connect as this user with the following header. The first part of the value is the app name.\n\nDo not miss the colon and remember the assign a restrictive role.",
"contents.validate": "Valideren",
"contents.validationHint": "Denk eraan om alle talen te controleren wanneer je validatiefouten ziet.",
"contents.versionCompare": "Vergelijk",
Expand Down Expand Up @@ -984,6 +986,9 @@
"schemas.fieldTypes.tags.countMin": "Min. items",
"schemas.fieldTypes.tags.description": "Speciaal formaat voor tags.",
"schemas.fieldTypes.ui.description": "Scheidingsteken voor het bewerken van gebruikersinterface.",
"schemas.fieldTypes.user.description": "User Credentials for custom Auth.",
"schemas.fieldTypes.userInfo.defaultRole": "Default Role",
"schemas.fieldTypes.userInfo.defaultRoleHint": "The default role. If a value is set a user info with a random API Key will be generated.",
"schemas.hideFieldFailed": "Kan veld niet verbergen. Laad opnieuw.",
"schemas.import": "Importeer schema",
"schemas.indexes.addIndex": "Add Index",
Expand Down
5 changes: 5 additions & 0 deletions backend/i18n/frontend_pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@
"common.administration": "Administração",
"common.administrationPageTitle": "Administração",
"common.api": "API",
"common.apiKey": "API Key",
"common.apps": "Aplicativos",
"common.aspectRatio": "AspectRatio",
"common.assets": "Ficheiros",
Expand Down Expand Up @@ -523,6 +524,7 @@
"contents.unsetValueConfirmTitle": "Quer desaparassar o valor?",
"contents.updated": "Conteúdo atualizado com sucesso.",
"contents.updateFailed": "Falhou na atualização do conteúdo. Por favor, recarregue.",
"contents.userInfo.instructions": "Connect as this user with the following header. The first part of the value is the app name.\n\nDo not miss the colon and remember the assign a restrictive role.",
"contents.validate": "Validar",
"contents.validationHint": "Por favor, lembre-se de verificar todos os idiomas quando vir erros de validação.",
"contents.versionCompare": "Comparar",
Expand Down Expand Up @@ -984,6 +986,9 @@
"schemas.fieldTypes.tags.countMin": "Min Itens",
"schemas.fieldTypes.tags.description": "Formato especial para tags.",
"schemas.fieldTypes.ui.description": "Separador para edição de UI.",
"schemas.fieldTypes.user.description": "User Credentials for custom Auth.",
"schemas.fieldTypes.userInfo.defaultRole": "Default Role",
"schemas.fieldTypes.userInfo.defaultRoleHint": "The default role. If a value is set a user info with a random API Key will be generated.",
"schemas.hideFieldFailed": "Falhou em esconder o campo. Por favor, recarregue.",
"schemas.import": "Esquema de importação",
"schemas.indexes.addIndex": "Add Index",
Expand Down
5 changes: 5 additions & 0 deletions backend/i18n/frontend_zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@
"common.administration": "管理",
"common.administrationPageTitle": "管理",
"common.api": "API",
"common.apiKey": "API Key",
"common.apps": "应用程序",
"common.aspectRatio": "纵横比",
"common.assets": "资源",
Expand Down Expand Up @@ -523,6 +524,7 @@
"contents.unsetValueConfirmTitle": "你想取消设置吗?",
"contents.updated": "内容更新成功。",
"contents.updateFailed": "更新内容失败,请重新加载。",
"contents.userInfo.instructions": "Connect as this user with the following header. The first part of the value is the app name.\n\nDo not miss the colon and remember the assign a restrictive role.",
"contents.validate": "验证",
"contents.validationHint": "当您看到验证错误时,请记住检查所有语言。",
"contents.versionCompare": "比较",
Expand Down Expand Up @@ -984,6 +986,9 @@
"schemas.fieldTypes.tags.countMin": "最小项目",
"schemas.fieldTypes.tags.description": "标签的特殊格式。",
"schemas.fieldTypes.ui.description": "编辑 UI 的分隔符。",
"schemas.fieldTypes.user.description": "User Credentials for custom Auth.",
"schemas.fieldTypes.userInfo.defaultRole": "Default Role",
"schemas.fieldTypes.userInfo.defaultRoleHint": "The default role. If a value is set a user info with a random API Key will be generated.",
"schemas.hideFieldFailed": "隐藏字段失败。请重新加载。",
"schemas.import": "导入Schemas",
"schemas.indexes.addIndex": "Add Index",
Expand Down
Loading
Loading