Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
M
Metabase
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Engineering Digital Service
Metabase
Commits
b6640477
Commit
b6640477
authored
10 years ago
by
Cam Saul
Browse files
Options
Downloads
Patches
Plain Diff
new optional map param check pattern
parent
d27edd08
Branches
Branches containing commit
Tags
Tags containing commit
No related merge requests found
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
src/metabase/api/common.clj
+8
-5
8 additions, 5 deletions
src/metabase/api/common.clj
src/metabase/api/common/internal.clj
+63
-54
63 additions, 54 deletions
src/metabase/api/common/internal.clj
src/metabase/api/user.clj
+5
-3
5 additions, 3 deletions
src/metabase/api/user.clj
with
76 additions
and
62 deletions
src/metabase/api/common.clj
+
8
−
5
View file @
b6640477
...
...
@@ -5,7 +5,8 @@
[
medley.core
:refer
:all
]
[
metabase.api.common.internal
:refer
:all
]
[
metabase.db
:refer
:all
]
[
metabase.db.internal
:refer
[
entity->korma
]])
[
metabase.db.internal
:refer
[
entity->korma
]]
[
metabase.util
:as
u
])
(
:import
com.metabase.corvus.api.ApiException
))
(
declare
check-404
)
...
...
@@ -216,6 +217,9 @@
`
(
require-params
~
param
)
param
)
(
defannotation
int
[
param
]
`
(
Integer/parseInt
~
param
))
;;; ### defendpoint
...
...
@@ -229,19 +233,18 @@
- 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."
[
method
route
args
&
body
]
[
method
route
args
&
more
]
{
:pre
[(
or
(
string?
route
)
(
vector?
route
))
(
vector?
args
)]}
(
let
[
name
(
route-fn-name
method
route
)
route
(
typify-route
route
)
annotated-args
args
args
(
deannotate-args-form
args
)]
[
arg-annotations
body
]
(
u/optional
map?
more
)]
`
(
do
(
def
~
name
(
~
method
~
route
~
args
(
auto-parse
~
args
(
catch-api-exceptions
(
let-annotated-args
~
annotat
ed-arg
s
(
let-annotated-args
~
arg-
annotat
ion
s
(
->
(
do
~@
body
)
wrap-response-if-needed
))))))
(
alter-meta!
#'~
name
assoc
:is-endpoint?
true
))))
...
...
This diff is collapsed.
Click to expand it.
src/metabase/api/common/internal.clj
+
63
−
54
View file @
b6640477
(
ns
metabase.api.common.internal
"Internal functions used by `metabase.api.common`."
(
:require
[
clojure.tools.logging
:as
log
]
[
metabase.util
:
refer
[
fn->
regex?
]
])
[
metabase.util
:
as
u
])
(
:import
com.metabase.corvus.api.ApiException
))
;;; # DEFENDPOINT HELPER FUNCTIONS + MACROS
...
...
@@ -70,7 +70,7 @@
(route-arg-keywords \"/:id/cards\") -> [:id]"
[
route
]
(
->>
(
re-seq
#
":([\w-]+)"
route
)
(
map
(
fn->
second
keyword
))))
(
map
(
u/
fn->
second
keyword
))))
(
defn
typify-args
"Given a sequence of keyword ARGS, return a sequence of `[:arg pattern :arg pattern ...]`
...
...
@@ -151,59 +151,59 @@
;;; ### Args Form Deannotation
(
defn
deannotate-arg
"If FORM is a symbol, strip off any annotations.
;;
(defn deannotate-arg
;;
"If FORM is a symbol, strip off any annotations.
(deannotate-arg 'password.required) -> password"
[
form
]
(
if-not
(
symbol?
form
)
form
(
let
[[
arg
&
_
]
(
clojure.string/split
(
name
form
)
#
"\."
)]
(
symbol
arg
))))
;;
(deannotate-arg 'password.required) -> password"
;;
[form]
;;
(if-not (symbol? form) form
;;
(let [[arg & _] (clojure.string/split (name form) #"\.")]
;;
(symbol arg))))
(
defn
deannotate-args-form
"Walk ARGS-FORM and strip off any annotations.
;;
(defn deannotate-args-form
;;
"Walk ARGS-FORM and strip off any annotations.
(deannotate-args-form [id :as {{:keys [password.required old_password.required]} :body}])
-> [id :as {{:keys [password old_password]} :body}]"
[
args-form
]
(
if
(
=
args-form
[])
'
[
:as
_
]
(
->>
args-form
(
mapv
(
partial
clojure.walk/prewalk
deannotate-arg
)))))
;;
(deannotate-args-form [id :as {{:keys [password.required old_password.required]} :body}])
;;
-> [id :as {{:keys [password old_password]} :body}]"
;;
[args-form]
;;
(if (= args-form []) '[:as _]
;;
(->> args-form
;;
(mapv (partial clojure.walk/prewalk deannotate-arg)))))
;;; ### Args Form Annotation Gathering
(
defn
args-form->symbols
"Recursively walk ARGS-FORM and return a sequence of symbols.
(args-form->symbols [id :as {{:keys [password.required old_password.required]} :body}])
-> (id password.required old_password.required)"
[
args-form
]
{
:post
[(
sequential?
%
)
(
every?
symbol?
%
)]}
(
cond
(
symbol?
args-form
)
[
args-form
]
(
map?
args-form
)
(
->>
args-form
(
mapcat
(
fn
[[
k
v
]]
[(
args-form->symbols
k
)
(
args-form->symbols
v
)]))
(
mapcat
args-form->symbols
))
(
sequential?
args-form
)
(
mapcat
args-form->symbols
args-form
)
:else
[]))
(
defn
symb->arg+annotations
"Return a sequence of pairs of `[annotation-kw deannotated-arg-symb]` for an annotated ARG.
(symb->arg+annotations 'password) -> nil
(symb->arg+annotations 'password.required) -> [[:required password]]
(symb->arg+annotations 'password.required.str) -> [[:required password], [:str password]]"
[
arg
]
{
:pre
[(
symbol?
arg
)]}
(
let
[[
arg
&
annotations
]
(
clojure.string/split
(
name
arg
)
#
"\."
)]
(
when
(
seq
annotations
)
(
->>
annotations
(
map
(
fn
[
annotation
]
[(
keyword
annotation
)
(
symbol
arg
)]))))))
;;
(defn args-form->symbols
;;
"Recursively walk ARGS-FORM and return a sequence of symbols.
;;
(args-form->symbols [id :as {{:keys [password.required old_password.required]} :body}])
;;
-> (id password.required old_password.required)"
;;
[args-form]
;;
{:post [(sequential? %)
;;
(every? symbol? %)]}
;;
(cond
;;
(symbol? args-form) [args-form]
;;
(map? args-form) (->> args-form
;;
(mapcat (fn [[k v]]
;;
[(args-form->symbols k) (args-form->symbols v)]))
;;
(mapcat args-form->symbols))
;;
(sequential? args-form) (mapcat args-form->symbols
;;
args-form)
;;
:else []))
;;
(defn symb->arg+annotations
;;
"Return a sequence of pairs of `[annotation-kw deannotated-arg-symb]` for an annotated ARG.
;;
(symb->arg+annotations 'password) -> nil
;;
(symb->arg+annotations 'password.required) -> [[:required password]]
;;
(symb->arg+annotations 'password.required.str) -> [[:required password], [:str password]]"
;;
[arg]
;;
{:pre [(symbol? arg)]}
;;
(let [[arg & annotations] (clojure.string/split (name arg) #"\.")]
;;
(when (seq annotations)
;;
(->> annotations
;;
(map (fn [annotation]
;;
[(keyword annotation) (symbol arg)]))))))
;;; ### let-annotated-args
...
...
@@ -216,14 +216,23 @@
(
symbol?
arg-symb
)]}
`
[
~
arg-symb
~
((
eval
'metabase.api.common/arg-annotation-fn
)
annotation-kw
arg-symb
)])
(
defn
process-arg-annotations
[
annotations
]
{
:pre
[(
or
(
nil?
annotations
)
(
map?
annotations
))]}
(
some->>
annotations
(
mapcat
(
fn
[[
arg
annotations
]]
(
if
(
sequential?
annotations
)
(
->>
annotations
(
map
keyword
)
(
map
(
u/rpartial
vector
arg
)))
[[(
keyword
annotations
)
arg
]])))
(
mapcat
arg-annotation-let-binding
)))
(
defmacro
let-annotated-args
"Wrap BODY in a let-form that calls corresponding implementations of `arg-annotation-fn` for annotated args in ANNOTATED-ARGS-FORM."
[
annotated-args-form
&
body
]
{
:pre
[(
vector?
annotated-args-form
)]}
(
let
[
annotations
(
->>
annotated-args-form
args-form->symbols
(
mapcat
symb->arg+annotations
)
(
mapcat
arg-annotation-let-binding
))]
[
arg-annotations
&
body
]
{
:pre
[(
or
(
nil?
arg-annotations
)
(
map?
arg-annotations
))]}
(
let
[
annotations
(
process-arg-annotations
arg-annotations
)]
(
if
(
seq
annotations
)
`
(
let
[
~@
annotations
]
~@
body
)
...
...
This diff is collapsed.
Click to expand it.
src/metabase/api/user.clj
+
5
−
3
View file @
b6640477
...
...
@@ -31,7 +31,8 @@
`
(
check
(
is-email?
~
email
)
[
400
(
format
~
(
str
(
name
email
)
" '%s' is not a valid email."
)
~
email
)])
email
)
(
defendpoint
PUT
"/:id"
[
id
:as
{{
:keys
[
email.email
]
:as
body
}
:body
}]
(
defendpoint
PUT
"/:id"
[
id
:as
{{
:keys
[
email
]
:as
body
}
:body
}]
{
email
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
...
...
@@ -45,8 +46,9 @@
`
(
check
(
password/is-complex?
~
password
)
[
400
"Insufficient password strength"
])
password
)
(
defendpoint
PUT
"/:id/password"
[
id
:as
{{
:keys
[
password.req.complex-pw
old_password.req
]}
:body
}]
(
require-params
password
old_password
)
(
defendpoint
PUT
"/:id/password"
[
id
:as
{{
:keys
[
password
old_password
]}
:body
}]
{
password
[
req
complex-pw
]
old_password
req
}
(
check-403
(
or
(
=
id
*current-user-id*
)
(
:is_superuser
@
*current-user*
)))
(
let-404
[
user
(
sel
:one
[
User
:password_salt
:password
]
:id
id
)]
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment