Browse Source
I copied most of this over from my personal website's repository. So, there are bits of code which look a bit out of place in this context. With that said, the code does run and just needs to be integrated in the defroutes in web.lisp.stable
Craig Oates
2 years ago
2 changed files with 128 additions and 2 deletions
@ -0,0 +1,125 @@
|
||||
(defpackage #:search |
||||
(:use #:cl |
||||
#:app-constants |
||||
#:cl-json |
||||
#:local-time |
||||
#:utils) |
||||
(:import-from #:dexador |
||||
#:request) |
||||
(:export #:build-keywords-string |
||||
#:build-payload |
||||
#:delete-entry |
||||
#:find-entry |
||||
#:get-id |
||||
#:get-keywords |
||||
#:submit-entry |
||||
#:set-filter-attributes)) |
||||
(in-package #:search) |
||||
|
||||
;; Explains the "~{~A~^,~}" in the format call below. |
||||
;; https://stackoverflow.com/questions/8830888/whats-the-canonical-way-to-join-strings-in-a-list |
||||
(defun build-keywords-string (id) |
||||
"Gets the keywords for `ID' in meilisearch DB and formats into a string. |
||||
The string should look something like: 'art,blog post,testing,whatever'. One |
||||
thing to note is meilisearch uses the comma to separate and create tokens of the |
||||
string. So, the user can have spaces in their keywords but they cannot separate |
||||
the keywords with a space. 'art blog post' is classed as three tokens and |
||||
'art,blog post' is classes as two." |
||||
(format nil "~{~A~^,~}" (search:get-keywords (search:find-entry id)))) |
||||
|
||||
(defun build-payload (id-value title-value relative-path-value |
||||
thumbnail-path-value created-at-value keywords-value) |
||||
"Creates a JSON object which reflects the schema in the meilsearch database. |
||||
Note: The JSON object to encoded as a string." |
||||
(cl-json:encode-json-to-string |
||||
`((("id" . ,id-value) |
||||
("title" . ,title-value) |
||||
("relative-path" . ,relative-path-value) |
||||
("thumbnail-path" . ,thumbnail-path-value) |
||||
("year" . ,(local-time:timestamp-year created-at-value)) |
||||
("month" . ,(local-time:timestamp-month created-at-value)) |
||||
("day" . ,(local-time:timestamp-day created-at-value)) |
||||
("keywords" . ,(cl-ppcre:split "," keywords-value)))))) |
||||
|
||||
(defun build-search-url (path) |
||||
"Constructs the URL to connect to the meilisearch instance (beta or prod.) |
||||
The function will check to see which environment the current instance of this |
||||
site is running in and use the beta or prod. URL's to connect to meilisearch. |
||||
`PATH' is the relative path which this function will concatenate onto the end of |
||||
the base URL." |
||||
(if (ritherdon-archive.config:developmentp) |
||||
(concatenate 'string "http://localhost:7700" path) |
||||
(concatenate 'string "https://www.nera.com" path))) |
||||
|
||||
(defun delete-entry (id) |
||||
"Deletes and entry from the meilisearch database based on its `ID'. |
||||
This does not affect this website's (nera) database -- only the meilisearch |
||||
one." |
||||
(dexador:request |
||||
(build-search-url |
||||
(format nil "/indexes/nera/documents/~a" id)); (get-id (find-entry id)))) |
||||
:method :delete |
||||
:use-connection-pool nil |
||||
:headers `(("Authorization" . ,(meilisearch-api-key))) |
||||
:verbose nil)) |
||||
|
||||
|
||||
(defun documents-total () |
||||
"Gets the total number of documents in the meilisearch database." |
||||
(rest |
||||
(second |
||||
(second |
||||
(assoc :indexes (cl-json:decode-json-from-string |
||||
(dexador:request (build-search-url "/stats") |
||||
:method :get |
||||
:use-connection-pool nil |
||||
:headers `(("Content-Type" . "application/json") |
||||
("Authorization" . ,(meilisearch-api-key))) |
||||
:verbose nil))))))) |
||||
|
||||
(defun find-entry (title) |
||||
"Finds the entry in the meilisearch database by its `TITLE'." |
||||
(cl-json:decode-json-from-string |
||||
(dexador:request |
||||
(build-search-url "/indexes/nera/search") |
||||
:method :post |
||||
:use-connection-pool nil |
||||
:headers `(("Content-Type" . "application/json") |
||||
("Authorization" . ,(meilisearch-api-key))) |
||||
:content (format nil "{ \"q\": \"~a\", \"limit\": 1 }" title) |
||||
:verbose nil))) |
||||
|
||||
(defun get-id (payload) |
||||
"Gets the id from the JSON `PAYLOAD', make sure limit is set to 1." |
||||
(rest (third (second (first payload))))) |
||||
|
||||
(defun get-keywords (payload) |
||||
"Get the keywords from the JSON `PAYLOAD'." |
||||
(rest (first (last (last (second (first payload))))))) |
||||
|
||||
(defun meilisearch-api-key () |
||||
"Returns either the beta or prod. API key for meilisearch. |
||||
The API key is determined based on which environment this website is |
||||
currently running in." |
||||
(if (ritherdon-archive.config:developmentp) |
||||
"Bearer meilisearch-beta-key" |
||||
"Bearer meilisearch-production-key-nera")) |
||||
|
||||
(defun submit-entry (payload) |
||||
"Adds a new article to the meilisearch database." |
||||
(dexador:request ;;"http://127.0.0.1:7700/indexes/nera/documents" |
||||
(build-search-url "/indexes/nera/documents") |
||||
:method :post |
||||
:use-connection-pool nil |
||||
:headers `(("Content-Type" . "application/json") |
||||
("Authorization" . ,(meilisearch-api-key))) |
||||
:content payload |
||||
:verbose nil)) |
||||
|
||||
(defun set-filter-attributes () |
||||
"Sets the filter attributes in the Meilisearch database. |
||||
These values are hard-coded into the system because they are based on what Nic |
||||
has requested. She would like the filtering to consist on years and months." |
||||
(utils:run-bash-command |
||||
(format nil "curl -X PATCH \'~a\' -H \'Authorization: ~a\' -H \'Content-Type: application/json\' --data-binary \'{ \"filterableAttributes\": [ \"year\", \"month\", \"keywords\" ]}\'" |
||||
(build-search-url "/indexes/nera/settings") (meilisearch-api-key)))) |
Loading…
Reference in new issue