/api/timeline endpoints. | (ns metabase.api.timeline (:require [compojure.core :refer [DELETE GET POST PUT]] [metabase.api.common :as api] [metabase.models.collection :as collection] [metabase.models.collection.root :as collection.root] [metabase.models.timeline :refer [Timeline]] [metabase.models.timeline-event :as timeline-event :refer [TimelineEvent]] [metabase.util :as u] [metabase.util.date-2 :as u.date] [metabase.util.malli.schema :as ms] [toucan2.core :as t2])) |
(set! *warn-on-reflection* true) | |
Events Query Parameters Schema | (def Include [:enum "events"]) |
/ | (api/defendpoint POST "Create a new [[Timeline]]." [:as {{:keys [name default description icon collection_id archived], :as body} :body}] {name ms/NonBlankString default [:maybe :boolean] description [:maybe :string] icon [:maybe timeline-event/Icon] collection_id [:maybe ms/PositiveInt] archived [:maybe :boolean]} (collection/check-write-perms-for-collection collection_id) (let [tl (merge body {:creator_id api/*current-user-id*} (when-not icon {:icon timeline-event/default-icon}))] (first (t2/insert-returning-instances! Timeline tl)))) |
/ | (api/defendpoint GET "Fetch a list of [[Timelines]]. Can include `archived=true` to return archived timelines." [include archived] {include [:maybe Include] archived [:maybe ms/BooleanValue]} (let [archived? archived timelines (->> (t2/select Timeline {:where [:and [:= :archived archived?] (collection/visible-collection-filter-clause)] :order-by [[:%lower.name :asc]]}) (map collection.root/hydrate-root-collection))] (cond->> (t2/hydrate timelines :creator [:collection :can_write]) (= include "events") (map #(timeline-event/include-events-singular % {:events/all? archived?}))))) |
/:id | (api/defendpoint GET "Fetch the [[Timeline]] with `id`. Include `include=events` to unarchived events included on the timeline. Add `archived=true` to return all events on the timeline, both archived and unarchived." [id include archived start end] {id ms/PositiveInt include [:maybe Include] archived [:maybe ms/BooleanValue] start [:maybe ms/TemporalString] end [:maybe ms/TemporalString]} (let [archived? archived timeline (api/read-check (t2/select-one Timeline :id id))] (cond-> (t2/hydrate timeline :creator [:collection :can_write]) ;; `collection_id` `nil` means we need to assoc 'root' collection ;; because hydrate `:collection` needs a proper `:id` to work. (nil? (:collection_id timeline)) collection.root/hydrate-root-collection (= include "events") (timeline-event/include-events-singular {:events/all? archived? :events/start (when start (u.date/parse start)) :events/end (when end (u.date/parse end))})))) |
/:id | (api/defendpoint PUT "Update the [[Timeline]] with `id`. Returns the timeline without events. Archiving a timeline will archive all of the events in that timeline." [id :as {{:keys [name default description icon collection_id archived] :as timeline-updates} :body}] {id ms/PositiveInt name [:maybe ms/NonBlankString] default [:maybe :boolean] description [:maybe :string] icon [:maybe timeline-event/Icon] collection_id [:maybe ms/PositiveInt] archived [:maybe :boolean]} (let [existing (api/write-check Timeline id) current-archived (:archived (t2/select-one Timeline :id id))] (collection/check-allowed-to-change-collection existing timeline-updates) (t2/update! Timeline id (u/select-keys-when timeline-updates :present #{:description :icon :collection_id :default :archived} :non-nil #{:name})) (when (and (some? archived) (not= current-archived archived)) (t2/update! TimelineEvent {:timeline_id id} {:archived archived})) (t2/hydrate (t2/select-one Timeline :id id) :creator [:collection :can_write]))) |
/:id | (api/defendpoint DELETE "Delete a [[Timeline]]. Will cascade delete its events as well." [id] {id ms/PositiveInt} (api/write-check Timeline id) (t2/delete! Timeline :id id) api/generic-204-no-content) |
(api/define-routes) | |