      :existing-entries (api-common/rep entries)}
     false))
 
+(defn- valid-entry-new-update? [conn ctx org-slug entry-uuid user action-type]
+  (timbre/info "Valid new update for" entry-uuid "from user" (:user-id user) "action" action-type)
+  (if-let* [existing-entry (entry-res/get-entry conn entry-uuid)
+            existing-org (or (:existing-org ctx) (org-res/get-org conn org-slug))
+            existing-board (or (:existing-board ctx) (board-res/get-board conn (:board-uuid existing-entry)))]
+    ;; Merge the existing entry with the new updates
+    (let [user-visibility (or (some (fn [[k v]] (when (= k (-> user :user-id keyword)) v)) (:user-visibility existing-entry))
+                              {})
+          updated-user-visibility (cond
+                                    (= action-type :dismiss)
+                                    (assoc user-visibility :dismiss-at (:data ctx))
+                                    (= action-type :follow)
+                                    (assoc user-visibility :follow true)
+                                    (= action-type :unfollow)
+                                    (assoc user-visibility :follow false))
+          updated-entry (assoc-in existing-entry [:user-visibility (keyword (:user-id user))] updated-user-visibility)
+          dismiss-at (:data ctx)]
+      (timbre/info "User visibility" user-visibility "updated:" updated-user-visibility)
+      (if (and (or (not= action-type :dismiss)
+                   (and (= action-type :dismiss)
+                        (lib-schema/valid? lib-schema/ISO8601 dismiss-at)))
+               (lib-schema/valid? common-res/Entry updated-entry))
+        {:existing-org (api-common/rep existing-org)
+         :existing-board (api-common/rep existing-board)
+         :existing-entry (api-common/rep existing-entry)
+         :updated-entry (api-common/rep updated-entry)}
+        [false, {:updated-entry (api-common/rep updated-entry)}])) ; invalid update
+    
+    true)) ; no existing entry, so this will fail existence check later
+
+(defn- valid-dismiss-all-update? [conn ctx org-slug user]
+  (if-let* [existing-org (or (:existing-org ctx) (org-res/get-org conn org-slug))
+            existing-entries (entry-res/list-all-entries-for-inbox conn (:uuid existing-org) (:user-id user) :asc (db-common/current-timestamp) :before)
+            dismiss-at (:data ctx)
+            updated-entries (map #(let [user-vis (get-in % [:user-visibility (keyword (:user-id user))] {})]
+                                    (assoc-in % [:user-visibility (keyword (:user-id user))] (assoc user-vis :dismiss-at dismiss-at)))
+                              existing-entries)]
+    (if (and (lib-schema/valid? lib-schema/ISO8601 dismiss-at)
+             (every? #(lib-schema/valid? common-res/Entry %) updated-entries))
+      {:existing-org (api-common/rep existing-org)
+       :existing-entries (api-common/rep existing-entries)
+       :updated-entries (api-common/rep updated-entries)}
+      false)
+    
+    true)) ; no existing entry, so this will fail existence check later
+
 ;; ----- Actions -----
 
 (defn- share-entry [conn ctx entry-for]

      (timbre/info "Updated entry for:" entry-for)
      (notification/send-trigger! (notification/->trigger :update org board {:old entry :new final-entry} user nil))
      {:updated-entry (api-common/rep (assoc final-entry :board-name (:name board)))})

    (do (timbre/error "Failed updating entry:" entry-for) false)))


  :handle-unprocessable-entity (fn [ctx]
    (api-common/unprocessable-entity-response (map #(schema/check common-res/FollowUp %) (:follow-ups ctx)))))

(defresource inbox-dismiss-all [conn org-slug]
  (api-common/open-company-authenticated-resource config/passphrase) ; verify validity and presence of required JWToken
  :allowed-methods [:options :post]

  ;; Authorization
  :allowed? (by-method {
    :options true
    :post (fn [ctx] (access/allow-members conn org-slug (:user ctx)))})

  ;; Media type client accepts
  :available-media-types (by-method {
                            :post [mt/entry-media-type]})
  :handle-not-acceptable (by-method {
                            :post (api-common/only-accept 406 mt/entry-media-type)})

  ;; Data handling
  :new? false
  :respond-with-entity? true

  ;; Validations
  :processable? (by-method {
    :options true
    :post (fn [ctx] (valid-dismiss-all-update? conn ctx org-slug (:user ctx)))})

  ;; Possibly no data to handle
  :malformed? (by-method {
    :options false
    :post (fn [ctx] (api-common/malformed-json? ctx true))}) ; allow nil

  ;; Existentialism
  :can-post-to-missing? false
  :exists? (fn [ctx] (if-let* [_slugs? (slugify/valid-slug? org-slug)
                               org (or (:existing-org ctx)
                                       (org-res/get-org conn org-slug))
                               org-uuid (:uuid org)]
                        {:existing-org (api-common/rep org)}
                        false))

  ;; Actions
  :post! (fn [ctx]
           (inbox-dismiss-all conn ctx org-slug))

  :handle-unprocessable-entity (fn [ctx]
    (api-common/unprocessable-entity-response (:updated-entries ctx))))

(defresource inbox [conn org-slug board-slug entry-uuid action-type]
  (api-common/open-company-authenticated-resource config/passphrase) ; verify validity and presence of required JWToken
  :allowed-methods [:options :post]

  ;; Authorization
  :allowed? (by-method {
    :options true
    :post (fn [ctx] (access/allow-members conn org-slug (:user ctx)))})

  ;; Media type client accepts
  :available-media-types (by-method {
                            :post [mt/entry-media-type]})
  :handle-not-acceptable (by-method {
                            :post (api-common/only-accept 406 mt/entry-media-type)})

  ;; Data handling
  :new? false
  :respond-with-entity? true

  ;; Validations
  :processable? (by-method {
    :options true
    :post (fn [ctx] (valid-entry-new-update? conn ctx org-slug entry-uuid (:user ctx) action-type))})

  ;; Possibly no data to handle
  :malformed? (by-method {
    :options false
    :post (fn [ctx] (api-common/malformed-json? ctx true))}) ; allow nil

  ;; Existentialism
  :can-post-to-missing? false
  :exists? (fn [ctx] (if-let* [_slugs? (and (slugify/valid-slug? org-slug)
                                            (slugify/valid-slug? board-slug))
                               org (or (:existing-org ctx)
                                       (org-res/get-org conn org-slug))
                               org-uuid (:uuid org)
                               entry (or (:existing-entry ctx)
                                         (entry-res/get-entry conn entry-uuid))
                               board (board-res/get-board conn (:board-uuid entry))
                               comments (or (:existing-comments ctx)
                                            (entry-res/list-comments-for-entry conn (:uuid entry)))
                               reactions (or (:existing-reactions ctx)
                                             (entry-res/list-reactions-for-entry conn (:uuid entry)))]
                        {:existing-org (api-common/rep org) :existing-board (api-common/rep board)
                         :existing-entry (api-common/rep entry)
                         :existing-comments (api-common/rep comments)
                         :existing-reactions (api-common/rep reactions)}
                        false))

  ;; Actions
  :post! (fn [ctx]
           (update-entry-new conn ctx (s/join " " [org-slug board-slug entry-uuid]) action-type))

  ;; Responses
  :handle-ok (fn [ctx] (entry-rep/render-entry (:existing-org ctx)
                                               (:existing-board ctx)
                                               (:updated-entry ctx)
                                               (:existing-comments ctx)
                                               (reaction-res/aggregate-reactions (:existing-reactions ctx))
                                               (:access-level ctx)
                                               (-> ctx :user :user-id)))
  :handle-unprocessable-entity (fn [ctx]
    (api-common/unprocessable-entity-response (:updated-entry ctx))))

;; ----- Routes -----

(defn routes [sys]
