<commit_before>(ns braid.core.client.state.helpers
  (:require
   [braid.core.client.schema :as schema]
   [braid.lib.misc :as misc]
   [cljs-utils.core :refer [flip]]
   [clojure.set :as set]))

(def key-by misc/key-by)

(def key-by-id (partial key-by :id))

(defn order-groups
  "Helper function to impose an order on groups.
  This is a seperate function (instead of inline in :ordered-groups because the
  index route needs to be able to call this to find the first group"
  [groups group-order]
  (if (nil? group-order)
    groups
    (let [ordered? (comp boolean (set group-order) :id)
          {ord true unord false} (group-by ordered? groups)
          by-id (group-by :id groups)]
      (concat
        (remove nil? (map (comp first by-id) group-order))
        unord))))

; ALL HELPERS BELOW SHOULD TAKE STATE AS FIRST ARG

; GETTERS

(defn get-user-preferences [state]
  (get state :preferences))

(defn current-user-id [state]
  (get-in state [:session :user-id]))

(defn ordered-groups [state]
  (order-groups (vals (state :groups)) (get-in state [:preferences :groups-order])))

; SETTERS

; page

(defn set-group-and-page [state group-id page-id]
  (assoc state
    :open-group-id group-id
    :page page-id))

(defn set-page-error [state bool]
  (assoc-in state [:page :error?] bool))

; user

(defn set-preferences [state prefs]
  (update-in state [:preferences] merge prefs))

; users

(defn update-user-avatar [state {:keys [group-id user-id avatar-url]}]
  (assoc-in state [:groups group-id :users user-id :avatar] avatar-url))

; threads and messages

(defn maybe-reset-temp-thread [state thread-id]
  (if (= thread-id (get-in state [:temp-threads (state :open-group-id) :id]))
    (assoc-in state [:temp-threads (state :open-group-id)]
              (schema/make-temp-thread (state :open-group-id)))
    state))

(defn update-thread-last-open-at [state thread-id]
  (if-let [thread (get-in state [:threads thread-id])]
    (let [latest-message (->> (thread :messages)
                              (map :created-at)
                              (reduce max (js/Date. 0)))
          new-last-open (js/Date. (inc (.getTime latest-message)))]
      (update-in state [:threads thread-id :last-open-at] (constantly new-last-open)))
    state))

(defn maybe-create-thread [state thread-id group-id]
  (let [state (update-in state [:user :open-thread-ids] conj thread-id)]
    (if-not (get-in state [:threads thread-id])
      (-> state
          (assoc-in [:threads thread-id] {:id thread-id
                                          :group-id group-id
                                          :messages []
                                          :tag-ids #{}
                                          :mentioned-ids #{}})
          (update-in [:group-threads group-id] #(conj (set %) thread-id)))
      state)))

(defn add-message [state message]
  (-> state
      (maybe-create-thread (message :thread-id) (message :group-id))
      (update-in [:threads (message :thread-id) :messages] conj message)
      (update-thread-last-open-at (message :thread-id))
      (update-in [:threads (message :thread-id) :tag-ids]
                 (partial set/union (set (message :mentioned-tag-ids))))
      (update-in [:threads (message :thread-id) :mentioned-ids]
                 (partial set/union (set (message :mentioned-user-ids))))))

; tags

(defn subscribe-to-tag [state tag-id]
  (update-in state [:user :subscribed-tag-ids] conj tag-id))

(defn add-tags [state tags]
  (update-in state [:tags] merge (key-by-id tags)))

; groups

(defn add-group [state group]
  (-> state
      (assoc-in [:groups (group :id)] group)
      (update-in [:temp-threads] assoc (group :id) (schema/make-temp-thread (group :id)))))

(defn remove-group [state group-id]
  (let [group-threads (get-in state [:group-threads group-id])]
    (-> state
        (update-in [:threads] #(apply dissoc % group-threads))
        (update-in [:group-threads] (flip dissoc group-id))
        (update-in [:groups] (flip dissoc group-id)))))<commit_msg>[core] Fix error due to require of removed lib<commit_after>(ns braid.core.client.state.helpers
  (:require
   [braid.core.client.schema :as schema]
   [braid.lib.misc :as misc]
   [clojure.set :as set]))

(def key-by misc/key-by)

(def key-by-id (partial key-by :id))

(defn order-groups
  "Helper function to impose an order on groups.
  This is a seperate function (instead of inline in :ordered-groups because the
  index route needs to be able to call this to find the first group"
  [groups group-order]
  (if (nil? group-order)
    groups
    (let [ordered? (comp boolean (set group-order) :id)
          {ord true unord false} (group-by ordered? groups)
          by-id (group-by :id groups)]
      (concat
        (remove nil? (map (comp first by-id) group-order))
        unord))))

; ALL HELPERS BELOW SHOULD TAKE STATE AS FIRST ARG

; GETTERS

(defn get-user-preferences [state]
  (get state :preferences))

(defn current-user-id [state]
  (get-in state [:session :user-id]))

(defn ordered-groups [state]
  (order-groups (vals (state :groups)) (get-in state [:preferences :groups-order])))

; SETTERS

; page

(defn set-group-and-page [state group-id page-id]
  (assoc state
    :open-group-id group-id
    :page page-id))

(defn set-page-error [state bool]
  (assoc-in state [:page :error?] bool))

; user

(defn set-preferences [state prefs]
  (update-in state [:preferences] merge prefs))

; users

(defn update-user-avatar [state {:keys [group-id user-id avatar-url]}]
  (assoc-in state [:groups group-id :users user-id :avatar] avatar-url))

; threads and messages

(defn maybe-reset-temp-thread [state thread-id]
  (if (= thread-id (get-in state [:temp-threads (state :open-group-id) :id]))
    (assoc-in state [:temp-threads (state :open-group-id)]
              (schema/make-temp-thread (state :open-group-id)))
    state))

(defn update-thread-last-open-at [state thread-id]
  (if-let [thread (get-in state [:threads thread-id])]
    (let [latest-message (->> (thread :messages)
                              (map :created-at)
                              (reduce max (js/Date. 0)))
          new-last-open (js/Date. (inc (.getTime latest-message)))]
      (update-in state [:threads thread-id :last-open-at] (constantly new-last-open)))
    state))

(defn maybe-create-thread [state thread-id group-id]
  (let [state (update-in state [:user :open-thread-ids] conj thread-id)]
    (if-not (get-in state [:threads thread-id])
      (-> state
          (assoc-in [:threads thread-id] {:id thread-id
                                          :group-id group-id
                                          :messages []
                                          :tag-ids #{}
                                          :mentioned-ids #{}})
          (update-in [:group-threads group-id] #(conj (set %) thread-id)))
      state)))

(defn add-message [state message]
  (-> state
      (maybe-create-thread (message :thread-id) (message :group-id))
      (update-in [:threads (message :thread-id) :messages] conj message)
      (update-thread-last-open-at (message :thread-id))
      (update-in [:threads (message :thread-id) :tag-ids]
                 (partial set/union (set (message :mentioned-tag-ids))))
      (update-in [:threads (message :thread-id) :mentioned-ids]
                 (partial set/union (set (message :mentioned-user-ids))))))

; tags

(defn subscribe-to-tag [state tag-id]
  (update-in state [:user :subscribed-tag-ids] conj tag-id))

(defn add-tags [state tags]
  (update-in state [:tags] merge (key-by-id tags)))

; groups

(defn add-group [state group]
  (-> state
      (assoc-in [:groups (group :id)] group)
      (update-in [:temp-threads] assoc (group :id) (schema/make-temp-thread (group :id)))))

(defn remove-group [state group-id]
  (let [group-threads (get-in state [:group-threads group-id])]
    (-> state
        (update-in [:threads] #(apply dissoc % group-threads))
        (update-in [:group-threads] (misc/flip dissoc group-id))
        (update-in [:groups] (misc/flip dissoc group-id)))))
{'fraction_non_alphanumeric': 0.15366518078256564, 'fraction_numerical': 0.00024764735017335313, 'mean_word_length': 2.5660044150110375, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3735010', 'n_tokens_mistral': 2738, 'n_tokens_neox': 2678, 'n_words': 750}