<commit_before>(ns metabase.api.card
  (:require [clojure.data :as data]
            [compojure.core :refer [GET POST DELETE PUT]]
            [korma.core :as k]
            [metabase.events :as events]
            [metabase.api.common :refer :all]
            [metabase.db :refer :all]
            (metabase.models [hydrate :refer [hydrate]]
                             [card :refer [Card] :as card]
                             [card-favorite :refer [CardFavorite]]
                             [card-label :refer [CardLabel]]
                             [common :as common]
                             [database :refer [Database]]
                             [label :refer [Label]]
                             [table :refer [Table]])
            [metabase.util :as u]))

(defannotation CardFilterOption
  "Option must be one of `all`, `mine`, or `fav`."
  [symb value :nillable]
  (checkp-contains? #{:all :mine :fav :database :table} symb (keyword value)))

(defn- hydrate-labels
  "Efficiently hydrate the `Labels` for a large collection of `Cards`."
  [cards]
  (let [card-labels          (sel :many :fields [CardLabel :card_id :label_id])
        label-id->label      (when (seq card-labels)
                               (sel :many :field->obj [Label :id] (k/where {:id [in (set (map :label_id card-labels))]})))
        card-id->card-labels (group-by :card_id card-labels)]
    (for [card cards]
      (assoc card :labels (for [card-label (card-id->card-labels (:id card))] ; TODO - do these need to be sorted ?
                            (label-id->label (:label_id card-label)))))))

(defendpoint GET "/"
  "Get all the `Cards`. With param `f` (default is `all`), restrict cards as follows:

   *  `all`         Return all `Cards`
   *  `mine`        Return all `Cards` created by current user
   *  `fav`         Return all `Cards` favorited by the current user
   *  `database`    Return all `Cards` with `:database_id` equal to `id`
   *  `table`       Return all `Cards` with `:table_id` equal to `id`

   All returned cards must be either created by current user or are publicly visible."
  [f model_id]
  {f CardFilterOption
   model_id Integer}
  (when (contains? #{:database :table} f)
    (checkp (integer? model_id) "id" (format "id is required parameter when filter mode is '%s'" (name f)))
    (case f
      :database (read-check Database model_id)
      :table    (read-check Database (:db_id (sel :one :fields [Table :db_id] :id model_id)))))
  (-> (case (or f :all) ; default value for `f` is `:all`
        :all      (sel :many Card (k/order :name :ASC) (k/where (or {:creator_id *current-user-id*}
                                                                    {:public_perms [> common/perms-none]})))
        :mine     (sel :many Card :creator_id *current-user-id* (k/order :name :ASC))
        :fav      (->> (hydrate (sel :many [CardFavorite :card_id] :owner_id *current-user-id*)
                                :card)
                       (map :card)
                       (sort-by :name))
        :database (sel :many Card (k/order :name :ASC) (k/where (and {:database_id model_id}
                                                                  (or {:creator_id *current-user-id*}
                                                                      {:public_perms [> common/perms-none]}))))
        :table    (sel :many Card (k/order :name :ASC) (k/where (and {:table_id model_id}
                                                                     (or {:creator_id *current-user-id*}
                                                                         {:public_perms [> common/perms-none]})))))
      (hydrate :creator)
      hydrate-labels))

(defendpoint POST "/"
  "Create a new `Card`."
  [:as {{:keys [dataset_query description display name public_perms visualization_settings]} :body}]
  {name         [Required NonEmptyString]
   public_perms [Required PublicPerms]
   display      [Required NonEmptyString]}
  (->> (ins Card
            :creator_id             *current-user-id*
            :dataset_query          dataset_query
            :description            description
            :display                display
            :name                   name
            :public_perms           public_perms
            :visualization_settings visualization_settings)
       (events/publish-event :card-create)))

(defendpoint GET "/:id"<commit_msg>Include `favorite` info with `GET /api/card`<commit_after>(ns metabase.api.card
  (:require [clojure.data :as data]
            [compojure.core :refer [GET POST DELETE PUT]]
            [korma.core :as k]
            [metabase.events :as events]
            [metabase.api.common :refer :all]
            [metabase.db :refer :all]
            (metabase.models [hydrate :refer [hydrate]]
                             [card :refer [Card] :as card]
                             [card-favorite :refer [CardFavorite]]
                             [card-label :refer [CardLabel]]
                             [common :as common]
                             [database :refer [Database]]
                             [label :refer [Label]]
                             [table :refer [Table]])
            [metabase.util :as u]))

(defannotation CardFilterOption
  "Option must be one of `all`, `mine`, or `fav`."
  [symb value :nillable]
  (checkp-contains? #{:all :mine :fav :database :table} symb (keyword value)))

(defn- hydrate-labels
  "Efficiently hydrate the `Labels` for a large collection of `Cards`."
  [cards]
  (let [card-labels          (sel :many :fields [CardLabel :card_id :label_id])
        label-id->label      (when (seq card-labels)
                               (sel :many :field->obj [Label :id] (k/where {:id [in (set (map :label_id card-labels))]})))
        card-id->card-labels (group-by :card_id card-labels)]
    (for [card cards]
      (assoc card :labels (for [card-label (card-id->card-labels (:id card))] ; TODO - do these need to be sorted ?
                            (label-id->label (:label_id card-label)))))))

(defn- hydrate-favorites
  "Efficiently add `favorite` status for a large collection of `Cards`."
  [cards]
  (let [favorite-card-ids (set (sel :many :field [CardFavorite :card_id], :owner_id *current-user-id*, :id [in (map :id cards)]))]
    (for [card cards]
      (assoc card :favorite (contains? favorite-card-ids (:id card))))))

(defn- cards:all []
  (sel :many Card (k/order :name :ASC) (k/where (or {:creator_id *current-user-id*}
                                                    {:public_perms [> common/perms-none]}))))

(defn- cards:mine []
  (sel :many Card :creator_id *current-user-id* (k/order :name :ASC)))

(defn- cards:fav []
  (->> (hydrate (sel :many [CardFavorite :card_id] :owner_id *current-user-id*)
                :card)
       (map :card)
       (sort-by :name)))

(defn- cards:database [database-id]
  (sel :many Card (k/order :name :ASC) (k/where (and {:database_id database-id}
                                                     (or {:creator_id *current-user-id*}
                                                         {:public_perms [> common/perms-none]})))))

(defn- cards:table [table-id]
  (sel :many Card (k/order :name :ASC) (k/where (and {:table_id table-id}
                                                     (or {:creator_id *current-user-id*}
                                                         {:public_perms [> common/perms-none]})))))

(defendpoint GET "/"
  "Get all the `Cards`. With param `f` (default is `all`), restrict cards as follows:

   *  `all`         Return all `Cards`
   *  `mine`        Return all `Cards` created by current user
   *  `fav`         Return all `Cards` favorited by the current user
   *  `database`    Return all `Cards` with `:database_id` equal to `id`
   *  `table`       Return all `Cards` with `:table_id` equal to `id`

   All returned cards must be either created by current user or are publicly visible."
  [f model_id]
  {f CardFilterOption
   model_id Integer}
  (when (contains? #{:database :table} f)
    (checkp (integer? model_id) "id" (format "id is required parameter when filter mode is '%s'" (name f)))
    (case f
      :database (read-check Database model_id)
      :table    (read-check Database (:db_id (sel :one :fields [Table :db_id] :id model_id)))))
  (-> (case (or f :all) ; default value for `f` is `:all`
        :all      (cards:all)
        :mine     (cards:mine)
        :fav      (cards:fav)
        :database (cards:database model_id)
        :table    (cards:table model_id))
      (hydrate :creator)
      hydrate-labels
      hydrate-favorites))

(defendpoint POST "/"
  "Create a new `Card`."
  [:as {{:keys [dataset_query description display name public_perms visualization_settings]} :body}]
  {name         [Required NonEmptyString]
   public_perms [Required PublicPerms]
   display      [Required NonEmptyString]}
  (->> (ins Card
            :creator_id             *current-user-id*
            :dataset_query          dataset_query
            :description            description
            :display                display
            :name                   name
            :public_perms           public_perms
            :visualization_settings visualization_settings)
       (events/publish-event :card-create)))

(defendpoint GET "/:id"
{'fraction_non_alphanumeric': 0.12668521292531565, 'fraction_numerical': 0.0, 'mean_word_length': 1.81875753920386, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 24, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '485065', 'n_tokens_mistral': 2783, 'n_tokens_neox': 2720, 'n_words': 816}