<commit_before>(ns metabase.api.common
  "Dynamic variables and utility functions/macros for writing API functions."
  (:require [compojure.core :refer [defroutes]]
            [medley.core :refer :all]
            [metabase.api.common.internal :refer :all]
            [metabase.db :refer :all])
  (:import com.metabase.corvus.api.ApiException))

;;; ## DYNAMIC VARIABLES
;; These get bound by middleware for each HTTP request.

(def ^:dynamic *current-user-id*
  "Int ID or `nil` of user associated with current API call."
  nil)

(def ^:dynamic *current-user*
  "Delay that returns the `User` (or nil) associated with the current API call.
   ex. `@*current-user*`"
  (atom nil)) ; default binding is just something that will return nil when dereferenced


;;; ## GENERAL HELPER FNS / MACROS

;; TODO - move this to something like `metabase.util.debug`
(defmacro with-current-user
  "Primarily for debugging purposes. Evaulates BODY as if `*current-user*` was the User with USER-ID."
  [user-id & body]
  `(binding [*current-user-id* ~user-id
             *current-user* (delay ((sel-fn :one "metabase.models.user/User" :id ~user-id))) ]
     ~@body))

(defmacro org-perms-case
  "Evaluates BODY inside a case statement based on `*current-user*`'s perms for Org with ORG-ID.
   Case will be `nil`, `:default`, or `:admin`."
  [org-id & body]
  `(let [org-id# ~org-id]                                ; make sure org-id gets evaluated before get to `case`
     (case (when *current-user-id*
             (when-let [{:keys [~'admin]} (sel :one ["metabase.models.org-perm/OrgPerm" :admin] :user_id *current-user-id* :organization_id org-id#)]
               (if ~'admin :admin :default)))
       ~@body)))


;;; ## CONDITIONAL RESPONSE FUNCTIONS / MACROS

(defn check
  "Assertion mechanism for use inside API functions.
   Checks that TEST is true, or throws an `ApiException` with STATUS-CODE and MESSAGE.

  This exception is automatically caught in the body of `defendpoint` functions, and the appropriate HTTP response is generated.

  `check` can be called with the form

      (check test code message)

  or with the form

      (check test [code message])

  You can also include multiple tests in a single call:

    (check test1 code1 message1
           test2 code2 message2)"
  ([test code-or-code-message-pair & rest-args]
   (let [[[code message] rest-args] (if (vector? code-or-code-message-pair)
                                      [code-or-code-message-pair rest-args]
                                      [[code-or-code-message-pair (first rest-args)] (rest rest-args)])]
     (when-not test
       (throw (ApiException. (int code) message)))
     (when-not (empty? rest-args)
       (recur (first rest-args) (second rest-args) (drop 2 rest-args))))))
<commit_msg>`check` should return the value of its last result<commit_after>(ns metabase.api.common
  "Dynamic variables and utility functions/macros for writing API functions."
  (:require [compojure.core :refer [defroutes]]
            [medley.core :refer :all]
            [metabase.api.common.internal :refer :all]
            [metabase.db :refer :all])
  (:import com.metabase.corvus.api.ApiException))

;;; ## DYNAMIC VARIABLES
;; These get bound by middleware for each HTTP request.

(def ^:dynamic *current-user-id*
  "Int ID or `nil` of user associated with current API call."
  nil)

(def ^:dynamic *current-user*
  "Delay that returns the `User` (or nil) associated with the current API call.
   ex. `@*current-user*`"
  (atom nil)) ; default binding is just something that will return nil when dereferenced


;;; ## GENERAL HELPER FNS / MACROS

;; TODO - move this to something like `metabase.util.debug`
(defmacro with-current-user
  "Primarily for debugging purposes. Evaulates BODY as if `*current-user*` was the User with USER-ID."
  [user-id & body]
  `(binding [*current-user-id* ~user-id
             *current-user* (delay ((sel-fn :one "metabase.models.user/User" :id ~user-id))) ]
     ~@body))

(defmacro org-perms-case
  "Evaluates BODY inside a case statement based on `*current-user*`'s perms for Org with ORG-ID.
   Case will be `nil`, `:default`, or `:admin`."
  [org-id & body]
  `(let [org-id# ~org-id]                                ; make sure org-id gets evaluated before get to `case`
     (case (when *current-user-id*
             (when-let [{:keys [~'admin]} (sel :one ["metabase.models.org-perm/OrgPerm" :admin] :user_id *current-user-id* :organization_id org-id#)]
               (if ~'admin :admin :default)))
       ~@body)))


;;; ## CONDITIONAL RESPONSE FUNCTIONS / MACROS

(defn check
  "Assertion mechanism for use inside API functions.
   Checks that TEST is true, or throws an `ApiException` with STATUS-CODE and MESSAGE.

  This exception is automatically caught in the body of `defendpoint` functions, and the appropriate HTTP response is generated.

  `check` can be called with the form

      (check test code message)

  or with the form

      (check test [code message])

  You can also include multiple tests in a single call:

    (check test1 code1 message1
           test2 code2 message2)"
  ([test code-or-code-message-pair & rest-args]
   (let [[[code message] rest-args] (if (vector? code-or-code-message-pair)
                                      [code-or-code-message-pair rest-args]
                                      [[code-or-code-message-pair (first rest-args)] (rest rest-args)])]
     (when-not test
       (throw (ApiException. (int code) message)))
     (if (empty? rest-args) test
         (recur (first rest-args) (second rest-args) (drop 2 rest-args))))))

{'fraction_non_alphanumeric': 0.125, 'fraction_numerical': 0.0024964336661911554, 'mean_word_length': 2.839151266255989, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2332666', 'n_tokens_mistral': 1788, 'n_tokens_neox': 1734, 'n_words': 597}