Can't import ring.middleware.anti-forgery
(ns msa-debugger-clojure.core
(:require
[reagent.core :as r :refer [atom]]
[reagent.session :as session]
[reitit.frontend :as reitit]
[clerk.core :as clerk]
[accountant.core :as accountant]
[reagent-forms.core :refer [bind-fields]]
[reagent-forms.core :as reagent-forms]
[ring.middleware.anti-forgery :as anti-forgery]
))
As said in readme, add dependency to project.clj:
:dependencies [[org.clojure/clojure "1.10.0"]
[ring-server "0.5.0"]
[reagent "0.8.1"]
[reagent-utils "0.3.2"]
[ring "1.7.1"]
[ring/ring-defaults "0.3.2"]
[ring/ring-anti-forgery "1.3.0"]
[hiccup "1.0.5"]
[yogthos/config "1.1.1"]
[org.clojure/clojurescript "1.10.520"
:scope "provided"]
[metosin/reitit "0.2.13"]
[pez/clerk "1.0.0"]
[venantius/accountant "0.2.4"
:exclusions [org.clojure/tools.reader]]
[reagent-forms "0.5.43"]
]
What i am doing wrong? :c
ring is a Clojure library and does not work in ClojureScript.
Related
I cannot get CKEditor react component to work in ClojureScript project.
When I try to use the component
(ns simple.core
(:require [reagent.core :as reagent]
[re-frame.core :as rf]
[clojure.string :as str]
[simple.routes :as routes]
["ckeditor4-react" :as ck :default CKEditor]
))
...
[:> CKEditor]
I get
template.cljs:312 Uncaught Error: Assert failed: Expected React component in: [:> nil]
(in simple.core.ui)
(or (string? comp) (fn? comp))
at Object.reagent$impl$template$vec_to_elem [as vec_to_elem] (template.cljs:312)
at Object.reagent$impl$template$as_element [as as_element] (template.cljs:329)
at template.cljs:403
at core.cljs:5598
at core.cljs:5598
at Object.cljs$core$IKVReduce$_kv_reduce$arity$3 (core.cljs:5602)
at Object.cljs$core$_kv_reduce [as _kv_reduce] (core.cljs:700)
at Object.cljs$core$reduce_kv [as reduce_kv] (core.cljs:2543)
at reagent$impl$template$make_element (template.cljs:401)
at Object.reagent$impl$template$native_element [as native_element] (template.cljs:285)
I have created a simple github project to illustrate.
https://github.com/madhat2r/shadow-re-frame-simple-example
If you clone it and follow instructions in the readme you can reproduce.
Thanks for your help!
Turns out it was an issue with the :require using :default you have to use
["ckeditor4-react" :as CKEditor]
...
[:> CKEditor {:onBeforeLoad (fn [ck] (set! (.-disableAutoInline ck) true))}]
Shadow-cljs: https://shadow-cljs.github.io/docs/UsersGuide.html#_about_default_exports
Note: the onBeforeLoad function above fixes a bug with current version. Left it for anyone who might come across it. https://github.com/ckeditor/ckeditor4-react/issues/57
I am trying to recreate the example in http://react-component.github.io/table/examples/animation.html to add animation to a table in a re-frame app. The table is rendered using antizer which is a ClojureScript library for Ant Design react components. For the animation I'm trying to use rc-animate (as in the example) which is a JavaScript library.
To integrate rc-animate, I followed the official Webpack guide and created a src/js/index.js file:
import Animate from 'rc-animate';
window.Animate = Animate;
My project.clj is:
(defproject ant-table-animation "0.1.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.8.0"]
[org.clojure/clojurescript "1.10.238"]
[reagent "0.8.1"]
[re-frame "0.10.5" :exclusions [reagent]]
[antizer "0.3.1"]]
:plugins [[lein-cljsbuild "1.1.7"]]
:min-lein-version "2.5.3"
:source-paths ["src/clj" "src/cljs"]
:clean-targets ^{:protect false} ["resources/public/js/compiled" "target"]
:figwheel {:css-dirs ["resources/public/css"]}
:profiles
{:dev
{:dependencies [[binaryage/devtools "0.9.10"]
[cider/piggieback "0.3.9"]
[figwheel-sidecar "0.5.16"]
[day8.re-frame/re-frame-10x "0.3.3"]]
:plugins [[lein-figwheel "0.5.16"]]}
:prod { }
}
:cljsbuild
{:builds
[{:id "dev"
:source-paths ["src/cljs"]
:figwheel {:on-jsload "ant-table-animation.core/mount-root"}
:compiler {:closure-defines {re-frame.trace.trace_enabled_QMARK_ true}
:main ant-table-animation.core
:output-to "resources/public/js/compiled/app.js"
:output-dir "resources/public/js/compiled/out"
:asset-path "js/compiled/out"
:source-map-timestamp true
:preloads [devtools.preload, day8.re-frame-10x.preload]
:external-config {:devtools/config {:features-to-install :all}}
:infer-externs true
:npm-deps false
:foreign-libs [{:file "dist/index_bundle.js"
:provides ["rc-animate" "rc-animate-child"]
:global-exports {rc-animate Animate
rc-animate-child AnimateChild}}]
}}
{:id "min"
:source-paths ["src/cljs"]
:compiler {:main ant-table-animation.core
:output-to "resources/public/js/compiled/app.js"
:optimizations :advanced
:closure-defines {goog.DEBUG false}
:pretty-print false}}
]}
)
and in my views.cljs I try to render the table like this:
(ns ant-table-animation.views
(:require
[re-frame.core :as re-frame]
[ant-table-animation.subs :as subs]
[ant-table-animation.events :as events]
[antizer.reagent :as ant]
[reagent.core :as reagent]
[rc-animate]
))
(.log js/console rc-animate)
(defn AnimateBody
[props]
(.createElement
js/React
rc-animate
(.assign js/Object #js {:transitionName "move", :component "tbody"} props)))
(.log js/console AnimateBody)
(defn orders
[]
(let [orders #(re-frame/subscribe [::subs/orders])
width 80]
[ant/table
{:columns
[{:title "Product Name" :dataIndex :product :width width}
{:title "Quantity" :dataIndex :quantity :width width}
{:title "Unit Price" :dataIndex :price :width width}
{:title "Actions" :dataIndex "actions" :width width
:render
#(reagent/as-element
[ant/button
{:icon "delete" :type "danger"
:on-click
(fn []
(re-frame/dispatch [::events/order-deleted (.-product %2)]))}])}]
:dataSource orders
:size "small"
:components {:body {:wrapper AnimateBody}}
:pagination {:page-size 20}
:scroll {:y 300}}]))
(defn main-panel []
(let [name (re-frame/subscribe [::subs/name])]
[:div
[:h1 "Hello from " #name]
[orders]
]))
I am not sure at all about the
(defn AnimateBody
[props]
(.createElement
js/React
rc-animate
(.assign js/Object #js {:transitionName "move", :component "tbody"} props)))
being equivalent to the line from the example
const AnimateBody = props => <Animate transitionName="move" component="tbody" {...props} />;
The table renders correctly, but when I try to delete a row it fails with the following error trace:
react-dom.development.js:55 Uncaught Error: Unable to find node on an unmounted component.
at invariant (react-dom.development.js:55)
at findCurrentFiberUsingSlowPath (react-dom.development.js:4256)
at findCurrentHostFiber (react-dom.development.js:4266)
at findHostInstance (react-dom.development.js:17676)
at Object.findDOMNode (react-dom.development.js:18145)
at AnimateChild.transition (AnimateChild.js:83)
at AnimateChild.componentWillLeave (AnimateChild.js:70)
at performLeave (Animate.js:339)
at Array.forEach (<anonymous>)
at Animate.componentDidUpdate (Animate.js:188)
at commitLifeCycles (react-dom.inc.js:15386)
at commitAllLifeCycles (react-dom.inc.js:16646)
at HTMLUnknownElement.callCallback (react-dom.inc.js:143)
at Object.invokeGuardedCallbackDev (react-dom.inc.js:193)
at invokeGuardedCallback (react-dom.inc.js:250)
at commitRoot (react-dom.inc.js:16800)
at completeRoot (react-dom.inc.js:18192)
at performWorkOnRoot (react-dom.inc.js:18120)
at performWork (react-dom.inc.js:18024)
at performSyncWork (react-dom.inc.js:17996)
at requestWork (react-dom.inc.js:17884)
at scheduleWork (react-dom.inc.js:17689)
at Object.enqueueForceUpdate (react-dom.inc.js:11855)
at Object.Component.forceUpdate (react.inc.js:479)
at reagent$impl$batching$run_queue (batching.cljs?rel=1541330682770:39)
at Object.flush_queues (batching.cljs?rel=1541330682770:86)
at Object.run_queues (batching.cljs?rel=1541330682770:76)
at batching.cljs?rel=1541330682770:63
at re_frame_10x.cljs?rel=1541164419576:125
It is also indicated that:
The above error occurred in the <Animate> component:
in Animate (created by ant_table_animation.views.animateBody)
in ant_table_animation.views.animateBody (created by BaseTable)
in table (created by BaseTable)
in BaseTable (created by Connect(BaseTable))
in Connect(BaseTable) (created by BodyTable)
in div (created by BodyTable)
in BodyTable (created by ExpandableTable)
in div (created by ExpandableTable)
in div (created by ExpandableTable)
in div (created by ExpandableTable)
in ExpandableTable (created by Connect(ExpandableTable))
in Connect(ExpandableTable) (created by Table)
in Provider (created by Table)
in Table (created by LocaleReceiver)
in LocaleReceiver (created by Table)
in div (created by Spin)
in AnimateChild (created by Animate)
in div (created by Animate)
in Animate (created by Spin)
in Spin (created by Table)
in div (created by Table)
in Table (created by ant_table_animation.views.orders)
in ant_table_animation.views.orders (created by ant_table_animation.views.main_panel)
in div (created by ant_table_animation.views.main_panel)
in ant_table_animation.views.main_panel
I am a Clojure beginner, and I know even less for React; this is where I ended up after a week of trying but now I feel stuck. I have uploaded my project in github for anyone that would like to give it a try.
The Unable to find node on an unmounted component error was occurring because of version issues with React. I was able to handle it by explicitly using the version of React used by the rc-animate library - 16.5.2 in my project.clj:
...
[reagent "0.8.1" :exclusions [cljsjs/react cljsjs/react-dom [cljsjs/react-dom-server]]]
[cljsjs/react "16.5.2-0"]
[cljsjs/react-dom "16.5.2-0"]
[cljsjs/react-dom-server "16.5.2-0"]
...
[antizer "0.3.1" :exclusions [cljsjs/react cljsjs/react-dom [cljsjs/react-dom-server]]]]
...
For the correct definition of the AnimateBody component I had to use a combination of reagent/adapt-react-class, reagent/as-element and reagent/reactify-component.
Specifically, in my views.cljs I define the component as:
(def animate (reagent/adapt-react-class rc-animate))
(def animateBody
(fn [props]
(reagent/as-element [animate (assoc props :transition-name "move" :component "tbody")])))
and then pass it to the ant/table component with:
...
:components {:body {:wrapper (reagent/reactify-component animateBody)}}
...
I am trying to learn clojurescript by building a desktop application. The boot configuration I am working with as follows:
(def +name+ "visivo/desktop")
(def +version+ "0.0.1-SNAPSHOPT")
(def +description+ "Desktop application for visivo")
(def +repository+ "https://gitlab.com/visivo/desktop")
(set-env!
:source-paths #{"src/cljs"}
:resource-paths #{"resources"}
:dependencies '[
[org.clojure/clojure "1.9.0-alpha20"]
[org.clojure/clojurescript "1.9.908"]
[org.clojure/tools.nrepl "0.2.12" :scope "test"]
[com.cemerick/piggieback "0.2.2" :scope "test"]
[weasel "0.7.0" :scope "test"]
[adzerk/boot-cljs "2.1.3" :scope "test"]
[adzerk/boot-cljs-repl "0.3.3" :scope "test"]
[adzerk/boot-reload "0.5.2" :scope "test"]
[proto-repl "0.3.1" :scope "test"]
[proto-repl-charts "0.3.2" :scope "test"]
[boot-codox "0.10.3" :scope "test"]])
(require
'[adzerk.boot-cljs :refer [cljs]]
'[adzerk.boot-cljs-repl :refer [cljs-repl start-repl]]
'[adzerk.boot-reload :refer [reload]]
'[codox.boot :refer [codox]])
(task-options!
pom {:project 'visivo/desktop
:version +version+
:description +description+
:url +repository+
:scm {:url +repository+}
:license {"Eclipse Public License"
"http://www.eclipse.org/legal/epl-v10.html"}})
(deftask prod []
(comp (cljs :ids #{"main"}
:optimizations :advanced)
(cljs :ids #{"renderer"}
:optimizations :advanced)))
(deftask dev []
(comp
(speak)
(watch)
(cljs-repl :ids #{"renderer"})
(reload :ids #{"renderer"}
:ws-host "localhost"
:on-jsload 'visivo.renderer/init
:target-path "target")
(cljs :ids #{"renderer"})
(cljs :ids #{"main"}
:compiler-options {:asset-path "target/main.out"
:closure-defines {'visivo.main/dev? true}})
(target)))
(deftask docs []
"Generates documentation for the project from comments"
(comp (codox
:name +name+
:description +description+
:version +version+
:language :clojurescript
:output-path ".")
(target :dir #{"docs"})))
I am willing to add a task to run figwheel. But before doing that I wanted to know whats the difference between using figwheel and (watch and reload) functions as described in dev task?
Here's some quotes about the differences between the two:
figwheel -> https://github.com/adzerk-oss/boot-reload It's not as smart as figwheel because u can lose state, but it's mostly enough. We are actually quite fine with reloading the page manually most of the time.
Figwheel has more bells and whistles but the core functionality should be very similar -- martinklepsch
Figwheel at it's core is the same as what boot-reload can do for you if you develop a Hoplon app
I am trying to use the friend-json-auth library with my app in tandem with compojure instead immutant as they have listed in their example app.
https://github.com/marianoguerra/immutant-recipes/tree/master/friend-json-auth
I am using angular as my client and I make this post request:
this.login = function ( username, password ) { return $http({
method: 'POST',
url: 'http://localhost:3000/api/session',
headers: {
'Content-Type': 'application/json',
'Data-Type': 'json'
},
data: { username : "jane", password : "user_password" }
}) };
but the reponse I get back is
POST http://localhost:3000/api/session 401 (Unauthorized)
Here is my POST endpoint for /api/session:
controller.clj
(ns recursiftion.controller
(:use [ring.adapter.jetty :only [run-jetty]]
[recursiftion.websocket :only [wamp-handler]]
[recursiftion.config :only [conf]]
[ring.middleware params keyword-params nested-params]
[ring.util.response :only (redirect)]
[cemerick.friend.util :only (gets)]
[clojure.data.json :only (read-json json-str)]
)
(:require [compojure.core :refer :all]
[compojure.handler :as handler]
[compojure.route :as route]
[clojure.java.io :as io]
[ring.util.io :refer [string-input-stream]]
[ring.util.response :as resp]
[ring.util.response :refer [response]]
[ring.middleware.json :as middleware]
[ring.middleware.cors :refer [wrap-cors]]
[environ.core :refer [env]]
[cheshire.core :refer :all]
[recursiftion.model :as model]
[clojure.pprint :refer [pprint]]
[cemerick.friend :as friend]
(cemerick.friend [workflows :as workflows]
[credentials :as creds])
[ring.middleware.session :as ring-session]
[marianoguerra.friend-json-workflow :as json-auth]
[ring.middleware.file :as ring-file]
[ring.middleware.file-info :as ring-file-info]))
(defroutes app-routes
(POST "/api/session" request
(let [node_object (or (get-in request [:params :data])
(get-in request [:body :data])
"ROUTER_ERROR")]
(json-auth/handle-session request)))
)
(def app
(-> (handler/api app-routes)
(middleware/wrap-json-body {:keywords? true})
(middleware/wrap-json-response)
(wrap-cors routes #"^http://localhost:9000$")))
(def users {"root" {:username "root"
:password (creds/hash-bcrypt "admin_password")
:roles #{::admin}}
"jane" {:username "jane"
:password (creds/hash-bcrypt "user_password")
:roles #{::user}}})
(def secure-app
(-> app
(friend/authenticate
{:login-uri "/friend-json-auth/api/session"
:unauthorized-handler json-auth/unauthorized-handler
:workflows [(json-auth/json-login
:login-uri "/friend-json-auth/api/session"
:login-failure-handler json-auth/login-failed
:credential-fn (partial creds/bcrypt-credential-fn users))]})
(ring-session/wrap-session)))
(defn -main []
(run-jetty app {:port (if (nil? (System/getenv "PORT"))
8000 ; localhost or heroku?
(Integer/parseInt (System/getenv "PORT")))}) )
project.clj
(defproject helloworld "1.0.0-SNAPSHOT"
:description "csc358 final project"
:url "http://localhost:9000/"
:license {:name "FIXME: choose"
:url "http://example.com/FIXME"}
:dependencies [[org.clojure/clojure "1.7.0"]
[compojure "1.1.8"]
[ring/ring-json "0.3.1"]
[ring/ring-core "1.4.0"]
[ring-router "0.2-SNAPSHOT"]
[ring/ring-jetty-adapter "1.3.2"]
[jumblerg/ring.middleware.cors "1.0.1"]
[c3p0/c3p0 "0.9.1.2"]
[org.clojure/java.jdbc "0.2.3"]
[cheshire "5.4.0"]
[environ "0.2.1"]
[hiccup "1.0.0"]
[clojurewerkz/neocons "3.1.0-rc1"]
[org.clojure/data.json "0.2.5"]
[clj-wamp "1.0.2"]
[clj-http "2.0.0"]
[com.cemerick/friend "0.2.1"]
[org.marianoguerra/friend-json-workflow "0.2.1"]]
:min-lein-version "2.0.0"
:plugins [[environ/environ.lein "0.2.1"]
[lein-ring "0.7.3"]]
:hooks [environ.leiningen.hooks]
:profiles {:dev {:dependencies [[ring-mock "0.1.3"]]}}
:ring {:handler recursiftion.controller/app})
I am very grateful for help you might be able to offer.
On his example client he uses JSON.stringify to pass a JSON string as a map to the AJAX request. In your request you're passing a js object instead of a JSON string as the value of data:
https://github.com/marianoguerra/immutant-recipes/blob/master/friend-json-auth/resources/s/js/app.js
function login(username, password) {
var data = JSON.stringify({"username": username, "password": password});
return $.ajax({
type: "POST",
url: "api/session",
dataType: "json",
contentType: "application/json",
data: data
});
}
I have two files, one html and one css. I have tried to turn them into a heroku app and even used the lein command to create a heroku friendly skeleton and plug these two files in, but cannot get it to work for the life of me. There is something very basic that I don't yet understand about how to coordinate a view with the back-end control. And the hello world tutorials aren't helping me because they do not show me how to do different things or explain what needs to change in my defroutes function, for example, for that to be accomplished. In short, my question is this: How can I coordinate these two files into a Clojure project to make the html render as the front page of a webapp and then deploy it on heroku?
html:
<html>
<head>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<img id="sun" src="http://goo.gl/dEEssP">
<div id='earth-orbit'>
<img id="earth" src="http://goo.gl/o3YWu9">
</div>
</body>
</html>
web.clj file in "lein new heroku ..." project:
(ns solar_system.web
(:require [compojure.core :refer [defroutes GET PUT POST DELETE ANY]]
[compojure.handler :refer [site]]
[compojure.route :as route]
[clojure.java.io :as io]
[ring.middleware.stacktrace :as trace]
[ring.middleware.session :as session]
[ring.middleware.session.cookie :as cookie]
[ring.adapter.jetty :as jetty]
[ring.middleware.basic-authentication :as basic]
[cemerick.drawbridge :as drawbridge]
[environ.core :refer [env]]))
(defn- authenticated? [user pass]
;; TODO: heroku config:add REPL_USER=[...] REPL_PASSWORD=[...]
(= [user pass] [(env :repl-user false) (env :repl-password false)]))
(def ^:private drawbridge
(-> (drawbridge/ring-handler)
(session/wrap-session)
(basic/wrap-basic-authentication authenticated?)))
(defroutes app
(ANY "/repl" {:as req}
(drawbridge req))
(GET "/" []
{:status 200
:headers {"Content-Type" "text/plain"}
:body (pr-str ["Hello" :from 'Heroku])}) ; <= Should I change this part here?
(ANY "*" []
(route/not-found (slurp (io/resource "404.html")))))
(defn wrap-error-page [handler]
(fn [req]
(try (handler req)
(catch Exception e
{:status 500
:headers {"Content-Type" "text/html"}
:body (slurp (io/resource "500.html"))}))))
(defn -main [& [port]]
(let [port (Integer. (or port (env :port) 5000))
;; TODO: heroku config:add SESSION_SECRET=$RANDOM_16_CHARS
store (cookie/cookie-store {:key (env :session-secret)})]
(jetty/run-jetty (-> #'app
((if (env :production)
wrap-error-page
trace/wrap-stacktrace))
(site {:session {:store store}}))
{:port port :join? false})))
;; For interactive development:
;; (.stop server)
;; (def server (-main))
project.clj file
(defproject solar_system "1.0.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://solar_system.herokuapp.com"
:license {:name "FIXME: choose"
:url "http://example.com/FIXME"}
:dependencies [[org.clojure/clojure "1.4.0"]
[compojure "1.1.1"]
[ring/ring-jetty-adapter "1.1.0"]
[ring/ring-devel "1.1.0"]
[ring-basic-authentication "1.0.1"]
[environ "0.2.1"]
[com.cemerick/drawbridge "0.0.6"]]
:min-lein-version "2.0.0"
:plugins [[environ/environ.lein "0.2.1"]]
:hooks [environ.leiningen.hooks]
:profiles {:production {:env {:production true}}})
example of typical handler code that renders text:
(ns hello-world.core
(:use ring.adapter.jetty))
(defn app [req]
{:status 200
:headers {"Content-Type" "text/plain"}
:body "Hello, world"}) ; <= Could I just change this part to slurp in
; the html file and stick it in a file in my
; root directory to get a successful 'git push heroku master'?
Modifying your code:
(defroutes app
(ANY "/repl" {:as req}
(drawbridge req))
(GET "/" []
{:status 200
:headers {"Content-Type" "text/html"} ; change content type
:body (slurp "resources/public/my-file.html")}) ; wherever your file is
(ANY "*" []
(route/not-found (slurp (io/resource "404.html")))))
How I'd write it:
(defroutes app
(ANY "/repl" {:as req} (drawbridge req))
(GET "/" [] (slurp "resources/public/my-file.html")) ; wherever your file is
(route/resources "/") ; special route for serving static files like css
; default root directory is resources/public/
(route/not-found (slurp (io/resource "404.html")))) ; IDK what io/resource does
; you might not need it