diff options
-rw-r--r-- | build.lisp | 3 | ||||
-rw-r--r-- | oneliners.api-client.lisp | 209 | ||||
-rw-r--r-- | src/main.lisp | 23 |
3 files changed, 171 insertions, 64 deletions
diff --git a/build.lisp b/build.lisp new file mode 100644 index 0000000..f8e4227 --- /dev/null +++ b/build.lisp @@ -0,0 +1,3 @@ + +(asdf:load-system "oneliners.cli") +(sb-ext:save-lisp-and-die "ol" :toplevel 'oneliners.cli::main :executable t) diff --git a/oneliners.api-client.lisp b/oneliners.api-client.lisp index d3142fb..98c156d 100644 --- a/oneliners.api-client.lisp +++ b/oneliners.api-client.lisp @@ -5,26 +5,32 @@ (defpackage #:ONELINERS.API-CLIENT (:use :cl :lazybones-client.shared) (:export #:*host* #:*body* #:*headers* #:*cookies* #:request-with - #:POST--AUTH - #:POST--ONELINER - #:PUT--ONELINER-ONELINER - #:GET--SEARCH)) + #:GET--SEARCH +#:PATCH--FLAG-ONELINER +#:PATCH--EDIT-ONELINER +#:PATCH--UNLOCK-ONELINER +#:PATCH--LOCK-ONELINER +#:POST--ADD-ONELINER +#:POST--MAKE-INVITE +#:POST--REVOKE-CONTRIBUTOR +#:POST--TOKEN-CONTRIBUTOR +#:POST--REDEEM-INVITE)) (in-package :ONELINERS.API-CLIENT) (defvar *host* nil "The host to which the client will send its requests.") -(defvar *body* nil - "Body passed to client post, put, and patch requests") + (defvar *body* nil + "Body passed to client post, put, and patch requests") -(defvar *cookies* nil - "An instance of CL-COOKIE:COOKIE-JAR.") + (defvar *cookies* nil + "An instance of CL-COOKIE:COOKIE-JAR.") -(defvar *headers* nil - "A liist of (header-name . header-value) pairs.") + (defvar *headers* nil + "A liist of (header-name . header-value) pairs.") -(defmacro request-with ((&key host body headers content-type cookies) &body forms) + (defmacro request-with ((&key host body headers content-type cookies) &body forms) "Make a request in a specific context. HOST is a string, the hostname where the request will be sent. Defaults @@ -52,11 +58,97 @@ COOKIES should be an instance of CL-COOKIE:COOKIE-JAR. Defaults to ,@forms))) -(DEFUN POST--AUTH () - "Requests an authorization token" +(DEFUN GET--SEARCH (&KEY TAGS LIMIT NOTFLAGGED) + "A search endpoint returning a JSON encoded array of Oneliner +Entries. TAGS cannot be empty. Returns a [Search +Result](#search-result) object." (LET ((LAZYBONES-CLIENT.SHARED::REQ-STRING (APPLY #'CONCATENATE 'STRING LAZYBONES-CLIENT.SHARED:*HOST* - (FORMAT NIL "/auth") (WHEN (OR) (LIST "?"))))) + (FORMAT NIL "/search") + (WHEN (OR TAGS LIMIT NOTFLAGGED) + (LIST "?" + (IF TAGS + (CONCATENATE 'STRING (SYMBOL-NAME 'TAGS) "=" + (FORMAT NIL "~a" TAGS)) + "") + (IF LIMIT + (CONCATENATE 'STRING "&" (SYMBOL-NAME 'LIMIT) "=" + (FORMAT NIL "~a" LIMIT)) + "") + (IF NOTFLAGGED + (CONCATENATE 'STRING "&" (SYMBOL-NAME 'NOTFLAGGED) + "=" (FORMAT NIL "~a" NOTFLAGGED)) + "")))))) + (DEXADOR:GET LAZYBONES-CLIENT.SHARED::REQ-STRING :COOKIE-JAR + LAZYBONES-CLIENT.SHARED:*COOKIES* :HEADERS + LAZYBONES-CLIENT.SHARED:*HEADERS*))) + + +(DEFUN PATCH--FLAG-ONELINER (ONELINER) + "Flag the oneliner for review. Open to anyone." + (LET ((LAZYBONES-CLIENT.SHARED::REQ-STRING + (APPLY #'CONCATENATE 'STRING LAZYBONES-CLIENT.SHARED:*HOST* + (FORMAT NIL "/flag/~a" ONELINER) NIL))) + (IF LAZYBONES-CLIENT.SHARED:*BODY* + (DEXADOR:PATCH LAZYBONES-CLIENT.SHARED::REQ-STRING :CONTENT + LAZYBONES-CLIENT.SHARED:*BODY* :COOKIE-JAR + LAZYBONES-CLIENT.SHARED:*COOKIES* :HEADERS + LAZYBONES-CLIENT.SHARED:*HEADERS*) + (DEXADOR:PATCH LAZYBONES-CLIENT.SHARED::REQ-STRING :COOKIE-JAR + LAZYBONES-CLIENT.SHARED:*COOKIES* :HEADERS + LAZYBONES-CLIENT.SHARED:*HEADERS*)))) + + +(DEFUN PATCH--EDIT-ONELINER (ONELINER) + "Edit the fields of a oneliner." + (LET ((LAZYBONES-CLIENT.SHARED::REQ-STRING + (APPLY #'CONCATENATE 'STRING LAZYBONES-CLIENT.SHARED:*HOST* + (FORMAT NIL "/edit/~a" ONELINER) NIL))) + (IF LAZYBONES-CLIENT.SHARED:*BODY* + (DEXADOR:PATCH LAZYBONES-CLIENT.SHARED::REQ-STRING :CONTENT + LAZYBONES-CLIENT.SHARED:*BODY* :COOKIE-JAR + LAZYBONES-CLIENT.SHARED:*COOKIES* :HEADERS + LAZYBONES-CLIENT.SHARED:*HEADERS*) + (DEXADOR:PATCH LAZYBONES-CLIENT.SHARED::REQ-STRING :COOKIE-JAR + LAZYBONES-CLIENT.SHARED:*COOKIES* :HEADERS + LAZYBONES-CLIENT.SHARED:*HEADERS*)))) + + +(DEFUN PATCH--UNLOCK-ONELINER (ONELINER) + "Unlocks a oneliner." + (LET ((LAZYBONES-CLIENT.SHARED::REQ-STRING + (APPLY #'CONCATENATE 'STRING LAZYBONES-CLIENT.SHARED:*HOST* + (FORMAT NIL "/unlock/~a" ONELINER) NIL))) + (IF LAZYBONES-CLIENT.SHARED:*BODY* + (DEXADOR:PATCH LAZYBONES-CLIENT.SHARED::REQ-STRING :CONTENT + LAZYBONES-CLIENT.SHARED:*BODY* :COOKIE-JAR + LAZYBONES-CLIENT.SHARED:*COOKIES* :HEADERS + LAZYBONES-CLIENT.SHARED:*HEADERS*) + (DEXADOR:PATCH LAZYBONES-CLIENT.SHARED::REQ-STRING :COOKIE-JAR + LAZYBONES-CLIENT.SHARED:*COOKIES* :HEADERS + LAZYBONES-CLIENT.SHARED:*HEADERS*)))) + + +(DEFUN PATCH--LOCK-ONELINER (ONELINER) + "Locks a oneliner. Locked oneliners cannot be edited or flagged." + (LET ((LAZYBONES-CLIENT.SHARED::REQ-STRING + (APPLY #'CONCATENATE 'STRING LAZYBONES-CLIENT.SHARED:*HOST* + (FORMAT NIL "/lock/~a" ONELINER) NIL))) + (IF LAZYBONES-CLIENT.SHARED:*BODY* + (DEXADOR:PATCH LAZYBONES-CLIENT.SHARED::REQ-STRING :CONTENT + LAZYBONES-CLIENT.SHARED:*BODY* :COOKIE-JAR + LAZYBONES-CLIENT.SHARED:*COOKIES* :HEADERS + LAZYBONES-CLIENT.SHARED:*HEADERS*) + (DEXADOR:PATCH LAZYBONES-CLIENT.SHARED::REQ-STRING :COOKIE-JAR + LAZYBONES-CLIENT.SHARED:*COOKIES* :HEADERS + LAZYBONES-CLIENT.SHARED:*HEADERS*)))) + + +(DEFUN POST--ADD-ONELINER () + "Make a new [oneliner](#oneliner)." + (LET ((LAZYBONES-CLIENT.SHARED::REQ-STRING + (APPLY #'CONCATENATE 'STRING LAZYBONES-CLIENT.SHARED:*HOST* + (FORMAT NIL "/add-oneliner") NIL))) (IF LAZYBONES-CLIENT.SHARED:*BODY* (DEXADOR:POST LAZYBONES-CLIENT.SHARED::REQ-STRING :CONTENT LAZYBONES-CLIENT.SHARED:*BODY* :COOKIE-JAR @@ -67,11 +159,11 @@ COOKIES should be an instance of CL-COOKIE:COOKIE-JAR. Defaults to LAZYBONES-CLIENT.SHARED:*HEADERS*)))) -(DEFUN POST--ONELINER () - "Adds a new oneliner entry to the wiki database." +(DEFUN POST--MAKE-INVITE () + "On success, return an object containing a new [invite token](#invite-token)." (LET ((LAZYBONES-CLIENT.SHARED::REQ-STRING (APPLY #'CONCATENATE 'STRING LAZYBONES-CLIENT.SHARED:*HOST* - (FORMAT NIL "/oneliner") (WHEN (OR) (LIST "?"))))) + (FORMAT NIL "/make-invite") NIL))) (IF LAZYBONES-CLIENT.SHARED:*BODY* (DEXADOR:POST LAZYBONES-CLIENT.SHARED::REQ-STRING :CONTENT LAZYBONES-CLIENT.SHARED:*BODY* :COOKIE-JAR @@ -82,68 +174,69 @@ COOKIES should be an instance of CL-COOKIE:COOKIE-JAR. Defaults to LAZYBONES-CLIENT.SHARED:*HEADERS*)))) -(DEFUN PUT--ONELINER-ONELINER (ONELINER) - "Updates a oneliner entry in the wiki database." +(DEFUN POST--REVOKE-CONTRIBUTOR (CONTRIBUTOR) + "A contributor can revoke their own access (if for some reason their + API key ends up out of their control), or an admin can revoke + anybody's access token, forcing the to re-authenticate." (LET ((LAZYBONES-CLIENT.SHARED::REQ-STRING (APPLY #'CONCATENATE 'STRING LAZYBONES-CLIENT.SHARED:*HOST* - (FORMAT NIL "/oneliner/~a" ONELINER) (WHEN (OR) (LIST "?"))))) + (FORMAT NIL "/revoke/~a" CONTRIBUTOR) NIL))) (IF LAZYBONES-CLIENT.SHARED:*BODY* - (DEXADOR:PUT LAZYBONES-CLIENT.SHARED::REQ-STRING :CONTENT + (DEXADOR:POST 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 + (DEXADOR:POST LAZYBONES-CLIENT.SHARED::REQ-STRING :COOKIE-JAR LAZYBONES-CLIENT.SHARED:*COOKIES* :HEADERS LAZYBONES-CLIENT.SHARED:*HEADERS*)))) -(DEFUN GET--SEARCH - (&KEY COMMANDS KEYWORDS LIMIT PAGE NEXTPAGE NOTFLAGGED ONLYAUDITED) - "A search endpoint returning a JSON encoded array of Oneliner Entries. +(DEFUN POST--TOKEN-CONTRIBUTOR (CONTRIBUTOR &KEY PASSWORD) + "Authenticate a contributor and reply with an [api token](#access-token)" + (LET ((LAZYBONES-CLIENT.SHARED::REQ-STRING + (APPLY #'CONCATENATE 'STRING LAZYBONES-CLIENT.SHARED:*HOST* + (FORMAT NIL "/token/~a" CONTRIBUTOR) + (WHEN (OR PASSWORD) + (LIST "?" + (IF PASSWORD + (CONCATENATE 'STRING (SYMBOL-NAME 'PASSWORD) "=" + (FORMAT NIL "~a" PASSWORD)) + "")))))) + (IF LAZYBONES-CLIENT.SHARED:*BODY* + (DEXADOR:POST LAZYBONES-CLIENT.SHARED::REQ-STRING :CONTENT + LAZYBONES-CLIENT.SHARED:*BODY* :COOKIE-JAR + LAZYBONES-CLIENT.SHARED:*COOKIES* :HEADERS + LAZYBONES-CLIENT.SHARED:*HEADERS*) + (DEXADOR:POST LAZYBONES-CLIENT.SHARED::REQ-STRING :COOKIE-JAR + LAZYBONES-CLIENT.SHARED:*COOKIES* :HEADERS + LAZYBONES-CLIENT.SHARED:*HEADERS*)))) + -**Note**: either command or keywords are required. -" +(DEFUN POST--REDEEM-INVITE (INVITE &KEY USERNAME PASSWORD1 PASSWORD2) + "Redeem an [invite code](#invite-code) and create a new [contributor](#new-contributor-post-body)" (LET ((LAZYBONES-CLIENT.SHARED::REQ-STRING (APPLY #'CONCATENATE 'STRING LAZYBONES-CLIENT.SHARED:*HOST* - (FORMAT NIL "/search") - (WHEN - (OR COMMANDS KEYWORDS LIMIT PAGE NEXTPAGE NOTFLAGGED - ONLYAUDITED) + (FORMAT NIL "/redeem/~a" INVITE) + (WHEN (OR USERNAME PASSWORD1 PASSWORD2) (LIST "?" - (IF COMMANDS - (CONCATENATE 'STRING (SYMBOL-NAME 'COMMANDS) "=" - (FORMAT NIL "~a" COMMANDS)) + (IF USERNAME + (CONCATENATE 'STRING (SYMBOL-NAME 'USERNAME) "=" + (FORMAT NIL "~a" USERNAME)) "") - (IF KEYWORDS - (CONCATENATE 'STRING "&" (SYMBOL-NAME 'KEYWORDS) - "=" (FORMAT NIL "~a" KEYWORDS)) + (IF PASSWORD1 + (CONCATENATE 'STRING "&" (SYMBOL-NAME 'PASSWORD1) + "=" (FORMAT NIL "~a" PASSWORD1)) "") - (IF LIMIT - (CONCATENATE 'STRING "&" (SYMBOL-NAME 'LIMIT) "=" - (FORMAT NIL "~a" LIMIT)) - "") - (IF PAGE - (CONCATENATE 'STRING "&" (SYMBOL-NAME 'PAGE) "=" - (FORMAT NIL "~a" PAGE)) - "") - (IF NEXTPAGE - (CONCATENATE 'STRING "&" (SYMBOL-NAME 'NEXTPAGE) - "=" (FORMAT NIL "~a" NEXTPAGE)) - "") - (IF NOTFLAGGED - (CONCATENATE 'STRING "&" (SYMBOL-NAME 'NOTFLAGGED) - "=" (FORMAT NIL "~a" NOTFLAGGED)) - "") - (IF ONLYAUDITED - (CONCATENATE 'STRING "&" (SYMBOL-NAME 'ONLYAUDITED) - "=" (FORMAT NIL "~a" ONLYAUDITED)) + (IF PASSWORD2 + (CONCATENATE 'STRING "&" (SYMBOL-NAME 'PASSWORD2) + "=" (FORMAT NIL "~a" PASSWORD2)) "")))))) (IF LAZYBONES-CLIENT.SHARED:*BODY* - (DEXADOR:GET LAZYBONES-CLIENT.SHARED::REQ-STRING :CONTENT + (DEXADOR:POST LAZYBONES-CLIENT.SHARED::REQ-STRING :CONTENT LAZYBONES-CLIENT.SHARED:*BODY* :COOKIE-JAR LAZYBONES-CLIENT.SHARED:*COOKIES* :HEADERS LAZYBONES-CLIENT.SHARED:*HEADERS*) - (DEXADOR:GET LAZYBONES-CLIENT.SHARED::REQ-STRING :COOKIE-JAR + (DEXADOR:POST LAZYBONES-CLIENT.SHARED::REQ-STRING :COOKIE-JAR LAZYBONES-CLIENT.SHARED:*COOKIES* :HEADERS LAZYBONES-CLIENT.SHARED:*HEADERS*)))) diff --git a/src/main.lisp b/src/main.lisp index 6c64ce2..0b33a6e 100644 --- a/src/main.lisp +++ b/src/main.lisp @@ -1,7 +1,8 @@ ;;;; main.lisp -- oneliners.cli entrypoint (defpackage oneliners.cli - (:use :cl)) + (:use :cl) + (:local-nicknames (#:api #:oneliners.api-client))) (in-package :oneliners.cli) ;;; CLI OPTIONS @@ -30,10 +31,7 @@ :arg-parser #'parse-integer) (:name :not-flagged :description "Filter flagged oneliners from the search results" - :long "not-flagged") - (:name :audited-only - :description "Filter unaudited oneliners from the search results" - :long "audited-only")) + :long "not-flagged")) (defparameter +help-suffix+ "Unless RESULT is an integer, search for oneliners that involve each command in COMMANDS. @@ -61,7 +59,7 @@ E.g. (defun last-search-file () (merge-pathnames ".last_oneliners_search" (user-homedir-pathname))) -;;; UTILITIES +;;; RUNNING COMMANDS (defun parent-process-name () "Prints the name of the parent process of the current process." @@ -104,3 +102,16 @@ printed to OUTPUT-STREAM. " (loop while (listen shell-output) do (princ (read-line shell-output) output-stream) (terpri output-stream)))))) + +;;; main + +(defun main () + (handler-case + (multiple-value-bind (options free-args) (opts:get-opts) + (print (list :options options :free-args free-args)) + (terpri) + (uiop:quit)) + (unix-opts:unknown-option (err) + (declare (ignore err)) + (princ (help-text)) + (terpri)))) |