Skip to content
Snippets Groups Projects
Commit 9b066764 authored by Cam Saul's avatar Cam Saul
Browse files

fix typo

parent 8adff6ca
Branches
Tags
No related merge requests found
......@@ -180,11 +180,13 @@
Dispatches on the arg annotation as a keyword, and is also passed the symbol
of the argument that should be checked.
(defendpoint GET ... [id.required])
(defendpoint GET ... [id] {id required})
-> (let [id ~(arg-annotation-fn :required id)] ...)
-> (let [id ~(arg-annotation-fn :required id)]
...)
-> (let [id (do (require-params id) id)] ...)"
-> (let [id (do (require-params id) id)]
...)"
(fn [annotation-kw arg-symb]
{:pre [(keyword? annotation-kw)
(symbol? arg-symb)]}
......@@ -194,32 +196,28 @@
(defmethod arg-annotation-fn :default [annotation-kw arg-symbol]
(throw (Exception. (format "Don't know what to do with arg annotation '%s' on arg '%s'!" (name annotation-kw) (name arg-symbol)))))
;; ### defannotation
(defmacro defannotation
"Convenience for defining a new `defendpoint` arg annotation.
BINDING is the actual symbol name of the arg being checked; `defannotation` returns form(s)
that will be included in the let binding for the annotated arg.
(defannotation required [param]
(defannotation Required [param]
`(require-params ~param) ; quasiquoting needed to keep require-params from being evaluated at macroexpansion time
param)"
[annotation-name [binding] & body]
`(defmethod arg-annotation-fn ~(keyword annotation-name) [~'_ ~binding]
`(do ~~@body)))
;; `required` just calls require-params
(defannotation required [param]
`(require-params ~param)
param)
;; ### common annotation definitions
;; `req` is an alias for `required`
(defannotation req [param]
;; `required` just calls require-params
(defannotation Required [param]
`(require-params ~param)
param)
(defannotation int [param]
`(Integer/parseInt ~param))
;;; ### defendpoint
......@@ -229,10 +227,12 @@
- calls `auto-parse` to automatically parse certain args. e.g. `id` is converted from `String` to `Integer` via `Integer/parseInt`
- converts ROUTE from a simple form like `\"/:id\"` to a typed one like `[\"/:id\" :id #\"[0-9]+\"]`
- sequentially applies specified annotation functions on args to validate or cast them.
- executes BODY inside a `try-catch` block that handles `ApiExceptions`
- automatically calls `wrap-response-if-needed` on the result of BODY
- tags function's metadata in a way that subsequent calls to `define-routes` (see below)
will automatically include the function in the generated `defroutes` form."
{:arglists '([method route args annotations-map? & body])}
[method route args & more]
{:pre [(or (string? route)
(vector? route))
......
......@@ -9,6 +9,14 @@
[metabase.util :refer [is-email? select-non-nil-keys]]
[metabase.util.password :as password]))
(defannotation Email [email]
`(check (is-email? ~email) [400 (format ~(str (name email) " '%s' is not a valid email.") ~email)])
email)
(defannotation ComplexPassword [password]
`(check (password/is-complex? ~password) [400 "Insufficient password strength"])
password)
(defendpoint GET "/" []
;; user must be a superuser to proceed
......@@ -26,13 +34,9 @@
(check-403 (or (= id *current-user-id*) (:is_superuser @*current-user*)))
(check-404 (sel :one User :id id)))
(defannotation email [email]
`(require-params ~email)
`(check (is-email? ~email) [400 (format ~(str (name email) " '%s' is not a valid email.") ~email)])
email)
(defendpoint PUT "/:id" [id :as {{:keys [email] :as body} :body}]
{email email}
{email [Required Email]}
;; user must be getting their own details OR they must be a superuser to proceed
(check-403 (or (= id *current-user-id*) (:is_superuser @*current-user*)))
;; can't change email if it's already taken BY ANOTHER ACCOUNT
......@@ -42,13 +46,10 @@
(mapply upd User id)))
(sel :one User :id id))
(defannotation complex-pw [password]
`(check (password/is-complex? ~password) [400 "Insufficient password strength"])
password)
(defendpoint PUT "/:id/password" [id :as {{:keys [password old_password]} :body}]
{password [req complex-pw]
old_password req}
{password [Required ComplexPassword]
old_password Required}
(check-403 (or (= id *current-user-id*)
(:is_superuser @*current-user*)))
(let-404 [user (sel :one [User :password_salt :password] :id id)]
......@@ -56,4 +57,5 @@
(set-user-password id password)
(sel :one User :id id))
(define-routes)
......@@ -176,10 +176,10 @@
(metabase.api.common.internal/auto-parse [id]
(metabase.api.common.internal/catch-api-exceptions
(metabase.api.common.internal/let-annotated-args
{id required}
{id Required}
(clojure.core/-> (do (->404 (sel :one Card :id id)))
metabase.api.common.internal/wrap-response-if-needed))))))
(clojure.core/alter-meta! #'GET_:id clojure.core/assoc :is-endpoint? true))
(defendpoint GET "/:id" [id]
{id required}
{id Required}
(->404 (sel :one Card :id id)))))
......@@ -149,7 +149,7 @@
;; Check that a non-superuser CANNOT update someone else's user details
(expect "You don't have permissions to do that."
((user->client :rasta) :put 403 (str "user/" (user->id :trashbird)) {email "toucan@metabase.com"}))
((user->client :rasta) :put 403 (str "user/" (user->id :trashbird)) {:email "toucan@metabase.com"}))
;; ## PUT /api/user/:id/password
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment