<commit_before>(ns subticket.service
  (:require [clojure.core.async :as a]
            [clojure.spec :as s]
            [environ.core :refer [env]]
            [io.pedestal
             [http :as http]
             [interceptor :refer [IntoInterceptor map->Interceptor]]
             [log :as log]]
            [io.pedestal.http.body-params :as body-params]
            [io.pedestal.interceptor.chain :as chain]
            [ring.middleware.session.cookie :as cookie]
            [subticket dbcon 
             [users :as users]])
  (:import java.lang.Exception
           javax.xml.bind.DatatypeConverter))

(require 'subticket.data-model)

(defn- pipe [from to f]
  (a/go
    (let [v (a/<! from)]
      (a/>! to (f v))
      (a/close! to)))
  to)

(extend-type clojure.lang.Fn
  IntoInterceptor
  (-interceptor [t]
    (map->Interceptor {:enter (fn [context]
                            (let [include-fn (partial assoc context :response)
                                  response (t (:request context))]
                              (if (satisfies? clojure.core.async.impl.protocols/ReadPort response)
                                (pipe response (a/chan 1)  include-fn)
                                (include-fn response))))})))
(defn response [status body & {:as headers}]
  {:status status :body body :headers headers})

(def ok                (partial response 200))
(def bad-request       (partial response 400))
(def server-error      (partial response 500 nil))

(def param-keys [:edn-params :form-params :json-params :path-params :query-params])

(defn- get-params [request] (apply merge (vals (select-keys request param-keys))))
(defn- spec-for [route] (keyword "subticket.data-model" (name route)))

(defn- handle-errors
  [e with-context]
  (if (instance? Exception e)
    (do (log/error :exception e)
        (with-context (server-error)))
    (if-let [body (:client-error e)]
      (do (log/warn :msg body)
          (with-context (bad-request body)))
      (do (log/error :msg e)
          (with-context (server-error))))))

(def default-json
  {:name :default-json
   :enter
   (fn [context]
     (let [request (:request context)
           params (get-params request)
           route (get-in context [:route :route-name])
           errors (s/explain-data (spec-for route) params)]
     (if errors
       (chain/terminate (assoc context :response (bad-request errors)))
       (assoc context ::tmp-request request :request params))))
   :leave
   (fn [context]
     (let [request (::tmp-request context)
           with-context (partial assoc context :request request :response)
           body (:response context)
           e (:exception body)]
       (if e
         (handle-errors e with-context)
         (with-context (ok body)))))})


;; Defines "/" and "/about" routes with their associated :get handlers.
;; The interceptors defined after the verb map (e.g., {:get home-page}
;; apply to / and its children (/about).
(defn json-interceptors [handler] [(body-params/body-params) http/json-body default-json (subticket.dbcon/in-transaction handler)])

;; Tabular routes
(def routes #{["/user/:username" :put (json-interceptors users/add-user-handler) :route-name :add-user]})

;; Map-based routes
;(def routes `{"/" {:interceptors [(body-params/body-params) http/html-body]
;                   :get home-page
;                   "/about" {:get about-page}}})

;; Terse/Vector-based routes
;(def routes
;  `[[["/" {:get home-page}
;      ^:interceptors [(body-params/body-params) http/html-body]
;      ["/about" {:get about-page}]]]])<commit_msg>refactor interceptors.<commit_after>(ns subticket.service
  (:require [clojure.core.async :as a]
            [clojure.spec :as s]
            [environ.core :refer [env]]
            [io.pedestal
             [http :as http]
             [interceptor :refer [IntoInterceptor map->Interceptor]]
             [log :as log]]
            [io.pedestal.http.body-params :as body-params]
            [io.pedestal.interceptor.chain :as chain]
            [ring.middleware.session.cookie :as cookie]
            [subticket dbcon 
             [users :as users]])
  (:import java.lang.Exception
           javax.xml.bind.DatatypeConverter))

(require 'subticket.data-model)

(defn- pipe [from to f]
  (a/go
    (let [v (a/<! from)]
      (a/>! to (f v))
      (a/close! to)))
  to)

(extend-type clojure.lang.Fn
  IntoInterceptor
  (-interceptor [t]
    (map->Interceptor {:enter (fn [context]
                            (let [include-fn (partial assoc context :response)
                                  response (t (:request context))]
                              (if (satisfies? clojure.core.async.impl.protocols/ReadPort response)
                                (pipe response (a/chan 1)  include-fn)
                                (include-fn response))))})))
(defn response [status body & {:as headers}]
  {:status status :body body :headers headers})

(def ok                (partial response 200))
(def bad-request       (partial response 400))
(def server-error      (partial response 500 nil))

(def param-keys [:edn-params :form-params :json-params :path-params :query-params])

(defn- get-params [request] (apply merge (vals (select-keys request param-keys))))
(defn- spec-for [route] (keyword "subticket.data-model" (name route)))

(defn- handle-errors
  [e with-context]
  (if (instance? Exception e)
    (do (log/error :exception e)
        (with-context (server-error)))
    (if-let [body (:client-error e)]
      (do (log/warn :msg body)
          (with-context (bad-request body)))
      (do (log/error :msg e)
          (with-context (server-error))))))

(def validate-request
  {:name :validate-request
   :enter
   (fn [context]
     (let [request (:request context)
           params (get-params request)
           route (get-in context [:route :route-name])
           spec (spec-for route)
           errors (and (s/spec? spec) (s/explain-data spec params))]
       (if errors
         (chain/terminate (assoc context :response (bad-request errors)))
         context)))})

(def params-only
  {:name :params-only
   :enter
   (fn [context]
     (let [request (:request context)
           params (get-params request)]
       (assoc context ::tmp-request request :request params)))
   :leave
   (fn [context] (assoc context :request (::tmp-request context)))})

(def handle-exceptions
  {:name :handle-exceptions
   :leave
   (fn [context]
     (if-let [e (get-in context [:response :exception])]
       (handle-errors e (partial assoc context :response))
       context))})

(def body-response
  {:name :body-response
   :leave
   (fn [context]
     (let [response (:response context)]
       (if (:status response)
         context
         (assoc context :response (ok response)))))})


;; Defines "/" and "/about" routes with their associated :get handlers.
;; The interceptors defined after the verb map (e.g., {:get home-page}
;; apply to / and its children (/about).
(defn unauthenticated-transaction [handler] [(body-params/body-params)
                                             http/json-body
                                             validate-request
                                             body-response
                                             handle-exceptions
                                             params-only
                                             (subticket.dbcon/in-transaction handler)])

;; Tabular routes
(def routes #{["/user/:username" :put (unauthenticated-transaction users/add-user-handler) :route-name :add-user]})

;; Map-based routes
;(def routes `{"/" {:interceptors [(body-params/body-params) http/html-body]
;                   :get home-page
;                   "/about" {:get about-page}}})

;; Terse/Vector-based routes
;(def routes
;  `[[["/" {:get home-page}
;      ^:interceptors [(body-params/body-params) http/html-body]
;      ["/about" {:get about-page}]]]])
{'fraction_non_alphanumeric': 0.142226148409894, 'fraction_numerical': 0.002523977788995457, 'mean_word_length': 2.1510934393638173, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, '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': '2728666', 'n_tokens_mistral': 2415, 'n_tokens_neox': 2328, 'n_words': 651}