Commit 1f896aee authored by Magnus Westergaard's avatar Magnus Westergaard
Browse files

DEICH-5621: Handle reserved characters to (among other things) allow field search by URI.

parent ced7aafd
......@@ -17,11 +17,11 @@ import {
import { Block, Flex, Icon } from "@digibib/deichman-ui";
const roleSearchField = {
mainEntry: "work.mainEntryInfo.id", // pseudo-role
[ACTOR]: "work.agentsInfo.actors.id",
[DIRECTOR]: "work.agentsInfo.directors.id",
[FEATURING]: "work.agentsInfo.featuring.id",
[PRODUCTION_COMPANY]: "work.agentsInfo.productionCompanies.id"
mainEntry: "work.mainEntryInfo.uri", // pseudo-role
[ACTOR]: "work.agentsInfo.actors.uri",
[DIRECTOR]: "work.agentsInfo.directors.uri",
[FEATURING]: "work.agentsInfo.featuring.uri",
[PRODUCTION_COMPANY]: "work.agentsInfo.productionCompanies.uri"
};
const DynamicListFromAgent = ({
......@@ -35,8 +35,7 @@ const DynamicListFromAgent = ({
const agentUri = agent.id;
const pLink = pageLinkFromUri(agentUri, agentLabel);
const agentId = agentUri.substring(agentUri.lastIndexOf("/") + 1);
const agentQuery = `${roleSearchField[agentRole]}:${agentId}`;
const agentQuery = `${roleSearchField[agentRole]}:"${agentUri}"`;
const mediaTypeQuery = mediaType
? `?mediatype=mediaType_${translations[mediaType]}`
: "";
......
......@@ -2,6 +2,7 @@ package common
import (
"encoding/json"
"fmt"
"strings"
"github.com/olivere/elastic/v7"
......@@ -22,8 +23,21 @@ type Bucket struct {
var (
logger = log.WithField("logger_name", "common.go")
// based on https://www.elastic.co/guide/en/elasticsearch/reference/7.11/query-dsl-query-string-query.html#_reserved_characters (with '<', '>', '&&' and '||' left out)
esReservedCharacters = []string{"+", "-", "=", "!", "(", ")", "{", "}", "[", "]", "^", `"`, "~", "*", "?", ":", `\`, "/"}
)
var reservedCharReplacer *strings.Replacer
func init() {
var args []string
for _, reserved := range esReservedCharacters {
args = append(args, reserved, fmt.Sprintf(`\%s`, reserved))
}
reservedCharReplacer = strings.NewReplacer(args...)
}
func CreateFilterQuery(simpleField string, value interface{}) []elastic.Query {
filterQueries := make([]elastic.Query, 0)
switch simpleField {
......@@ -85,3 +99,18 @@ func CreateSortBy(sortField string, sortOrder string) elastic.Sorter {
}
return elastic.NewFieldSort(sortField + field).Order(strings.HasPrefix(sortOrder, "asc"))
}
// escape reserved characters, but preserve any leading or trailing wildcards
func EscapeQueryStringQuery(q string) string {
wildcard := "*"
trimmedQ := strings.TrimSuffix(strings.TrimPrefix(q, wildcard), wildcard)
escapedQuery := reservedCharReplacer.Replace(trimmedQ)
if (strings.HasPrefix(q, wildcard)) {
escapedQuery = fmt.Sprintf("%s%s", wildcard, escapedQuery)
}
if (strings.HasSuffix(q, wildcard)) {
escapedQuery = fmt.Sprintf("%s%s", escapedQuery, wildcard)
}
return escapedQuery
}
package common
import (
"testing"
)
func TestQueryStringQueryEscaper(t *testing.T) {
cases := []struct {
Input string
Expect string
}{
{
Input: "",
Expect: "",
},
{
Input: "Face/off",
Expect: `Face\/off`,
},
{
Input: "http://data.deichman.no/person/h28328100",
Expect: `http\:\/\/data.deichman.no\/person\/h28328100`,
},
{
Input: "Anne + Jørgen = sant",
Expect: `Anne \+ Jørgen \= sant`,
},
{
Input: "*ace/off",
Expect: `*ace\/off`,
},
{
Input: "Face/of*",
Expect: `Face\/of*`,
},
{
Input: "*ace/of*",
Expect: `*ace\/of*`,
},
{
Input: "Fa*e/off",
Expect: `Fa\*e\/off`,
},
}
for _, c := range cases {
output := EscapeQueryStringQuery(c.Input)
if c.Expect != output {
t.Errorf("\nExpected:\n%v\ngot:\n%v\n", c.Expect, output)
}
}
}
......@@ -7,6 +7,7 @@ import (
"unicode/utf8"
"github.com/olivere/elastic/v7"
"gitlab.deichman.no/digibib/deichman/sibyl/internal/search/common"
)
var fieldReplacer *strings.Replacer
......@@ -348,10 +349,12 @@ func (pq parsedQuery) buildMustAndShouldQueries() (mustQueries, shouldQueries []
if len(pq.fieldTerms) > 0 {
var fields []string
for _, f := range pq.fieldTerms {
if strings.HasSuffix(f.term, "*") || strings.Contains(f.term, " ") {
fields = append(fields, fmt.Sprintf("%s:'%s'", f.field, f.term))
hasLeadingOrTrailingWildcard := strings.HasPrefix(f.term, "*") || strings.HasSuffix(f.term, "*")
escapedTerm := common.EscapeQueryStringQuery(f.term)
if hasLeadingOrTrailingWildcard || strings.Contains(f.term, " ") {
fields = append(fields, fmt.Sprintf("%s:'%s'", f.field, escapedTerm))
} else {
fields = append(fields, fmt.Sprintf("%s:%s", f.field, f.term))
fields = append(fields, fmt.Sprintf("%s:%s", f.field, escapedTerm))
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment