diff options
-rw-r--r-- | build-app.lisp | 18 | ||||
-rw-r--r-- | oneliners.api-client.lisp | 88 | ||||
-rw-r--r-- | oneliners.cli.asd | 2 | ||||
-rw-r--r-- | src/lib.lisp | 61 |
4 files changed, 98 insertions, 71 deletions
diff --git a/build-app.lisp b/build-app.lisp index 0a1bfd5..69338b1 100644 --- a/build-app.lisp +++ b/build-app.lisp @@ -80,7 +80,7 @@ you run the oneliner, all positional variables appear first. (group (:header "ONELINER EXECUTION OPTIONS") (text :contents "Runs the Nth search result with possible arguments ARGS.") (flag :long-name "id" - :description "Runs a oneliner by its id instead of by result number.") + :description "Refers a oneliner by its unique id instead of by result number.") (flag :long-name "clip" :description "Put oneliner into clipboard instead of running it.") (flag :long-name "clear-cache" @@ -203,21 +203,17 @@ than the users." (a:when-let (hist-number (parse-integer (first arguments) :junk-allowed t)) (cond ((getopt :long-name "flag") - (cli::flag-item hist-number)) + (cli::flag-item hist-number (getopt :long-name "id"))) ((getopt :long-name "unflag") - (cli::unflag-item hist-number)) + (cli::unflag-item hist-number (getopt :long-name "id"))) ((getopt :long-name "lock") - (cli::lock-item hist-number)) + (cli::lock-item hist-number (getopt :long-name "id"))) ((getopt :long-name "unlock") - (cli::unlock-item hist-number)) + (cli::unlock-item hist-number (getopt :long-name "id"))) ((getopt :long-name "edit") - (cli::edit-item hist-number)) + (cli::edit-item hist-number (getopt :long-name "id"))) ((getopt :long-name "explain") - (cli::print-item-explanation hist-number)) - - ;; ((getopt :long-name "alias") - ;; (cli::make-alias-for-item hist-number (second arguments))) - + (cli::print-item-explanation hist-number (getopt :long-name "id"))) (t (cli::run-item hist-number (rest arguments) :by-id (getopt :long-name "id") diff --git a/oneliners.api-client.lisp b/oneliners.api-client.lisp index bd7ba72..5fc6f10 100644 --- a/oneliners.api-client.lisp +++ b/oneliners.api-client.lisp @@ -5,11 +5,11 @@ (defpackage #:ONELINERS.API-CLIENT (:use :cl :lazybones-client.shared) (:export #:*host* #:*body* #:*headers* #:*cookies* #:request-with - #:PUT--CONTRIBUTOR-WHO-PASSWORD -#:GET--ONELINERS + #:GET--ONELINERS #:GET--ONELINERS-ALL-FLAGGED #:GET--ONELINERS-NEWEST #:PUT--ONELINER-ENTRY-FLAG +#:GET--ONELINER-ENTRY #:PATCH--ONELINER-ENTRY-EDIT #:PUT--ONELINER-ONELINER-LOCKED #:POST--ONELINER @@ -19,6 +19,7 @@ #:POST--ACCESS #:POST--INVITE-REDEEM-CODE #:PUT--CONTRIBUTOR-WHO-SIGNATURE +#:PUT--CONTRIBUTOR-WHO-PASSWORD #:PUT--CONTRIBUTOR-WHO-LOCKED #:GET--CONTRIBUTOR-WHO)) (in-package :ONELINERS.API-CLIENT) @@ -69,39 +70,6 @@ COOKIES should be an instance of CL-COOKIE:COOKIE-JAR. Defaults to (dex:response-body ,http-error-var))))))) -(DEFUN PUT--CONTRIBUTOR-WHO-PASSWORD (WHO &KEY VALUE REPEATED CURRENT TOKEN) - "Change a contributor's password." - (LET ((LAZYBONES-CLIENT.SHARED::REQ-STRING - (APPLY #'CONCATENATE 'STRING LAZYBONES-CLIENT.SHARED:*HOST* "/api" - (FORMAT NIL "/contributor/~a/password" WHO) - (WHEN (OR VALUE REPEATED CURRENT TOKEN) - (LIST "?" - (IF VALUE - (CONCATENATE 'STRING (SYMBOL-NAME 'VALUE) "=" - (FORMAT NIL "~a" VALUE)) - "") - (IF REPEATED - (CONCATENATE 'STRING "&" (SYMBOL-NAME 'REPEATED) - "=" (FORMAT NIL "~a" REPEATED)) - "") - (IF CURRENT - (CONCATENATE 'STRING "&" (SYMBOL-NAME 'CURRENT) "=" - (FORMAT NIL "~a" CURRENT)) - "") - (IF TOKEN - (CONCATENATE 'STRING "&" (SYMBOL-NAME 'TOKEN) "=" - (FORMAT NIL "~a" TOKEN)) - "")))))) - (IF LAZYBONES-CLIENT.SHARED:*BODY* - (DEXADOR:PUT LAZYBONES-CLIENT.SHARED::REQ-STRING :CONTENT - LAZYBONES-CLIENT.SHARED:*BODY* :COOKIE-JAR - LAZYBONES-CLIENT.SHARED:*COOKIES* :HEADERS - LAZYBONES-CLIENT.SHARED:*HEADERS*) - (DEXADOR:PUT LAZYBONES-CLIENT.SHARED::REQ-STRING :COOKIE-JAR - LAZYBONES-CLIENT.SHARED:*COOKIES* :HEADERS - LAZYBONES-CLIENT.SHARED:*HEADERS*)))) - - (DEFUN GET--ONELINERS (&KEY TAGS LIMIT NOTFLAGGED) "A search endpoint returning a JSON encoded array of Oneliner Entries. TAGS cannot be empty. Returns a [Search @@ -186,6 +154,16 @@ Result](#search-result) object." LAZYBONES-CLIENT.SHARED:*HEADERS*)))) +(DEFUN GET--ONELINER-ENTRY (ENTRY) + "Gets a oneliner by id." + (LET ((LAZYBONES-CLIENT.SHARED::REQ-STRING + (APPLY #'CONCATENATE 'STRING LAZYBONES-CLIENT.SHARED:*HOST* "/api" + (FORMAT NIL "/oneliner/~a" ENTRY) NIL))) + (DEXADOR:GET LAZYBONES-CLIENT.SHARED::REQ-STRING :COOKIE-JAR + LAZYBONES-CLIENT.SHARED:*COOKIES* :HEADERS + LAZYBONES-CLIENT.SHARED:*HEADERS*))) + + (DEFUN PATCH--ONELINER-ENTRY-EDIT (ENTRY &KEY TOKEN) "Edit the fields of a oneliner." (LET ((LAZYBONES-CLIENT.SHARED::REQ-STRING @@ -337,7 +315,7 @@ Result](#search-result) object." (DEFUN PUT--CONTRIBUTOR-WHO-SIGNATURE (WHO &KEY TOKEN) - NIL + "Update a [contributor's](#contributor) signature." (LET ((LAZYBONES-CLIENT.SHARED::REQ-STRING (APPLY #'CONCATENATE 'STRING LAZYBONES-CLIENT.SHARED:*HOST* "/api" (FORMAT NIL "/contributor/~a/signature" WHO) @@ -357,8 +335,42 @@ Result](#search-result) object." LAZYBONES-CLIENT.SHARED:*HEADERS*)))) +(DEFUN PUT--CONTRIBUTOR-WHO-PASSWORD (WHO &KEY VALUE REPEATED CURRENT TOKEN) + "Change a contributor's password." + (LET ((LAZYBONES-CLIENT.SHARED::REQ-STRING + (APPLY #'CONCATENATE 'STRING LAZYBONES-CLIENT.SHARED:*HOST* "/api" + (FORMAT NIL "/contributor/~a/password" WHO) + (WHEN (OR VALUE REPEATED CURRENT TOKEN) + (LIST "?" + (IF VALUE + (CONCATENATE 'STRING (SYMBOL-NAME 'VALUE) "=" + (FORMAT NIL "~a" VALUE)) + "") + (IF REPEATED + (CONCATENATE 'STRING "&" (SYMBOL-NAME 'REPEATED) + "=" (FORMAT NIL "~a" REPEATED)) + "") + (IF CURRENT + (CONCATENATE 'STRING "&" (SYMBOL-NAME 'CURRENT) "=" + (FORMAT NIL "~a" CURRENT)) + "") + (IF TOKEN + (CONCATENATE 'STRING "&" (SYMBOL-NAME 'TOKEN) "=" + (FORMAT NIL "~a" TOKEN)) + "")))))) + (IF LAZYBONES-CLIENT.SHARED:*BODY* + (DEXADOR:PUT LAZYBONES-CLIENT.SHARED::REQ-STRING :CONTENT + LAZYBONES-CLIENT.SHARED:*BODY* :COOKIE-JAR + LAZYBONES-CLIENT.SHARED:*COOKIES* :HEADERS + LAZYBONES-CLIENT.SHARED:*HEADERS*) + (DEXADOR:PUT LAZYBONES-CLIENT.SHARED::REQ-STRING :COOKIE-JAR + LAZYBONES-CLIENT.SHARED:*COOKIES* :HEADERS + LAZYBONES-CLIENT.SHARED:*HEADERS*)))) + + (DEFUN PUT--CONTRIBUTOR-WHO-LOCKED (WHO &KEY VALUE TOKEN) - NIL + "Admin users may lock a particular contributor, preventing that +contributor for making edits or adding new oneliners." (LET ((LAZYBONES-CLIENT.SHARED::REQ-STRING (APPLY #'CONCATENATE 'STRING LAZYBONES-CLIENT.SHARED:*HOST* "/api" (FORMAT NIL "/contributor/~a/locked" WHO) @@ -383,7 +395,7 @@ Result](#search-result) object." (DEFUN GET--CONTRIBUTOR-WHO (WHO) - NIL + "Return a [contributor](#contributor) data object." (LET ((LAZYBONES-CLIENT.SHARED::REQ-STRING (APPLY #'CONCATENATE 'STRING LAZYBONES-CLIENT.SHARED:*HOST* "/api" (FORMAT NIL "/contributor/~a" WHO) NIL))) diff --git a/oneliners.cli.asd b/oneliners.cli.asd index 9b37b4c..1993389 100644 --- a/oneliners.cli.asd +++ b/oneliners.cli.asd @@ -1,5 +1,5 @@ (defsystem "oneliners.cli" - :version "0.3.0" + :version "0.4.0" :author "Colin Okay" :license "AGPLv3" :depends-on ("trivial-clipboard" diff --git a/src/lib.lisp b/src/lib.lisp index b87ffc6..d990b22 100644 --- a/src/lib.lisp +++ b/src/lib.lisp @@ -157,10 +157,11 @@ the directories that appear in the value of that variable." (nth n contents))))) (defmacro with-cached-result ((olvar n &optional idp) &body body) - (a:with-gensyms (nvar) - `(let ((,nvar ,n)) + (a:with-gensyms (nvar idpvar) + `(let ((,nvar ,n) + (,idpvar ,idp)) (assert (plusp ,nvar) () "Item number must be 1 or greater") - (a:if-let (,olvar ,(if idp `(cached-result ,nvar t) `(cached-result (1- ,nvar)))) + (a:if-let (,olvar (if ,idpvar (cached-result ,nvar t) (cached-result (1- ,nvar)))) (progn ,@body) (format t "Could not find the oneliner specified by ~a~%" ,nvar))))) @@ -172,29 +173,29 @@ the directories that appear in the value of that variable." ;;; API REQUEST FUNCTIONS -(defun flag-item (item-number) - (with-cached-result (ol item-number) +(defun flag-item (item-number &optional idp) + (with-cached-result (ol item-number idp) (ensure-config) (api:request-with (:host (host)) (api:put--oneliner-entry-flag (getf ol :id) :token (api-token) :value "true")))) -(defun unflag-item (item-number) - (with-cached-result (ol item-number) +(defun unflag-item (item-number &optional idp) + (with-cached-result (ol item-number idp) (ensure-config) (api:request-with (:host (host)) (api:put--oneliner-entry-flag (getf ol :id) :token (api-token) :value "false")))) -(defun lock-item (item-number) - (with-cached-result (ol item-number) +(defun lock-item (item-number &optional idp) + (with-cached-result (ol item-number idp) (ensure-config) (api:request-with (:host (host)) (api:put--oneliner-oneliner-locked (getf ol :id) :token (api-token) :value "true")))) -(defun unlock-item (item-number) - (with-cached-result (ol item-number) +(defun unlock-item (item-number &optional idp) + (with-cached-result (ol item-number idp) (ensure-config) (api:request-with (:host (host)) @@ -249,12 +250,20 @@ the directories that appear in the value of that variable." (handle-run-oneliner oneliner (or force-clip (equalp runstyle "manual")))))) (defun run-item (item-number args &key by-id force-clip (timeout nil timeout-p)) - (let ((*ol-output-timeout* (if timeout-p timeout *ol-output-timeout*))) - (if by-id - (with-cached-result (ol item-number t) - (bind-vars-and-run-oneliner ol args force-clip)) - (with-cached-result (ol item-number) - (bind-vars-and-run-oneliner ol args force-clip))))) + (let ((*ol-output-timeout* (if timeout-p timeout *ol-output-timeout*)) + (found nil)) + (with-cached-result (ol item-number by-id) + (setf found t) + (bind-vars-and-run-oneliner ol args force-clip)) + (when (and by-id (not found)) + (format t "Trying to fetch that oneliner with id ~a from the wiki.~%" item-number) + (a:if-let ((ol + (api:request-with (:host (host)) + (jonathan:parse + (api::get--oneliner-entry item-number))))) + (progn (bind-vars-and-run-oneliner ol args force-clip) + (merge-into-cache (list ol))) + (format t "Still couldn't find it. Is something wrong?"))))) (defun valid-oneliner-string-p (string) (and (not (find #\newline string)) @@ -329,10 +338,10 @@ the directories that appear in the value of that variable." (api:post--oneliner :token (api-token)) (format t "Added~%")))) -(defun edit-item (n) +(defun edit-item (n &optional idp) (ensure-config) (assert (api-token) () "Cannot edit a oneliner without an api token.") - (with-cached-result (ol n) + (with-cached-result (ol n idp) (let* ((oneliner (prompt "Oneliner: " :expect 'valid-oneliner-string-p @@ -377,7 +386,9 @@ the directories that appear in the value of that variable." new-item) :content-type "application/json") (api:patch--oneliner-entry-edit (getf ol :id) :token (api-token)) - (update-history-item n new-item) + (if idp + (update-history-item n new-item) + (update-cached-item new-item)) (format t "OK~%")))))) (defun request-invite-code () @@ -480,7 +491,15 @@ the directories that appear in the value of that variable." (ol (nth (1- n) results))) (when ol (setf (nth (1- n) results) (append item ol)) - (cache-search-results-to-last-search-file results))))) + (cache-search-results-to-last-search-file results)))) + (merge-into-cache (list item))) + +(defun update-cached-item (item) + (let* ((history (with-open-file (input (last-search-file)) (read input))) + (pos (position (getf item :id) history :key (lambda (x) (getf item :id))))) + (if pos + (update-history-item (1+ pos) item) + (merge-into-cache (list item))))) (defun cache-search-results-to-last-search-file (results) (with-open-file (output (last-search-file) :direction :output :if-exists :supersede) |