Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ISSUE-100: Automatic Draft Saving, Navigation, better Metadata Dates, Multiple Options for Getty #106

Merged
merged 20 commits into from
Mar 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
e1c1db3
Adding actual saving of drafts on Webform navigation
DiegoPino Jan 27, 2021
6986dd8
Update strawberryFieldharvester.php
DiegoPino Jan 27, 2021
99114a8
Hides Preview Webform driven SBF widget Node forms and deals with VID
DiegoPino Jan 28, 2021
7a5948d
Just updates comments for now
DiegoPino Jan 28, 2021
8079920
Delete the temporary errors private storage for Drafts
DiegoPino Jan 28, 2021
025a0ce
Legacy stuff. We NEVER had an error so we never saw this.
DiegoPino Jan 28, 2021
e1c8949
Modal controller of webform now respects vid too
DiegoPino Jan 28, 2021
f8f68af
Push for a now a fixed but better "progress stored" message
DiegoPino Jan 28, 2021
a93c004
And le creme the la creme
DiegoPino Jan 28, 2021
909a0b5
A bit cleaner not enought yet
DiegoPino Jan 28, 2021
893fdaf
I tell people now directly how lazy they can be!
DiegoPino Jan 28, 2021
1f70639
Getty with options.
DiegoPino Jan 29, 2021
04867f1
Clean and simplify? (mmm) Metadata Date element
DiegoPino Feb 2, 2021
647d201
Change TO date to End Date
DiegoPino Feb 2, 2021
5596ff0
Tiny cosmetic changes
DiegoPino Feb 5, 2021
9920902
Use our entity constants to map anything supported and not only "node"
DiegoPino Feb 5, 2021
9b8ed39
Use WebformElementEntityReferenceInterface ::getTargetType
DiegoPino Feb 6, 2021
dac472d
Check if element #multiple key exists before decide on metadata date …
DiegoPino Feb 11, 2021
267ddec
ISSUE-100 --- fix bug in \WebformMetadataDate::preSave that caused si…
patdunlavey Feb 22, 2021
788c070
Merge pull request #103 from Born-Digital-US/ISSUE-100
DiegoPino Feb 23, 2021
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
8 changes: 7 additions & 1 deletion config/schema/webform_strawberryfield.schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,18 @@ field.widget.settings.strawberryfield_webform_inline_widget:
webform_id:
type: string
label: 'Webform ID'
render_always:
type: boolean
label: 'Always render inline'
hide_cancel:
type: boolean
label: 'Do not show the Cancel button once inline'
rows:
type: integer
label: 'Rows'
field.widget.settings.strawberryfield_webform_widget:
type: config_object
label: 'Webform Inline Widget Schema'
label: 'Webform Widget Schema'
mapping:
placeholder:
type: string
Expand Down
219 changes: 137 additions & 82 deletions src/Controller/AuthAutocompleteController.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,16 @@ public function handleAutocomplete(Request $request, $auth_type, $vocab = 'subje
$results = $this->wikidata($input);
break;
case 'aat':
$results = $this->getty($input, 'aat', $vocab);
// @TODO this will be deprecated in 1.1. legacy so old access can be kept
$results = $this->getty($input, 'aat', $rdftype);
break;
case 'getty':
$results = $this->getty($input, $vocab, $rdftype);
break;
case 'viaf':
$results = $this->viaf($input);
break;
}


}

return new JsonResponse($results);
Expand All @@ -137,7 +139,7 @@ public function handleAutocomplete(Request $request, $auth_type, $vocab = 'subje
* @return array
*/
protected function loc($input, $vocab, $rdftype) {
//@TODO make the following whitelist a constant since we use it in
//@TODO make the following allowed list a constant since we use it in
// \Drupal\webform_strawberryfield\Plugin\WebformElement\WebformLoC
if (!in_array($vocab, [
'relators',
Expand All @@ -150,7 +152,7 @@ protected function loc($input, $vocab, $rdftype) {
])) {
// Drop before tryin to hit non existing vocab
$this->messenger()->addError(
$this->t('@vocab for LoC autocomplete is not in in our whitelist.',
$this->t('@vocab for LoC autocomplete is not in in our allowed list.',
[
'@vocab' => $vocab,
]
Expand Down Expand Up @@ -264,7 +266,7 @@ protected function wikidata($input) {
}
return $results;
}
$this->messenger->addError(
$this->messenger()->addError(
$this->t('Looks like data fetched from @url is not in JSON format.<br> JSON says: @jsonerror <br>Please check your URL!',
[
'@url' => $remoteUrl,
Expand All @@ -281,52 +283,49 @@ protected function wikidata($input) {
* @param string $vocab
*
* @param string $mode
* Can be either 'subjects' for fuzzy or exact for 1:1 preflabel
*
* Can be either 'fuzzy' or 'subjects', exact for 1:1 preflalbe or combined
* subjects will be deprecated in 1.1
* @return array
*/
protected function getty($input, $vocab = 'aat', $mode = 'subjects') {
protected function getty($input, $vocab = 'aat', $mode = 'fuzzy') {

if (!in_array($mode, [
'subjects',
'exact',
])) {
// Drop before tryin to hit non existing vocab
if (!in_array($mode, ['fuzzy', 'subjects', 'exact', 'terms'])) {
// Drop before trying to hit non existing vocab
$this->messenger()->addError(
$this->t('@mode mode for aat autocomplete is not in in our whitelist.',
$this->t('@mode mode for @vocab Getty autocomplete is not in in our allowed list.',
[
'@mode' => $mode,
'@vocab' => $vocab,
]
)
);
$results[] = [
'value' => NULL,
'label' => "Wrong Query Mode {$mode} in AAT Query",
'label' => "Wrong Query Mode {$mode} in Getty {$vocab} Query",
'desc' => NULL,
];
return $results;
}


// Split in pieces

// Limit the size here: max 64 chars.
$input = trim($input);
$queries = [];
$results = [];
// Limit the size here: max 64 chars.
if (strlen($input) > 64) {
return $results[] = [
'value' => NULL,
'label' => "Sorry query is too long! Try with less characters",
'desc' => NULL,
];

}
//split in pieces
$input_parts = explode(' ', $input);
$clean_input = array_diff($input_parts, $this::STOPWORDS_EN);
if (!empty($clean_input)) {

// @see http://vocab.getty.edu/queries#Case-insensitive_Full_Text_Search_Query
// Build the SPARQL query
if ($mode == "subjects") {
if (in_array($mode, ["subjects","fuzzy"])) {
$toremove = ['-', '.', '(', ')', '|' . '+', '$', '#', '@', '*'];
$search = str_replace($toremove, ' ', $clean_input);
$search = array_map('trim', $search);
Expand All @@ -336,52 +335,101 @@ protected function getty($input, $vocab = 'aat', $mode = 'subjects') {
return strtolower($value) . '*';
}, $search);
$search = implode(' AND ', $search);
$query = <<<SPARQL
// Note to myself: removing order by asc(lcase(str(?T)))
$query_fuzzy = <<<SPARQL
SELECT ?S ?T ?P ?Note {
?S a skos:Concept; luc:text !searchterm; skos:inScheme <http://vocab.getty.edu/!vocab/> ;
gvp:prefLabelGVP [xl:literalForm ?T].
optional {?S gvp:parentStringAbbrev ?P}
optional {?S skos:scopeNote [dct:language gvp_lang:en; rdf:value ?Note]}
} order by asc(lcase(str(?T)))
LIMIT 10
}
LIMIT !number
SPARQL;


$search = '"' . $search . '"';
$query_fuzzy = preg_replace('!\s+!', ' ', $query_fuzzy);
// use Drupal\Component\Render\FormattableMarkup; has no pass through option
// Anymore, so use native PHP.
// If we have more than one word we will use extra single quote to make
// a closer to exact match.
$queries[] = strtr(trim($query_fuzzy), [
'!searchterm' => $search,
'!vocab' => $vocab,
'!number' => 10
]);
}
else {
$search = array_map('trim', $clean_input);
$search = strtolower(implode(' ', $search));
$original_search = $search;
$query = <<<SPARQL
elseif ($mode == "exact") {
$search_exact = array_map('trim', $clean_input);
$search_exact = strtolower(implode(' ', $search_exact));
$original_search = $search_exact;
$query_exact = <<<SPARQL
select distinct ?S ?T ?P ?Note {
?S skos:inScheme <http://vocab.getty.edu/!vocab/> ;
gvp:prefLabelGVP/xl:literalForm !searchterm@en .
optional {?S gvp:parentStringAbbrev ?P}
optional {?S skos:scopeNote [dct:language gvp_lang:en; rdf:value ?Note]}
}
LIMIT 1
LIMIT !number
SPARQL;
$search_exact = '"' . $search_exact . '"';
$query_exact = preg_replace('!\s+!', ' ', $query_exact);
$queries[] = strtr(trim($query_exact), [
'!searchterm' => $search_exact,
'!vocab' => $vocab,
'!number' => 1
]);
}
$search = '"' . $search . '"';
$query = preg_replace('!\s+!', ' ', $query);
// use Drupal\Component\Render\FormattableMarkup; has no pass through option
// Anymore, so use native PHP.
// If we have more than one word we will use extra single quote to make
// a closer to exact match.
// @TODO ask if people want always fuzzy?
elseif ($mode == "terms") {
$toremove = ['-', '.', '(', ')', '|' . '+', '$', '#', '@', '*'];
$search_terms = str_replace($toremove, ' ', $clean_input);
$search_terms = array_map('trim', $search_terms);
$search_terms = array_filter($search_terms);
if (count($search_terms) > 0) {
$search_terms = strtolower(implode('* ', $search_terms));
$search_terms = $search_terms.'*'; //adds an extra * for the last term
}
$original_search = $search_terms;
$query_terms = <<<SPARQL
select distinct ?S ?T ?P ?Note {
?S a gvp:Concept; luc:term !searchterm; skos:inScheme <http://vocab.getty.edu/!vocab/>.
?S gvp:prefLabelGVP [xl:literalForm ?T]
optional {?S gvp:parentStringAbbrev ?P}
optional {?S skos:scopeNote [dct:language gvp_lang:en; rdf:value ?Note]}
}
LIMIT !number
SPARQL;

/*
* ?S a gvp:Concept; luc:term "actors* (performing artists)*"; skos:inScheme aat:.
?S gvp:prefLabelGVP [xl:literalForm ?T]
optional {?S gvp:parentStringAbbrev ?P}
optional {?S skos:scopeNote [dct:language gvp_lang:en; rdf:value ?Note]}
*
*/
$search_terms = '"' . $search_terms . '"';
$query_terms= preg_replace('!\s+!', ' ', $query_terms);
// use Drupal\Component\Render\FormattableMarkup; has no pass through option
// Anymore, so use native PHP.
// If we have more than one word we will use extra single quote to make
// a closer to exact match.
$queries[] = strtr(trim($query_terms), [
'!searchterm' => $search_terms,
'!vocab' => $vocab,
'!number' => 10
]);
}

$query = strtr(trim($query), [
'!searchterm' => $search,
'!vocab' => $vocab,
]);

$bodies = [];
$baseurl = 'http://vocab.getty.edu/sparql.json';
$options = ['query' => ['query' => $query]];
$url = Url::fromUri($baseurl, $options);
$remoteUrl = $url->toString() . '&_implicit=false&implicit=true&_equivalent=false&_form=%2Fsparql';
$options['headers'] = ['Accept' => 'application/sparql-results+json'];
$body = $this->getRemoteJsonData($remoteUrl, $options);
// I leave this as an array in case we want to combine modes in the future.
foreach($queries as $query) {
error_log($query);
$options = ['query' => ['query' => $query]];
$url = Url::fromUri($baseurl, $options);
$remoteUrl = $url->toString() . '&_implicit=false&implicit=true&_equivalent=false&_form=%2Fsparql';
$options['headers'] = ['Accept' => 'application/sparql-results+json'];
$bodies[] = $this->getRemoteJsonData($remoteUrl, $options);
}
// This is how a result here looks like
/*
"results" : {
Expand All @@ -408,44 +456,51 @@ protected function getty($input, $vocab = 'aat', $mode = 'subjects') {
*/


$results = [];
$jsondata = json_decode($body, TRUE);
$json_error = json_last_error();
if ($json_error == JSON_ERROR_NONE) {
if (isset($jsondata['results']) && count($jsondata['results']['bindings']) > 0) {
foreach ($jsondata['results']['bindings'] as $key => $item) {
// We reapply original search because i had no luck with SPARQL binding the search for exact
// So we have no T
$term = isset($item['T']['value']) ? $item['T']['value'] : $original_search;
$parent = isset($item['P']['value']) ? ' | Parent of: ' . $item['P']['value'] : '';
$note = isset($item['Note']['value']) ? ' | (' . $item['Note']['value'] . ')' : '';
$uri = isset($item['S']['value']) ? $item['S']['value'] : '';
$results[] = [
'value' => $uri,
'label' => $term . $parent . $note,
'desc' => $parent . $note,
];

$jsonfail = FALSE;
foreach($bodies as $body) {
$jsondata = json_decode($body, TRUE);
$json_error = json_last_error();
if ($json_error == JSON_ERROR_NONE) {
if (isset($jsondata['results']) && count($jsondata['results']['bindings']) > 0) {
foreach ($jsondata['results']['bindings'] as $key => $item) {
// We reapply original search because i had no luck with SPARQL binding the search for exact
// So we have no T
$term = isset($item['T']['value']) ? $item['T']['value'] : $original_search;
$parent = isset($item['P']['value']) ? ' | Parent of: ' . $item['P']['value'] : '';
$note = isset($item['Note']['value']) ? ' | (' . $item['Note']['value'] . ')' : '';
$uri = isset($item['S']['value']) ? $item['S']['value'] : '';
$results[] = [
'value' => $uri,
'label' => $term . $parent . $note,
'desc' => $parent . $note,
];
}
}
}
else {
$results[] = [
'value' => NULL,
'label' => 'Sorry no Match from Getty ' . $vocab . ' Vocabulary',
'desc' => NULL,
];
$jsonfail = TRUE;
}
return $results;
}
$this->messenger->addError(
$this->t('Looks like data fetched from @url is not in JSON format.<br> JSON says: @jsonerror <br>Please check your URL!',
[
'@url' => $remoteUrl,
'@jsonerror' => $json_error,
]
)
);
return [];
if (empty($results)) {
$results[] = [
'value' => NULL,
'label' => 'Sorry no Match from Getty ' . $vocab . ' Vocabulary',
'desc' => NULL,
];
}
if ($jsonfail) {
$this->messenger()->addError(
$this->t('Looks like data fetched from @url is not in JSON format.<br> JSON says: @jsonerror <br>Please check your URL!',
[
'@url' => $remoteUrl,
'@jsonerror' => $json_error,
]
)
);
}
}
return $results;
}

/**
Expand Down Expand Up @@ -489,7 +544,7 @@ protected function viaf($input) {
}
return $results;
}
$this->messenger->addError(
$this->messenger()->addError(
$this->t('Looks like data fetched from @url is not in JSON format.<br> JSON says: @jsonerror <br>Please check your URL!',
[
'@url' => $remoteUrl,
Expand Down
Loading