From c64b7bfba7a6f4744a4550b04644b316d4a60efe Mon Sep 17 00:00:00 2001 From: Glenruben Larsen Date: Tue, 13 Feb 2024 14:32:10 +0100 Subject: [PATCH 1/9] Add search, config, service and part --- src/main/resources/index.d.ts | 130 +++++++++--------- .../services/googleSearch/googleSearch.ts | 27 ++++ .../services/googleSearch/googleSearch.xml | 5 + .../searchExperiment/searchExperiment.jsx | 90 ++++++++++++ .../searchExperiment/searchExperiment.ts | 24 ++++ .../searchExperiment/searchExperiment.xml | 4 + src/main/resources/site/site.xml | 8 ++ 7 files changed, 223 insertions(+), 65 deletions(-) create mode 100644 src/main/resources/services/googleSearch/googleSearch.ts create mode 100644 src/main/resources/services/googleSearch/googleSearch.xml create mode 100644 src/main/resources/site/parts/searchExperiment/searchExperiment.jsx create mode 100644 src/main/resources/site/parts/searchExperiment/searchExperiment.ts create mode 100644 src/main/resources/site/parts/searchExperiment/searchExperiment.xml diff --git a/src/main/resources/index.d.ts b/src/main/resources/index.d.ts index 52d454eec..7a91290b5 100644 --- a/src/main/resources/index.d.ts +++ b/src/main/resources/index.d.ts @@ -6,70 +6,71 @@ declare global { namespace XP { namespace PartComponent { export type Accordion = _PartComponent<'mimir:accordion'> - export type ActiveStatistics = _PartComponent<"mimir:activeStatistics"> - export type Article = _PartComponent<"mimir:article"> - export type ArticleArchive = _PartComponent<"mimir:articleArchive"> - export type ArticleList = _PartComponent<"mimir:articleList"> - export type AttachmentTablesFigures = _PartComponent<"mimir:attachmentTablesFigures"> - export type Banner = _PartComponent<"mimir:banner"> - export type BkibolCalculator = _PartComponent<"mimir:bkibolCalculator"> - export type CategoryLinks = _PartComponent<"mimir:categoryLinks"> - export type Contact = _PartComponent<"mimir:contact"> - export type ContactForm = _PartComponent<"mimir:contactForm"> - export type Divider = _PartComponent<"mimir:divider"> - export type DownloadLink = _PartComponent<"mimir:downloadLink"> - export type Employee = _PartComponent<"mimir:employee"> - export type EmployeeList = _PartComponent<"mimir:employeeList"> - export type EndedStatistics = _PartComponent<"mimir:endedStatistics"> - export type EntryLinks = _PartComponent<"mimir:entryLinks"> - export type ExternalCard = _PartComponent<"mimir:externalCard"> - export type FactBox = _PartComponent<"mimir:factBox"> - export type FrontPageBanner = _PartComponent<"mimir:frontPageBanner"> - export type FrontpageKeyfigures = _PartComponent<"mimir:frontpageKeyfigures"> - export type Highchart = _PartComponent<"mimir:highchart"> - export type HighchartExpert = _PartComponent<"mimir:highchartExpert"> - export type Highmap = _PartComponent<"mimir:highmap"> - export type HusleieCalculator = _PartComponent<"mimir:husleieCalculator"> - export type InfoGraphics = _PartComponent<"mimir:infoGraphics"> - export type KeyFigure = _PartComponent<"mimir:keyFigure"> - export type KpiCalculator = _PartComponent<"mimir:kpiCalculator"> - export type Links = _PartComponent<"mimir:links"> - export type LocalSearch = _PartComponent<"mimir:localSearch"> - export type MailChimpForm = _PartComponent<"mimir:mailChimpForm"> - export type Map = _PartComponent<"mimir:map"> - export type Maths = _PartComponent<"mimir:maths"> - export type MenuBox = _PartComponent<"mimir:menuBox"> - export type MenuDropdown = _PartComponent<"mimir:menuDropdown"> - export type NameSearch = _PartComponent<"mimir:nameSearch"> - export type OmStatistikken = _PartComponent<"mimir:omStatistikken"> - export type PictureCardLinks = _PartComponent<"mimir:pictureCardLinks"> - export type PifCalculator = _PartComponent<"mimir:pifCalculator"> - export type ProfiledBox = _PartComponent<"mimir:profiledBox"> - export type ProfiledLinkIcon = _PartComponent<"mimir:profiledLinkIcon"> - export type Project = _PartComponent<"mimir:project"> - export type PubArchiveCalendarLinks = _PartComponent<"mimir:pubArchiveCalendarLinks"> - export type PublicationArchive = _PartComponent<"mimir:publicationArchive"> - export type RelatedArticles = _PartComponent<"mimir:relatedArticles"> - export type RelatedExternalLinks = _PartComponent<"mimir:relatedExternalLinks"> - export type RelatedFactPage = _PartComponent<"mimir:relatedFactPage"> - export type RelatedKostra = _PartComponent<"mimir:relatedKostra"> - export type RelatedStatistics = _PartComponent<"mimir:relatedStatistics"> - export type ReleasedStatistics = _PartComponent<"mimir:releasedStatistics"> - export type RichText = _PartComponent<"mimir:richText"> - export type SearchResult = _PartComponent<"mimir:searchResult"> - export type SimpleStatbank = _PartComponent<"mimir:simpleStatbank"> - export type StandardCardsList = _PartComponent<"mimir:standardCardsList"> - export type StatbankBox = _PartComponent<"mimir:statbankBox"> - export type StatbankFrame = _PartComponent<"mimir:statbankFrame"> - export type StatbankLinkList = _PartComponent<"mimir:statbankLinkList"> - export type StatbankSubjectTree = _PartComponent<"mimir:statbankSubjectTree"> - export type StaticVisualization = _PartComponent<"mimir:staticVisualization"> - export type Statistics = _PartComponent<"mimir:statistics"> - export type SubjectArticleList = _PartComponent<"mimir:subjectArticleList"> - export type Table = _PartComponent<"mimir:table"> - export type UpcomingReleases = _PartComponent<"mimir:upcomingReleases"> - export type Variables = _PartComponent<"mimir:variables"> - export type VideoEmbed = _PartComponent<"mimir:videoEmbed"> + export type ActiveStatistics = _PartComponent<'mimir:activeStatistics'> + export type Article = _PartComponent<'mimir:article'> + export type ArticleArchive = _PartComponent<'mimir:articleArchive'> + export type ArticleList = _PartComponent<'mimir:articleList'> + export type AttachmentTablesFigures = _PartComponent<'mimir:attachmentTablesFigures'> + export type Banner = _PartComponent<'mimir:banner'> + export type BkibolCalculator = _PartComponent<'mimir:bkibolCalculator'> + export type CategoryLinks = _PartComponent<'mimir:categoryLinks'> + export type Contact = _PartComponent<'mimir:contact'> + export type ContactForm = _PartComponent<'mimir:contactForm'> + export type Divider = _PartComponent<'mimir:divider'> + export type DownloadLink = _PartComponent<'mimir:downloadLink'> + export type Employee = _PartComponent<'mimir:employee'> + export type EmployeeList = _PartComponent<'mimir:employeeList'> + export type EndedStatistics = _PartComponent<'mimir:endedStatistics'> + export type EntryLinks = _PartComponent<'mimir:entryLinks'> + export type ExternalCard = _PartComponent<'mimir:externalCard'> + export type FactBox = _PartComponent<'mimir:factBox'> + export type FrontPageBanner = _PartComponent<'mimir:frontPageBanner'> + export type FrontpageKeyfigures = _PartComponent<'mimir:frontpageKeyfigures'> + export type Highchart = _PartComponent<'mimir:highchart'> + export type HighchartExpert = _PartComponent<'mimir:highchartExpert'> + export type Highmap = _PartComponent<'mimir:highmap'> + export type HusleieCalculator = _PartComponent<'mimir:husleieCalculator'> + export type InfoGraphics = _PartComponent<'mimir:infoGraphics'> + export type KeyFigure = _PartComponent<'mimir:keyFigure'> + export type KpiCalculator = _PartComponent<'mimir:kpiCalculator'> + export type Links = _PartComponent<'mimir:links'> + export type LocalSearch = _PartComponent<'mimir:localSearch'> + export type MailChimpForm = _PartComponent<'mimir:mailChimpForm'> + export type Map = _PartComponent<'mimir:map'> + export type Maths = _PartComponent<'mimir:maths'> + export type MenuBox = _PartComponent<'mimir:menuBox'> + export type MenuDropdown = _PartComponent<'mimir:menuDropdown'> + export type NameSearch = _PartComponent<'mimir:nameSearch'> + export type OmStatistikken = _PartComponent<'mimir:omStatistikken'> + export type PictureCardLinks = _PartComponent<'mimir:pictureCardLinks'> + export type PifCalculator = _PartComponent<'mimir:pifCalculator'> + export type ProfiledBox = _PartComponent<'mimir:profiledBox'> + export type ProfiledLinkIcon = _PartComponent<'mimir:profiledLinkIcon'> + export type Project = _PartComponent<'mimir:project'> + export type PubArchiveCalendarLinks = _PartComponent<'mimir:pubArchiveCalendarLinks'> + export type PublicationArchive = _PartComponent<'mimir:publicationArchive'> + export type RelatedArticles = _PartComponent<'mimir:relatedArticles'> + export type RelatedExternalLinks = _PartComponent<'mimir:relatedExternalLinks'> + export type RelatedFactPage = _PartComponent<'mimir:relatedFactPage'> + export type RelatedKostra = _PartComponent<'mimir:relatedKostra'> + export type RelatedStatistics = _PartComponent<'mimir:relatedStatistics'> + export type ReleasedStatistics = _PartComponent<'mimir:releasedStatistics'> + export type RichText = _PartComponent<'mimir:richText'> + export type SearchExperiment = _PartComponent<'mimir:searchExperiment'> + export type SearchResult = _PartComponent<'mimir:searchResult'> + export type SimpleStatbank = _PartComponent<'mimir:simpleStatbank'> + export type StandardCardsList = _PartComponent<'mimir:standardCardsList'> + export type StatbankBox = _PartComponent<'mimir:statbankBox'> + export type StatbankFrame = _PartComponent<'mimir:statbankFrame'> + export type StatbankLinkList = _PartComponent<'mimir:statbankLinkList'> + export type StatbankSubjectTree = _PartComponent<'mimir:statbankSubjectTree'> + export type StaticVisualization = _PartComponent<'mimir:staticVisualization'> + export type Statistics = _PartComponent<'mimir:statistics'> + export type SubjectArticleList = _PartComponent<'mimir:subjectArticleList'> + export type Table = _PartComponent<'mimir:table'> + export type UpcomingReleases = _PartComponent<'mimir:upcomingReleases'> + export type Variables = _PartComponent<'mimir:variables'> + export type VideoEmbed = _PartComponent<'mimir:videoEmbed'> } namespace LayoutComponent { @@ -79,4 +80,3 @@ declare global { } } } - diff --git a/src/main/resources/services/googleSearch/googleSearch.ts b/src/main/resources/services/googleSearch/googleSearch.ts new file mode 100644 index 000000000..0e2577d6d --- /dev/null +++ b/src/main/resources/services/googleSearch/googleSearch.ts @@ -0,0 +1,27 @@ +import { getSiteConfig } from '/lib/xp/portal' +import { request, HttpRequestParams, HttpResponse } from '/lib/http-client' + +export function get(req: XP.Request): XP.Response { + const siteConfig: XP.SiteConfig = getSiteConfig()! + + const requestParams: HttpRequestParams = { + url: `https://www.googleapis.com/customsearch/v1`, + method: 'get', + contentType: 'application/json', + connectionTimeout: 60000, + readTimeout: 10000, + params: { + key: siteConfig.googleSearchApiKey, + cx: siteConfig.googleSearchEngineId, + q: req.params.q, + }, + } + + const result: HttpResponse = request(requestParams) + + return { + body: result.body, + contentType: 'application/json', + status: 200, + } +} diff --git a/src/main/resources/services/googleSearch/googleSearch.xml b/src/main/resources/services/googleSearch/googleSearch.xml new file mode 100644 index 000000000..d18703052 --- /dev/null +++ b/src/main/resources/services/googleSearch/googleSearch.xml @@ -0,0 +1,5 @@ + + + role:system.everyone + + diff --git a/src/main/resources/site/parts/searchExperiment/searchExperiment.jsx b/src/main/resources/site/parts/searchExperiment/searchExperiment.jsx new file mode 100644 index 000000000..38dce5123 --- /dev/null +++ b/src/main/resources/site/parts/searchExperiment/searchExperiment.jsx @@ -0,0 +1,90 @@ +import React, { useState } from 'react' +import { Divider, Title } from '@statisticsnorway/ssb-component-library' +import PropTypes from 'prop-types' +import axios from 'axios' +import { Col, Container, Row } from 'react-bootstrap' + +function SearchExperiment(props) { + const [loading, setLoading] = useState(false) + const [searchResults, setSearchResults] = useState(null) + const [query, setQuery] = useState(props.query || '') + + function fetchSearchResult() { + if (!query) { + // don't search if query is empty, + return + } + setLoading(true) + axios + .get(props.searchUrl, { + params: { + start: 0, + q: query, + }, + }) + .then((res) => { + setSearchResults(res.data) + }) + .catch((err) => console.log(err)) + .finally(() => setLoading(false)) + } + + function showSearchResults() { + if (loading) { + return

Loading...

+ } + if (searchResults) { + return searchResults.items.map((item) => ( +
  • + + + + {item.title} +

    {item.snippet}

    +
    +
    +
  • + )) + } + return

    No search results

    + } + + function handleKeyDown(event) { + if (event.key === 'Enter') { + fetchSearchResult() + } + } + + return ( +
    + Søk med Google! +
    + + + + setQuery(e.target.value)} + onKeyDown={(e) => handleKeyDown(e)} + style={{ width: '100%' }} + /> + + + + + + +
      {showSearchResults()}
    +
    +
    + ) +} + +SearchExperiment.propTypes = { + searchUrl: PropTypes.string, + query: PropTypes.string, +} + +export default (props) => diff --git a/src/main/resources/site/parts/searchExperiment/searchExperiment.ts b/src/main/resources/site/parts/searchExperiment/searchExperiment.ts new file mode 100644 index 000000000..f93e133a7 --- /dev/null +++ b/src/main/resources/site/parts/searchExperiment/searchExperiment.ts @@ -0,0 +1,24 @@ +import { serviceUrl } from '/lib/xp/portal' +import { render } from '/lib/enonic/react4xp' + +export function get(req: XP.Request): XP.Response { + return renderPart(req) +} + +export function preview(req: XP.Request): XP.Response { + return renderPart(req) +} + +function renderPart(req: XP.Request): XP.Response { + const result = render( + 'site/parts/searchExperiment/searchExperiment', + { + searchUrl: serviceUrl({ + service: 'googleSearch', + }), + query: req.params.q, + }, + req + ) + return result +} diff --git a/src/main/resources/site/parts/searchExperiment/searchExperiment.xml b/src/main/resources/site/parts/searchExperiment/searchExperiment.xml new file mode 100644 index 000000000..d758111a7 --- /dev/null +++ b/src/main/resources/site/parts/searchExperiment/searchExperiment.xml @@ -0,0 +1,4 @@ + + Søk med Google + Eksperimentell Google-søk på vår side + diff --git a/src/main/resources/site/site.xml b/src/main/resources/site/site.xml index 8bec992b4..2131221f3 100644 --- a/src/main/resources/site/site.xml +++ b/src/main/resources/site/site.xml @@ -61,6 +61,14 @@ /informasjon/om-statistikkbanken/hvordan-bruke-statistikkbanken + + + + + + + + false From e2a7b766b0217d81bce98ddc1beeb61a5a1478a8 Mon Sep 17 00:00:00 2001 From: Glenruben Larsen Date: Tue, 13 Feb 2024 15:50:09 +0100 Subject: [PATCH 2/9] Add sorting, use OG title without -SSB --- .../services/googleSearch/googleSearch.ts | 3 +++ .../searchExperiment/searchExperiment.jsx | 27 ++++++++++++++++--- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/main/resources/services/googleSearch/googleSearch.ts b/src/main/resources/services/googleSearch/googleSearch.ts index 0e2577d6d..0e0dbe536 100644 --- a/src/main/resources/services/googleSearch/googleSearch.ts +++ b/src/main/resources/services/googleSearch/googleSearch.ts @@ -4,6 +4,8 @@ import { request, HttpRequestParams, HttpResponse } from '/lib/http-client' export function get(req: XP.Request): XP.Response { const siteConfig: XP.SiteConfig = getSiteConfig()! + const sortString: 'date' | 'relevance' = req.params.sort === 'date' ? 'date' : 'relevance' + const requestParams: HttpRequestParams = { url: `https://www.googleapis.com/customsearch/v1`, method: 'get', @@ -14,6 +16,7 @@ export function get(req: XP.Request): XP.Response { key: siteConfig.googleSearchApiKey, cx: siteConfig.googleSearchEngineId, q: req.params.q, + sort: sortString === 'relevance' ? '' : sortString, }, } diff --git a/src/main/resources/site/parts/searchExperiment/searchExperiment.jsx b/src/main/resources/site/parts/searchExperiment/searchExperiment.jsx index 38dce5123..a4b252a11 100644 --- a/src/main/resources/site/parts/searchExperiment/searchExperiment.jsx +++ b/src/main/resources/site/parts/searchExperiment/searchExperiment.jsx @@ -8,6 +8,7 @@ function SearchExperiment(props) { const [loading, setLoading] = useState(false) const [searchResults, setSearchResults] = useState(null) const [query, setQuery] = useState(props.query || '') + const [sort, setSort] = useState('relevance') function fetchSearchResult() { if (!query) { @@ -20,6 +21,7 @@ function SearchExperiment(props) { params: { start: 0, q: query, + sort: sort, }, }) .then((res) => { @@ -33,13 +35,13 @@ function SearchExperiment(props) { if (loading) { return

    Loading...

    } - if (searchResults) { + if (searchResults && searchResults.items && searchResults.items.length > 0) { return searchResults.items.map((item) => (
  • - {item.title} + {item.pagemap?.metatags[0]['og:title'] || item.title}

    {item.snippet}

    @@ -55,12 +57,16 @@ function SearchExperiment(props) { } } + function handleRadioChange(event) { + setSort(event.target.value) + } + return (
    Søk med Google!
    - + Search + + + +
      {showSearchResults()}
    From fbe5356f51634c12fabcd0af9dc0754ae101b3ca Mon Sep 17 00:00:00 2001 From: Glenruben Larsen Date: Tue, 13 Feb 2024 15:59:22 +0100 Subject: [PATCH 3/9] Add embedded search in part --- .../resources/site/parts/searchEmbed/searchEmbed.html | 5 +++++ .../resources/site/parts/searchEmbed/searchEmbed.ts | 11 +++++++++++ .../resources/site/parts/searchEmbed/searchEmbed.xml | 4 ++++ 3 files changed, 20 insertions(+) create mode 100644 src/main/resources/site/parts/searchEmbed/searchEmbed.html create mode 100644 src/main/resources/site/parts/searchEmbed/searchEmbed.ts create mode 100644 src/main/resources/site/parts/searchEmbed/searchEmbed.xml diff --git a/src/main/resources/site/parts/searchEmbed/searchEmbed.html b/src/main/resources/site/parts/searchEmbed/searchEmbed.html new file mode 100644 index 000000000..a896ecee8 --- /dev/null +++ b/src/main/resources/site/parts/searchEmbed/searchEmbed.html @@ -0,0 +1,5 @@ +
    + + +
    \ No newline at end of file diff --git a/src/main/resources/site/parts/searchEmbed/searchEmbed.ts b/src/main/resources/site/parts/searchEmbed/searchEmbed.ts new file mode 100644 index 000000000..4cecca614 --- /dev/null +++ b/src/main/resources/site/parts/searchEmbed/searchEmbed.ts @@ -0,0 +1,11 @@ +import { render } from '/lib/thymeleaf' + +export function get(req: XP.Request): XP.Response { + const view = resolve('searchEmbed.html') + const model = { + test: 'test', + req: req, + } + const body = render(view, model) + return { body } +} diff --git a/src/main/resources/site/parts/searchEmbed/searchEmbed.xml b/src/main/resources/site/parts/searchEmbed/searchEmbed.xml new file mode 100644 index 000000000..8bbc91cd4 --- /dev/null +++ b/src/main/resources/site/parts/searchEmbed/searchEmbed.xml @@ -0,0 +1,4 @@ + + Søk med Embedded Google-søk + Eksperimentell Google-søk med branding + From b0bb10cdf701207b6fa6df376eb5fd85314b1b71 Mon Sep 17 00:00:00 2001 From: Glenruben Larsen Date: Wed, 14 Feb 2024 13:27:00 +0100 Subject: [PATCH 4/9] Add cool experimental Vertex search part --- .../site/parts/searchVertex/searchVertex.html | 9 +++++++++ .../resources/site/parts/searchVertex/searchVertex.ts | 11 +++++++++++ .../site/parts/searchVertex/searchVertex.xml | 4 ++++ 3 files changed, 24 insertions(+) create mode 100644 src/main/resources/site/parts/searchVertex/searchVertex.html create mode 100644 src/main/resources/site/parts/searchVertex/searchVertex.ts create mode 100644 src/main/resources/site/parts/searchVertex/searchVertex.xml diff --git a/src/main/resources/site/parts/searchVertex/searchVertex.html b/src/main/resources/site/parts/searchVertex/searchVertex.html new file mode 100644 index 000000000..d256da58a --- /dev/null +++ b/src/main/resources/site/parts/searchVertex/searchVertex.html @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/site/parts/searchVertex/searchVertex.ts b/src/main/resources/site/parts/searchVertex/searchVertex.ts new file mode 100644 index 000000000..7c6cae18c --- /dev/null +++ b/src/main/resources/site/parts/searchVertex/searchVertex.ts @@ -0,0 +1,11 @@ +import { render } from '/lib/thymeleaf' + +export function get(req: XP.Request): XP.Response { + const view = resolve('searchVertex.html') + const model = { + test: 'test', + req: req, + } + const body = render(view, model) + return { body } +} diff --git a/src/main/resources/site/parts/searchVertex/searchVertex.xml b/src/main/resources/site/parts/searchVertex/searchVertex.xml new file mode 100644 index 000000000..6852ed62b --- /dev/null +++ b/src/main/resources/site/parts/searchVertex/searchVertex.xml @@ -0,0 +1,4 @@ + + Søk med fancy VERTEX Google-søk + Eksperimentelt AI Google-søk med den nye kule tingen + From 77d675a7c91f81a5070f7e84c8858def76b4559e Mon Sep 17 00:00:00 2001 From: Glenruben Larsen Date: Wed, 14 Feb 2024 15:03:17 +0100 Subject: [PATCH 5/9] norwegian language pls --- src/main/resources/site/parts/searchVertex/searchVertex.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/site/parts/searchVertex/searchVertex.html b/src/main/resources/site/parts/searchVertex/searchVertex.html index d256da58a..d8c1a433e 100644 --- a/src/main/resources/site/parts/searchVertex/searchVertex.html +++ b/src/main/resources/site/parts/searchVertex/searchVertex.html @@ -1,5 +1,5 @@ - + From 5f6fa7600c397104f1b2ef24079736567ab3df9b Mon Sep 17 00:00:00 2001 From: Glenruben Larsen Date: Fri, 1 Mar 2024 13:48:01 +0100 Subject: [PATCH 6/9] Add selectable google search to search part --- package-lock.json | 396 +++++++++++++++--- package.json | 1 + src/main/resources/lib/ssb/utils/solrUtils.ts | 61 ++- .../services/googleSearch/googleSearch.ts | 33 +- .../site/parts/searchResult/searchResult.ts | 52 ++- .../site/parts/searchResult/searchResult.xml | 39 +- 6 files changed, 480 insertions(+), 102 deletions(-) diff --git a/package-lock.json b/package-lock.json index de6a133f2..537a78443 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "@googleapis/customsearch": "^1.1.0", "bootstrap": "~5.3.2", "core-js": "~3.35.1", "date-fns": "~2.30.0", @@ -3535,6 +3536,17 @@ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.6.tgz", "integrity": "sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==" }, + "node_modules/@googleapis/customsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@googleapis/customsearch/-/customsearch-1.1.0.tgz", + "integrity": "sha512-puQ9gsr+Wu6A9MrQ379LPDVXCZTs7aubclHyb/pclvIKckbghxVuax/wgOaUoDrB+HASwJmDUSz9BHeaMVvzCg==", + "dependencies": { + "googleapis-common": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.13", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", @@ -6215,6 +6227,17 @@ "node": ">=0.8" } }, + "node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -7823,7 +7846,6 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, "funding": [ { "type": "github", @@ -7872,6 +7894,14 @@ "node": "*" } }, + "node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "engines": { + "node": "*" + } + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -8288,6 +8318,11 @@ "node": "*" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -8346,7 +8381,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", - "dev": true, "dependencies": { "function-bind": "^1.1.2", "get-intrinsic": "^1.2.1", @@ -9295,7 +9329,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -9398,7 +9431,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", - "dev": true, "dependencies": { "get-intrinsic": "^1.2.1", "gopd": "^1.0.1", @@ -9759,6 +9791,14 @@ "node": ">=8" } }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -10754,6 +10794,11 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -11223,6 +11268,43 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gaxios": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.3.0.tgz", + "integrity": "sha512-p+ggrQw3fBwH2F5N/PAI4k/G/y1art5OxKpb2J2chwNNHM4hHuAOtivjPuirMF4KNKwTTUal/lPfL2+7h2mEcg==", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/gaxios/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gcp-metadata": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz", + "integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==", + "dependencies": { + "gaxios": "^6.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -11254,7 +11336,6 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", - "dev": true, "dependencies": { "function-bind": "^1.1.2", "has-proto": "^1.0.1", @@ -11425,11 +11506,42 @@ "node": ">=8" } }, + "node_modules/google-auth-library": { + "version": "9.6.3", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.6.3.tgz", + "integrity": "sha512-4CacM29MLC2eT9Cey5GDVK4Q8t+MMp8+OEdOaqD9MG6b0dOyLORaaeJMPQ7EESVgm/+z5EKYyFLxgzBJlJgyHQ==", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^6.1.1", + "gcp-metadata": "^6.1.0", + "gtoken": "^7.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/googleapis-common": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-7.0.1.tgz", + "integrity": "sha512-mgt5zsd7zj5t5QXvDanjWguMdHAcJmmDrF9RkInCecNsyV7S7YtGqm5v2IWONNID88osb7zmx5FtrAP12JfD0w==", + "dependencies": { + "extend": "^3.0.2", + "gaxios": "^6.0.3", + "google-auth-library": "^9.0.0", + "qs": "^6.7.0", + "url-template": "^2.0.8", + "uuid": "^9.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -11449,6 +11561,18 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, + "node_modules/gtoken": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", + "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", + "dependencies": { + "gaxios": "^6.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/gzip-size": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", @@ -11506,7 +11630,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", - "dev": true, "dependencies": { "get-intrinsic": "^1.2.2" }, @@ -11518,7 +11641,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -11530,7 +11652,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -11651,6 +11772,18 @@ "node": ">=8.0.0" } }, + "node_modules/https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/human-signals": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", @@ -14538,6 +14671,14 @@ "node": ">=4" } }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -14658,6 +14799,25 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -15186,8 +15346,7 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/mz": { "version": "2.7.0", @@ -15249,7 +15408,6 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, "dependencies": { "whatwg-url": "^5.0.0" }, @@ -15590,7 +15748,6 @@ "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -16936,6 +17093,20 @@ "node": ">=4" } }, + "node_modules/qs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", + "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -17878,7 +18049,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, "funding": [ { "type": "github", @@ -18243,7 +18413,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", - "dev": true, "dependencies": { "define-data-property": "^1.1.1", "get-intrinsic": "^1.2.1", @@ -18374,7 +18543,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, "dependencies": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -19297,8 +19465,7 @@ "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/tree-kill": { "version": "1.2.2", @@ -19993,6 +20160,11 @@ "punycode": "^2.1.0" } }, + "node_modules/url-template": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", + "integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw==" + }, "node_modules/use-isomorphic-layout-effect": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", @@ -20113,8 +20285,7 @@ "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/webpack": { "version": "5.89.0", @@ -20346,7 +20517,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -23114,6 +23284,14 @@ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.6.tgz", "integrity": "sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==" }, + "@googleapis/customsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@googleapis/customsearch/-/customsearch-1.1.0.tgz", + "integrity": "sha512-puQ9gsr+Wu6A9MrQ379LPDVXCZTs7aubclHyb/pclvIKckbghxVuax/wgOaUoDrB+HASwJmDUSz9BHeaMVvzCg==", + "requires": { + "googleapis-common": "^7.0.0" + } + }, "@humanwhocodes/config-array": { "version": "0.11.13", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", @@ -25103,6 +25281,14 @@ "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", "dev": true }, + "agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "requires": { + "debug": "^4.3.4" + } + }, "aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -26450,8 +26636,7 @@ "base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, "base64id": { "version": "2.0.0", @@ -26477,6 +26662,11 @@ "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", "dev": true }, + "bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==" + }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -26779,6 +26969,11 @@ "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -26819,7 +27014,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", - "dev": true, "requires": { "function-bind": "^1.1.2", "get-intrinsic": "^1.2.1", @@ -27510,7 +27704,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "requires": { "ms": "2.1.2" } @@ -27580,7 +27773,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", - "dev": true, "requires": { "get-intrinsic": "^1.2.1", "gopd": "^1.0.1", @@ -27837,6 +28029,14 @@ } } }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -28585,6 +28785,11 @@ "jest-util": "^29.7.0" } }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -28937,6 +29142,33 @@ "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true }, + "gaxios": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.3.0.tgz", + "integrity": "sha512-p+ggrQw3fBwH2F5N/PAI4k/G/y1art5OxKpb2J2chwNNHM4hHuAOtivjPuirMF4KNKwTTUal/lPfL2+7h2mEcg==", + "requires": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9" + }, + "dependencies": { + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + } + } + }, + "gcp-metadata": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz", + "integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==", + "requires": { + "gaxios": "^6.0.0", + "json-bigint": "^1.0.0" + } + }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -28959,7 +29191,6 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", - "dev": true, "requires": { "function-bind": "^1.1.2", "has-proto": "^1.0.1", @@ -29080,11 +29311,36 @@ } } }, + "google-auth-library": { + "version": "9.6.3", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.6.3.tgz", + "integrity": "sha512-4CacM29MLC2eT9Cey5GDVK4Q8t+MMp8+OEdOaqD9MG6b0dOyLORaaeJMPQ7EESVgm/+z5EKYyFLxgzBJlJgyHQ==", + "requires": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^6.1.1", + "gcp-metadata": "^6.1.0", + "gtoken": "^7.0.0", + "jws": "^4.0.0" + } + }, + "googleapis-common": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/googleapis-common/-/googleapis-common-7.0.1.tgz", + "integrity": "sha512-mgt5zsd7zj5t5QXvDanjWguMdHAcJmmDrF9RkInCecNsyV7S7YtGqm5v2IWONNID88osb7zmx5FtrAP12JfD0w==", + "requires": { + "extend": "^3.0.2", + "gaxios": "^6.0.3", + "google-auth-library": "^9.0.0", + "qs": "^6.7.0", + "url-template": "^2.0.8", + "uuid": "^9.0.0" + } + }, "gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, "requires": { "get-intrinsic": "^1.1.3" } @@ -29101,6 +29357,15 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, + "gtoken": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", + "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", + "requires": { + "gaxios": "^6.0.0", + "jws": "^4.0.0" + } + }, "gzip-size": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", @@ -29142,7 +29407,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", - "dev": true, "requires": { "get-intrinsic": "^1.2.2" } @@ -29150,14 +29414,12 @@ "has-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" }, "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" }, "has-tostringtag": { "version": "1.0.0", @@ -29253,6 +29515,15 @@ "requires-port": "^1.0.0" } }, + "https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "requires": { + "agent-base": "^7.0.2", + "debug": "4" + } + }, "human-signals": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", @@ -31347,6 +31618,14 @@ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, + "json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "requires": { + "bignumber.js": "^9.0.0" + } + }, "json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -31458,6 +31737,25 @@ } } }, + "jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "requires": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, "keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -31895,8 +32193,7 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "mz": { "version": "2.7.0", @@ -31943,7 +32240,6 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, "requires": { "whatwg-url": "^5.0.0" } @@ -32186,8 +32482,7 @@ "object-inspect": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "dev": true + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==" }, "object-keys": { "version": "1.1.1", @@ -33072,6 +33367,14 @@ "stringify-object": "^3.2.0" } }, + "qs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", + "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "requires": { + "side-channel": "^1.0.4" + } + }, "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -33778,8 +34081,7 @@ "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, "safe-regex-test": { "version": "1.0.0", @@ -34052,7 +34354,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", - "dev": true, "requires": { "define-data-property": "^1.1.1", "get-intrinsic": "^1.2.1", @@ -34155,7 +34456,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, "requires": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -34831,8 +35131,7 @@ "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "tree-kill": { "version": "1.2.2", @@ -35318,6 +35617,11 @@ "punycode": "^2.1.0" } }, + "url-template": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", + "integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw==" + }, "use-isomorphic-layout-effect": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", @@ -35409,8 +35713,7 @@ "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "webpack": { "version": "5.89.0", @@ -35569,7 +35872,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, "requires": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" diff --git a/package.json b/package.json index 2240f0c42..cdf2dab26 100644 --- a/package.json +++ b/package.json @@ -158,6 +158,7 @@ ] }, "dependencies": { + "@googleapis/customsearch": "^1.1.0", "bootstrap": "~5.3.2", "core-js": "~3.35.1", "date-fns": "~2.30.0", diff --git a/src/main/resources/lib/ssb/utils/solrUtils.ts b/src/main/resources/lib/ssb/utils/solrUtils.ts index 401d26034..cdfc6fe7c 100644 --- a/src/main/resources/lib/ssb/utils/solrUtils.ts +++ b/src/main/resources/lib/ssb/utils/solrUtils.ts @@ -1,6 +1,7 @@ -import { sanitizeHtml } from '/lib/xp/portal' +import { customsearch_v1 } from '@googleapis/customsearch' +import { sanitizeHtml, getSiteConfig } from '/lib/xp/portal' import { localize } from '/lib/xp/i18n' -import { request, HttpResponse } from '/lib/http-client' +import { request, HttpResponse, HttpRequestParams } from '/lib/http-client' import { formatDate } from '/lib/ssb/utils/dateUtils' const SOLR_PARAM_QUERY = 'q' @@ -61,6 +62,62 @@ export function solrSearch( } } +export function googleSearch( + term: string, + start?: number, + language?: string, + numberOfHits?: number, + mainSubject?: string, + contentType?: string, + sortParam?: string +): SolrPrepResultAndTotal { + const sortString: string = sortParam === 'date' || sortParam === 'publiseringsdato' ? 'date' : '' + const siteConfig: XP.SiteConfig = getSiteConfig()! + + const requestParams: HttpRequestParams = { + url: `https://www.googleapis.com/customsearch/v1`, + method: 'get', + contentType: 'application/json', + connectionTimeout: 60000, + readTimeout: 10000, + params: { + key: siteConfig.googleSearchApiKey, + cx: siteConfig.googleSearchEngineId, + q: term, + sort: sortString, + start: start || 0, + }, + } + + const search = request(requestParams) + + const results: customsearch_v1.Schema$Search = JSON.parse(search.body!) + const solrFormatResults: Array | undefined = results.items?.map((item) => ({ + contentType: 'artikkel', + id: item.pagemap?.metatags[0].pageid || '1234', + title: item.pagemap?.metatags[0]['og:title'] || 'tittel', + preface: item.htmlSnippet || '', + url: item.link || '', + mainSubject: 'befolkning', + secondaryMainSubject: 'befolkning', + publishDate: '2024-02-28T08:00:00Z', + publishDateHuman: formatDate('2024-02-28T08:00:00Z', 'PPP', 'no'), + })) + return solrFormatResults + ? { + hits: solrFormatResults, + total: Number(results.searchInformation?.totalResults) || 0, + contentTypes: [{ count: 10, title: 'artikkel' }], + subjects: [{ count: 10, title: 'befolkning' }], + } + : { + hits: [], + total: 0, + contentTypes: [], + subjects: [], + } +} + function nerfSearchResult(solrResult: SolrResult, language: string): Array { return solrResult.grouped.gruppering.groups.reduce((acc: Array, group) => { group.doclist.docs.forEach((doc: SolrDoc) => { diff --git a/src/main/resources/services/googleSearch/googleSearch.ts b/src/main/resources/services/googleSearch/googleSearch.ts index 0e0dbe536..8731c8804 100644 --- a/src/main/resources/services/googleSearch/googleSearch.ts +++ b/src/main/resources/services/googleSearch/googleSearch.ts @@ -1,29 +1,18 @@ -import { getSiteConfig } from '/lib/xp/portal' -import { request, HttpRequestParams, HttpResponse } from '/lib/http-client' +import { type SolrPrepResultAndTotal, googleSearch } from '/lib/ssb/utils/solrUtils' export function get(req: XP.Request): XP.Response { - const siteConfig: XP.SiteConfig = getSiteConfig()! - - const sortString: 'date' | 'relevance' = req.params.sort === 'date' ? 'date' : 'relevance' - - const requestParams: HttpRequestParams = { - url: `https://www.googleapis.com/customsearch/v1`, - method: 'get', - contentType: 'application/json', - connectionTimeout: 60000, - readTimeout: 10000, - params: { - key: siteConfig.googleSearchApiKey, - cx: siteConfig.googleSearchEngineId, - q: req.params.q, - sort: sortString === 'relevance' ? '' : sortString, - }, - } - - const result: HttpResponse = request(requestParams) + const results: SolrPrepResultAndTotal = googleSearch( + req.params.sok, + req.params.start || 0, + req.params.language || 'nb', + req.params.count || 15, + req.params.emne || '', + req.params.mainsubject || '', + req.params.sort || 'relevance' + ) return { - body: result.body, + body: results, contentType: 'application/json', status: 200, } diff --git a/src/main/resources/site/parts/searchResult/searchResult.ts b/src/main/resources/site/parts/searchResult/searchResult.ts index bf7438764..33f3313a9 100644 --- a/src/main/resources/site/parts/searchResult/searchResult.ts +++ b/src/main/resources/site/parts/searchResult/searchResult.ts @@ -8,6 +8,7 @@ import { type SolrPrepResultAndTotal, type Facet, solrSearch, + googleSearch, } from '/lib/ssb/utils/solrUtils' import { type SolrResponse, getNameSearchResult } from '/lib/ssb/utils/nameSearchUtils' import { queryNodes, getNode } from '/lib/ssb/repo/common' @@ -218,21 +219,40 @@ export function renderPart(req: XP.Request) { } /* query solr */ - const solrResult: SolrPrepResultAndTotal = sanitizedTerm - ? solrSearch( - sanitizedTerm, - language, - parseInt(part.config.numberOfHits), - 0, - req.params.emne, - req.params.innholdstype - ) - : { - total: 0, - hits: [], - contentTypes: [], - subjects: [], - } + let solrResult: SolrPrepResultAndTotal + if (part.config.searchEngine === 'google') { + solrResult = sanitizedTerm + ? googleSearch( + sanitizedTerm, + 0, + language, + parseInt(part.config.numberOfHits), + req.params.emne, + req.params.innholdstype + ) + : { + total: 0, + hits: [], + contentTypes: [], + subjects: [], + } + } else { + solrResult = sanitizedTerm + ? solrSearch( + sanitizedTerm, + language, + parseInt(part.config.numberOfHits), + 0, + req.params.emne, + req.params.innholdstype + ) + : { + total: 0, + hits: [], + contentTypes: [], + subjects: [], + } + } const totalHits = bestBet() ? solrResult.total + 1 : solrResult.total const showNameSearch = isEnabled('name-search-in-freetext-search') ? true : false @@ -268,7 +288,7 @@ export function renderPart(req: XP.Request) { locale: language, }), searchServiceUrl: serviceUrl({ - service: 'freeTextSearch', + service: part.config.searchEngine === 'google' ? 'googleSearch' : 'freeTextSearch', }), nameSearchUrl: serviceUrl({ service: 'nameSearch', diff --git a/src/main/resources/site/parts/searchResult/searchResult.xml b/src/main/resources/site/parts/searchResult/searchResult.xml index ec6f249c8..1a245c023 100644 --- a/src/main/resources/site/parts/searchResult/searchResult.xml +++ b/src/main/resources/site/parts/searchResult/searchResult.xml @@ -1,17 +1,26 @@ - Søkeresultat -
    - - - - - - - - 15 - - \d - - - + Søkeresultat +
    + + + + + + + + 15 + + \d + + + + + + + + + + solr + +
    From bb8ff932f1959ccf23a9fa470d743317540e3599 Mon Sep 17 00:00:00 2001 From: Glenruben Larsen Date: Tue, 30 Apr 2024 12:55:21 +0200 Subject: [PATCH 7/9] WIP-google-vertex try to get any data --- build.gradle | 10 ++- gradle.properties | 1 + src/main/java/no/ssb/xp/vertex/Search.java | 64 +++++++++++++++++++ .../java/no/ssb/xp/vertex/VertexService.java | 11 ++++ .../resources/lib/types/googleServices.ts | 5 ++ .../services/vertexSearch/vertexSearch.ts | 19 ++++++ .../services/vertexSearch/vertexSearch.xml | 5 ++ .../site/parts/searchResult/searchResult.ts | 3 +- 8 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 src/main/java/no/ssb/xp/vertex/Search.java create mode 100644 src/main/java/no/ssb/xp/vertex/VertexService.java create mode 100644 src/main/resources/lib/types/googleServices.ts create mode 100644 src/main/resources/services/vertexSearch/vertexSearch.ts create mode 100644 src/main/resources/services/vertexSearch/vertexSearch.xml diff --git a/build.gradle b/build.gradle index 182ff5273..56d377916 100644 --- a/build.gradle +++ b/build.gradle @@ -14,6 +14,10 @@ app { systemVersion = "${xpVersion}"} dependencies { + implementation platform('com.google.cloud:libraries-bom:26.37.0') + implementation 'com.google.cloud:google-cloud-discoveryengine' + // https://mvnrepository.com/artifact/com.google.cloud/google-cloud-discoveryengine + // implementation 'com.google.cloud:google-cloud-discoveryengine:0.38.0' include "com.enonic.lib:lib-thymeleaf:2.1.0" implementation "com.enonic.xp:core-api:${xpVersion}" implementation "com.enonic.xp:portal-api:${xpVersion}" @@ -52,9 +56,9 @@ repositories { mavenLocal() mavenCentral() xp.enonicRepo() - maven { - url "https://repo1.maven.org/maven2/" - } + // maven { + // url "https://repo1.maven.org/maven2/" + // } maven { url 'https://jitpack.io' } diff --git a/gradle.properties b/gradle.properties index 02e3e3156..f8b9d057c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,3 +11,4 @@ xpVersion = 7.13.3 # Settings for publishing to a Maven repo group = +enableFeaturePreview('IMPROVED_POM_SUPPORT') diff --git a/src/main/java/no/ssb/xp/vertex/Search.java b/src/main/java/no/ssb/xp/vertex/Search.java new file mode 100644 index 000000000..980903f7d --- /dev/null +++ b/src/main/java/no/ssb/xp/vertex/Search.java @@ -0,0 +1,64 @@ +package no.ssb.xp.vertex; + +import com.google.cloud.discoveryengine.v1.SearchRequest; +import com.google.cloud.discoveryengine.v1.SearchResponse; +import com.google.cloud.discoveryengine.v1.SearchServiceClient; +import com.google.cloud.discoveryengine.v1.SearchServiceSettings; +import com.google.cloud.discoveryengine.v1.ServingConfigName; +import java.io.IOException; +import java.util.concurrent.ExecutionException; + +public class Search { + public void run() throws IOException, ExecutionException { + + System.out.println(); + // TODO(developer): Replace these variables before running the sample. + // Project ID or project number of the Cloud project you want to use. + String projectId = "ssbno-t-lf"; + // Location of the data store. Options: "global", "us", "eu" + String location = "eu"; + // Collection containing the data store. + String collectionId = "ssbno-search-no_1713449390194"; + // Data store ID. + String dataStoreId = "ssbno-no_1713449458710"; + // Serving configuration. Options: "default_search" + String servingConfigId = "default_search"; + // Search Query for the data store. + String searchQuery = "Konsumpris"; + search(projectId, location, collectionId, dataStoreId, servingConfigId, searchQuery); + } + + /** Performs a search on a given datastore. */ + public static void search( + String projectId, + String location, + String collectionId, + String dataStoreId, + String servingConfigId, + String searchQuery) + throws IOException, ExecutionException { + // For more information, refer to: + // https://cloud.google.com/generative-ai-app-builder/docs/locations#specify_a_multi-region_for_your_data_store + String endpoint = "eu-discoveryengine.googleapis.com:443"; + SearchServiceSettings settings = + SearchServiceSettings.newBuilder().setEndpoint(endpoint).build(); + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the `searchServiceClient.close()` method on the client to safely + // clean up any remaining background resources. + try (SearchServiceClient searchServiceClient = SearchServiceClient.create(settings)) { + SearchRequest request = + SearchRequest.newBuilder() + .setServingConfig( + ServingConfigName.formatProjectLocationCollectionDataStoreServingConfigName( + projectId, location, collectionId, dataStoreId, servingConfigId)) + .setQuery(searchQuery) + .setPageSize(10) + .build(); + SearchResponse response = searchServiceClient.search(request).getPage().getResponse(); + for (SearchResponse.SearchResult element : response.getResultsList()) { + System.out.println("Response content: " + element); + } + } + } +} diff --git a/src/main/java/no/ssb/xp/vertex/VertexService.java b/src/main/java/no/ssb/xp/vertex/VertexService.java new file mode 100644 index 000000000..641725f7d --- /dev/null +++ b/src/main/java/no/ssb/xp/vertex/VertexService.java @@ -0,0 +1,11 @@ +package no.ssb.xp.vertex; + +public class VertexService { + public static void main(String[] args) { + System.out.println("Hello, World!"); + } + + public String getVertex() { + return "Vertex is gotten, yes."; + } +} diff --git a/src/main/resources/lib/types/googleServices.ts b/src/main/resources/lib/types/googleServices.ts new file mode 100644 index 000000000..7e1ee6585 --- /dev/null +++ b/src/main/resources/lib/types/googleServices.ts @@ -0,0 +1,5 @@ +export type VertexSearch = { + getVertex(): string +} + +// export type Search = diff --git a/src/main/resources/services/vertexSearch/vertexSearch.ts b/src/main/resources/services/vertexSearch/vertexSearch.ts new file mode 100644 index 000000000..1a84823be --- /dev/null +++ b/src/main/resources/services/vertexSearch/vertexSearch.ts @@ -0,0 +1,19 @@ +import { type VertexSearch } from '/lib/googleServices' + +const vertexSearch: VertexSearch = __.newBean('no.ssb.xp.vertex.VertexService') + +const search = __.newBean('no.ssb.xp.vertex.Search') + +try { + search.run() +} catch (e) { + log.error(e) +} + +export function get(): XP.Response { + return { + body: vertexSearch.getVertex(), + contentType: 'application/json', + status: 200, + } +} diff --git a/src/main/resources/services/vertexSearch/vertexSearch.xml b/src/main/resources/services/vertexSearch/vertexSearch.xml new file mode 100644 index 000000000..d18703052 --- /dev/null +++ b/src/main/resources/services/vertexSearch/vertexSearch.xml @@ -0,0 +1,5 @@ + + + role:system.everyone + + diff --git a/src/main/resources/site/parts/searchResult/searchResult.ts b/src/main/resources/site/parts/searchResult/searchResult.ts index e7fdfb9c2..b41115767 100644 --- a/src/main/resources/site/parts/searchResult/searchResult.ts +++ b/src/main/resources/site/parts/searchResult/searchResult.ts @@ -2,8 +2,7 @@ import { get as getContentByKey, type Content } from '/lib/xp/content' import { sanitizeHtml, getContent, getComponent, pageUrl, serviceUrl } from '/lib/xp/portal' import { localize } from '/lib/xp/i18n' import { render } from '/lib/enonic/react4xp' -import { solrSearch googleSearch, -} from '/lib/ssb/utils/solrUtils' +import { solrSearch, googleSearch } from '/lib/ssb/utils/solrUtils' import { getNameSearchResult } from '/lib/ssb/utils/nameSearchUtils' import { type SolrResponse, type PreparedSearchResult, type SolrPrepResultAndTotal } from '/lib/types/solr' import { queryNodes, getNode } from '/lib/ssb/repo/common' From b007a03a1a88ba8e532528343e4df98cb1738a97 Mon Sep 17 00:00:00 2001 From: Glenruben Larsen Date: Tue, 21 May 2024 09:19:59 +0200 Subject: [PATCH 8/9] fix that didnt work --- build.gradle | 7 +++++-- gradle.properties | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 56d377916..37fbf8b43 100644 --- a/build.gradle +++ b/build.gradle @@ -14,10 +14,13 @@ app { systemVersion = "${xpVersion}"} dependencies { - implementation platform('com.google.cloud:libraries-bom:26.37.0') - implementation 'com.google.cloud:google-cloud-discoveryengine' + // implementation platform('com.google.cloud:libraries-bom:26.37.0') + // implementation 'com.google.cloud:google-cloud-discoveryengine' // https://mvnrepository.com/artifact/com.google.cloud/google-cloud-discoveryengine // implementation 'com.google.cloud:google-cloud-discoveryengine:0.38.0' + implementation 'com.google.guava:guava:31.0.1-jre' + include 'com.google.cloud:google-cloud-discoveryengine:0.38.0' + // https://mvnrepository.com/artifact/com.google.guava/guava include "com.enonic.lib:lib-thymeleaf:2.1.0" implementation "com.enonic.xp:core-api:${xpVersion}" implementation "com.enonic.xp:portal-api:${xpVersion}" diff --git a/gradle.properties b/gradle.properties index f8b9d057c..dab2a7c9c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,3 +12,5 @@ xpVersion = 7.13.3 # Settings for publishing to a Maven repo group = enableFeaturePreview('IMPROVED_POM_SUPPORT') + +org.gradle.jvmargs=-Xmx2048m From f043eae30822c6c9f0b2bc0e224bd2016453cef2 Mon Sep 17 00:00:00 2001 From: Glenruben Larsen Date: Tue, 3 Sep 2024 13:02:23 +0200 Subject: [PATCH 9/9] Remove failed vertex experiment. Add VertexConnector as search option. --- package-lock.json | 104 ++++++++---------- src/main/java/no/ssb/xp/vertex/Search.java | 64 ----------- .../java/no/ssb/xp/vertex/VertexService.java | 11 -- src/main/resources/lib/ssb/utils/solrUtils.ts | 57 ++++++++++ .../services/googleSearch/googleSearch.ts | 9 +- .../googleVertexSearch/googleVertexSearch.ts | 20 ++++ .../googleVertexSearch.xml} | 0 .../services/vertexSearch/vertexSearch.ts | 19 ---- .../site/parts/searchResult/searchResult.ts | 21 +++- .../site/parts/searchResult/searchResult.xml | 1 + .../site/parts/searchVertex/searchVertex.html | 9 -- .../site/parts/searchVertex/searchVertex.ts | 11 -- .../site/parts/searchVertex/searchVertex.xml | 4 - 13 files changed, 150 insertions(+), 180 deletions(-) delete mode 100644 src/main/java/no/ssb/xp/vertex/Search.java delete mode 100644 src/main/java/no/ssb/xp/vertex/VertexService.java create mode 100644 src/main/resources/services/googleVertexSearch/googleVertexSearch.ts rename src/main/resources/services/{vertexSearch/vertexSearch.xml => googleVertexSearch/googleVertexSearch.xml} (100%) delete mode 100644 src/main/resources/services/vertexSearch/vertexSearch.ts delete mode 100644 src/main/resources/site/parts/searchVertex/searchVertex.html delete mode 100644 src/main/resources/site/parts/searchVertex/searchVertex.ts delete mode 100644 src/main/resources/site/parts/searchVertex/searchVertex.xml diff --git a/package-lock.json b/package-lock.json index 97ca52c8b..f2bc6daff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "@googleapis/customsearch": "^1.1.0", "bootstrap": "~5.3.3", "core-js": "~3.38.1", "date-fns": "~3.6.0", @@ -8747,10 +8748,9 @@ } }, "node_modules/call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", - "dev": true, + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -9737,10 +9737,9 @@ } }, "node_modules/define-data-property": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", - "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", - "dev": true, + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -10360,7 +10359,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dev": true, "dependencies": { "get-intrinsic": "^1.2.4" }, @@ -10372,7 +10370,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, "engines": { "node": ">= 0.4" } @@ -11646,10 +11643,9 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", - "dev": true, + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", @@ -11945,10 +11941,9 @@ } }, "node_modules/has-property-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", - "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", - "dev": true, + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dependencies": { "es-define-property": "^1.0.0" }, @@ -11957,10 +11952,9 @@ } }, "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true, + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "engines": { "node": ">= 0.4" }, @@ -18489,10 +18483,9 @@ "dev": true }, "node_modules/set-function-length": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", - "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", - "dev": true, + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -18626,7 +18619,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "dev": true, "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -27731,10 +27723,9 @@ "dev": true }, "call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", - "dev": true, + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "requires": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -28446,10 +28437,9 @@ "dev": true }, "define-data-property": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", - "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", - "dev": true, + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "requires": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -28902,7 +28892,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dev": true, "requires": { "get-intrinsic": "^1.2.4" } @@ -28910,8 +28899,7 @@ "es-errors": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" }, "es-iterator-helpers": { "version": "1.0.19", @@ -29865,10 +29853,9 @@ "dev": true }, "get-intrinsic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", - "dev": true, + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "requires": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", @@ -30083,19 +30070,17 @@ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" }, "has-property-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", - "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", - "dev": true, + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "requires": { "es-define-property": "^1.0.0" } }, "has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==" }, "has-symbols": { "version": "1.0.3", @@ -30196,6 +30181,15 @@ "requires-port": "^1.0.0" } }, + "https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "requires": { + "agent-base": "^7.0.2", + "debug": "4" + } + }, "husky": { "version": "9.1.5", "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.5.tgz", @@ -34891,10 +34885,9 @@ "dev": true }, "set-function-length": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", - "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", - "dev": true, + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "requires": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -35000,7 +34993,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "dev": true, "requires": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -36994,4 +36986,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/main/java/no/ssb/xp/vertex/Search.java b/src/main/java/no/ssb/xp/vertex/Search.java deleted file mode 100644 index 980903f7d..000000000 --- a/src/main/java/no/ssb/xp/vertex/Search.java +++ /dev/null @@ -1,64 +0,0 @@ -package no.ssb.xp.vertex; - -import com.google.cloud.discoveryengine.v1.SearchRequest; -import com.google.cloud.discoveryengine.v1.SearchResponse; -import com.google.cloud.discoveryengine.v1.SearchServiceClient; -import com.google.cloud.discoveryengine.v1.SearchServiceSettings; -import com.google.cloud.discoveryengine.v1.ServingConfigName; -import java.io.IOException; -import java.util.concurrent.ExecutionException; - -public class Search { - public void run() throws IOException, ExecutionException { - - System.out.println(); - // TODO(developer): Replace these variables before running the sample. - // Project ID or project number of the Cloud project you want to use. - String projectId = "ssbno-t-lf"; - // Location of the data store. Options: "global", "us", "eu" - String location = "eu"; - // Collection containing the data store. - String collectionId = "ssbno-search-no_1713449390194"; - // Data store ID. - String dataStoreId = "ssbno-no_1713449458710"; - // Serving configuration. Options: "default_search" - String servingConfigId = "default_search"; - // Search Query for the data store. - String searchQuery = "Konsumpris"; - search(projectId, location, collectionId, dataStoreId, servingConfigId, searchQuery); - } - - /** Performs a search on a given datastore. */ - public static void search( - String projectId, - String location, - String collectionId, - String dataStoreId, - String servingConfigId, - String searchQuery) - throws IOException, ExecutionException { - // For more information, refer to: - // https://cloud.google.com/generative-ai-app-builder/docs/locations#specify_a_multi-region_for_your_data_store - String endpoint = "eu-discoveryengine.googleapis.com:443"; - SearchServiceSettings settings = - SearchServiceSettings.newBuilder().setEndpoint(endpoint).build(); - // Initialize client that will be used to send requests. This client only needs to be created - // once, and can be reused for multiple requests. After completing all of your requests, call - // the `searchServiceClient.close()` method on the client to safely - // clean up any remaining background resources. - try (SearchServiceClient searchServiceClient = SearchServiceClient.create(settings)) { - SearchRequest request = - SearchRequest.newBuilder() - .setServingConfig( - ServingConfigName.formatProjectLocationCollectionDataStoreServingConfigName( - projectId, location, collectionId, dataStoreId, servingConfigId)) - .setQuery(searchQuery) - .setPageSize(10) - .build(); - SearchResponse response = searchServiceClient.search(request).getPage().getResponse(); - for (SearchResponse.SearchResult element : response.getResultsList()) { - System.out.println("Response content: " + element); - } - } - } -} diff --git a/src/main/java/no/ssb/xp/vertex/VertexService.java b/src/main/java/no/ssb/xp/vertex/VertexService.java deleted file mode 100644 index 641725f7d..000000000 --- a/src/main/java/no/ssb/xp/vertex/VertexService.java +++ /dev/null @@ -1,11 +0,0 @@ -package no.ssb.xp.vertex; - -public class VertexService { - public static void main(String[] args) { - System.out.println("Hello, World!"); - } - - public String getVertex() { - return "Vertex is gotten, yes."; - } -} diff --git a/src/main/resources/lib/ssb/utils/solrUtils.ts b/src/main/resources/lib/ssb/utils/solrUtils.ts index 318fbd669..75f980c41 100644 --- a/src/main/resources/lib/ssb/utils/solrUtils.ts +++ b/src/main/resources/lib/ssb/utils/solrUtils.ts @@ -1,4 +1,5 @@ import { customsearch_v1 } from '@googleapis/customsearch' + import { sanitizeHtml, getSiteConfig } from '/lib/xp/portal' import { localize } from '/lib/xp/i18n' import { request, HttpResponse, HttpRequestParams } from '/lib/http-client' @@ -127,6 +128,62 @@ export function googleSearch( subjects: [], } } +export function vertexServiceSearch( + term: string, + start?: number, + language?: string, + numberOfHits?: number, + mainSubject?: string, + contentType?: string, + sortParam?: string +): SolrPrepResultAndTotal { + const sortString: string = sortParam === 'date' || sortParam === 'publiseringsdato' ? 'date' : '' + + const requestParams: HttpRequestParams = { + url: `http://localhost:3000/query`, + method: 'get', + contentType: 'application/json', + connectionTimeout: 60000, + readTimeout: 10000, + params: { + q: term, + sort: sortString, + offset: start?.toString() || '', + contenttype: contentType, + category: mainSubject, + }, + } + + const search = request(requestParams) + + const results = JSON.parse(search.body!) + log.info('\x1b[32m%s\x1b[0m', JSON.stringify(results, null, 2)) + + const solrFormatResults: Array | undefined = results.results?.map((item) => ({ + contentType: item.document?.structData?.fields?.contenttype?.listValue?.values[0]?.stringValue, + id: item.id || '1234', + title: item.document.derivedStructData.fields.title.stringValue || 'tittel', + preface: 'Her kommer tekst fra dokumentet', + url: item.document.derivedStructData.fields.link.stringValue || '', + mainSubject: item.document.structData.fields?.category?.listValue?.values[0]?.stringValue || 'test0', + secondaryMainSubject: item.document.structData.fields?.category?.listValue?.values[1]?.stringValue || 'test1', + publishDate: '2024-02-28T08:00:00Z', + publishDateHuman: formatDate('2024-02-28T08:00:00Z', 'PPP', 'no'), + })) + return solrFormatResults + ? { + hits: solrFormatResults, + total: Number(results.totalSize) || 0, + contentTypes: [{ count: 10, title: 'artikkel' }], + subjects: [{ count: 10, title: 'befolkning' }], + } + : { + hits: [], + total: 0, + contentTypes: [], + subjects: [], + } +} function nerfSearchResult(solrResult: SolrResult, language: string): Array { return solrResult.grouped.gruppering.groups.reduce((acc: Array, group) => { diff --git a/src/main/resources/services/googleSearch/googleSearch.ts b/src/main/resources/services/googleSearch/googleSearch.ts index 8731c8804..8cf9183db 100644 --- a/src/main/resources/services/googleSearch/googleSearch.ts +++ b/src/main/resources/services/googleSearch/googleSearch.ts @@ -1,11 +1,12 @@ -import { type SolrPrepResultAndTotal, googleSearch } from '/lib/ssb/utils/solrUtils' +import { googleSearch } from '/lib/ssb/utils/solrUtils' +import { SolrPrepResultAndTotal } from '/lib/types/solr' export function get(req: XP.Request): XP.Response { const results: SolrPrepResultAndTotal = googleSearch( - req.params.sok, - req.params.start || 0, + req.params.sok || 'kpi', + Number(req.params.start) || 0, req.params.language || 'nb', - req.params.count || 15, + Number(req.params.count) || 15, req.params.emne || '', req.params.mainsubject || '', req.params.sort || 'relevance' diff --git a/src/main/resources/services/googleVertexSearch/googleVertexSearch.ts b/src/main/resources/services/googleVertexSearch/googleVertexSearch.ts new file mode 100644 index 000000000..f2c036de1 --- /dev/null +++ b/src/main/resources/services/googleVertexSearch/googleVertexSearch.ts @@ -0,0 +1,20 @@ +import { vertexServiceSearch } from '/lib/ssb/utils/solrUtils' +import { SolrPrepResultAndTotal } from '/lib/types/solr' + +export function get(req: XP.Request): XP.Response { + const results: SolrPrepResultAndTotal = vertexServiceSearch( + req.params.sok || 'kpi', + Number(req.params.start) || 0, + req.params.language || 'nb', + Number(req.params.count) || 15, + req.params.emne || '', + req.params.mainsubject || '', + req.params.sort || 'relevance' + ) + + return { + body: results, + contentType: 'application/json', + status: 200, + } +} diff --git a/src/main/resources/services/vertexSearch/vertexSearch.xml b/src/main/resources/services/googleVertexSearch/googleVertexSearch.xml similarity index 100% rename from src/main/resources/services/vertexSearch/vertexSearch.xml rename to src/main/resources/services/googleVertexSearch/googleVertexSearch.xml diff --git a/src/main/resources/services/vertexSearch/vertexSearch.ts b/src/main/resources/services/vertexSearch/vertexSearch.ts deleted file mode 100644 index 1a84823be..000000000 --- a/src/main/resources/services/vertexSearch/vertexSearch.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { type VertexSearch } from '/lib/googleServices' - -const vertexSearch: VertexSearch = __.newBean('no.ssb.xp.vertex.VertexService') - -const search = __.newBean('no.ssb.xp.vertex.Search') - -try { - search.run() -} catch (e) { - log.error(e) -} - -export function get(): XP.Response { - return { - body: vertexSearch.getVertex(), - contentType: 'application/json', - status: 200, - } -} diff --git a/src/main/resources/site/parts/searchResult/searchResult.ts b/src/main/resources/site/parts/searchResult/searchResult.ts index 811d0b888..6bd2c6d23 100644 --- a/src/main/resources/site/parts/searchResult/searchResult.ts +++ b/src/main/resources/site/parts/searchResult/searchResult.ts @@ -2,7 +2,7 @@ import { get as getContentByKey, type Content } from '/lib/xp/content' import { sanitizeHtml, getContent, getComponent, pageUrl, serviceUrl } from '/lib/xp/portal' import { localize } from '/lib/xp/i18n' import { render } from '/lib/enonic/react4xp' -import { solrSearch, googleSearch } from '/lib/ssb/utils/solrUtils' +import { solrSearch, googleSearch, vertexServiceSearch } from '/lib/ssb/utils/solrUtils' import { getNameSearchResult } from '/lib/ssb/utils/nameSearchUtils' import { type SolrResponse, type PreparedSearchResult, type SolrPrepResultAndTotal } from '/lib/types/solr' import { queryNodes, getNode } from '/lib/ssb/repo/common' @@ -230,6 +230,23 @@ export function renderPart(req: XP.Request) { contentTypes: [], subjects: [], } + } + if (part.config.searchEngine === 'vertex') { + solrResult = sanitizedTerm + ? vertexServiceSearch( + sanitizedTerm, + 0, + language, + parseInt(part.config.numberOfHits), + req.params.emne, + req.params.innholdstype + ) + : { + total: 0, + hits: [], + contentTypes: [], + subjects: [], + } } else { solrResult = sanitizedTerm ? solrSearch( @@ -279,7 +296,7 @@ export function renderPart(req: XP.Request) { locale: language, }), searchServiceUrl: serviceUrl({ - service: part.config.searchEngine === 'google' ? 'googleSearch' : 'freeTextSearch', + service: part.config.searchEngine === 'vertex' ? 'googleVertexSearch' : 'freeTextSearch', }), nameSearchUrl: serviceUrl({ service: 'nameSearch', diff --git a/src/main/resources/site/parts/searchResult/searchResult.xml b/src/main/resources/site/parts/searchResult/searchResult.xml index 1a245c023..66af31a84 100644 --- a/src/main/resources/site/parts/searchResult/searchResult.xml +++ b/src/main/resources/site/parts/searchResult/searchResult.xml @@ -19,6 +19,7 @@ + solr diff --git a/src/main/resources/site/parts/searchVertex/searchVertex.html b/src/main/resources/site/parts/searchVertex/searchVertex.html deleted file mode 100644 index d8c1a433e..000000000 --- a/src/main/resources/site/parts/searchVertex/searchVertex.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/src/main/resources/site/parts/searchVertex/searchVertex.ts b/src/main/resources/site/parts/searchVertex/searchVertex.ts deleted file mode 100644 index 7c6cae18c..000000000 --- a/src/main/resources/site/parts/searchVertex/searchVertex.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { render } from '/lib/thymeleaf' - -export function get(req: XP.Request): XP.Response { - const view = resolve('searchVertex.html') - const model = { - test: 'test', - req: req, - } - const body = render(view, model) - return { body } -} diff --git a/src/main/resources/site/parts/searchVertex/searchVertex.xml b/src/main/resources/site/parts/searchVertex/searchVertex.xml deleted file mode 100644 index 6852ed62b..000000000 --- a/src/main/resources/site/parts/searchVertex/searchVertex.xml +++ /dev/null @@ -1,4 +0,0 @@ - - Søk med fancy VERTEX Google-søk - Eksperimentelt AI Google-søk med den nye kule tingen -