Skip to content

Commit cdc1813

Browse files
committed
init(facebook-example): inizialize app
0 parents  commit cdc1813

File tree

14 files changed

+224
-0
lines changed

14 files changed

+224
-0
lines changed

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# clojure
2+
profiles.clj
3+
.lein-env
4+
pom.properties
5+
6+
# nrepl specific
7+
.nrepl-port
8+
target/

Procfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
web: java $JVM_OPTS -cp target/facebook-example-standalone.jar clojure.main -m facebook-example.core

README.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Facebook Example
2+
3+
A Facebook Messenger Bot Example in Clojure
4+
5+
### Setup
6+
7+
1. Setup a Facebook Page, Facebook app, create a Page Access Token and link the app to the page by following this [step-by-step guide](https://github.com/prometheus-ai/fb-messenger-clj/wiki/Facebook-Setup).
8+
9+
2. Download the repository: [lemmings-io/02-facebook-example](https://github.com/lemmings-io/02-facebook-example/archive/master.zip)
10+
11+
3. Extract it into the `/lemmings/clojure/projects` directory.
12+
13+
4. Start a new VM shell session via `vagrant ssh`
14+
15+
5. In the VM shell change into the facebook-example project directory
16+
17+
cd 02-facebook-example/
18+
19+
6. Run `ngrok http 3000` ([read more about ngrok](https://ngrok.com))
20+
21+
![ngrok Server](resources/doc/images/ngrok.png)
22+
23+
7. Start another new VM shell session via `vagrant ssh`
24+
25+
8. Add your Facebook Page Access Token to your environment
26+
27+
export FB_PAGE_ACCESS_TOKEN="<YOUR_FB_PAGE_ACCESS_TOKEN>"
28+
29+
9. Start the local server
30+
31+
lein ring server-headless
32+
33+
![Lein Server](resources/doc/images/lein-ring-server.png)
34+
35+
Via the [lein-ring doc](https://github.com/weavejester/lein-ring): by default, this command attempts to find a free port, starting at 3000.
36+
37+
10. Visit the https URL as shown in step 4.
38+
E.g. `https://0db8caac.ngrok.io`
39+
40+
If everything went right, you'll see "Hello Lemming :)" in your Browser 🎈
41+
42+
![Hello Lemming](resources/doc/images/welcome-browser.png)
43+
44+
11. In your Facebook Developer App go to "Webhooks" in the left sidebar and add `Callback URL` and `Verify Token` accordingly:
45+
46+
![Webhook Setup](resources/doc/images/webhook-setup.png)
47+
48+
12. Click "Verify and Save" and your app is connected to Facebook's Messenger API 🎈
49+
50+
![Webhook Success](resources/doc/images/webhook-success.png)
51+
52+
13. Go to your Facebook Page and send a message and your bot echo's your input. Congratulations!💧
53+
54+
![Echo Bot](resources/doc/images/echo-bot.png)
55+
56+
Check out the code to find out more 🙂
57+
58+
Note: This clojure app is ready for deployment on Heroku and based on [Heroku's Clojure Getting Started Example](https://github.com/heroku/clojure-getting-started).

project.clj

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
(defproject facebook-example "0.1.0-SNAPSHOT"
2+
:description "Facebook Messenger Bot in Clojure"
3+
:url "http://example.com/FIXME"
4+
:license {:name "Eclipse Public License"
5+
:url "http://www.eclipse.org/legal/epl-v10.html"}
6+
:dependencies [[org.clojure/clojure "1.8.0"]
7+
[org.clojure/data.json "0.2.1"]
8+
[compojure "1.5.1"]
9+
[http-kit "2.2.0"]
10+
[ring/ring-defaults "0.2.1"]
11+
[ring/ring-json "0.4.0"]
12+
[ring/ring-jetty-adapter "1.5.0"]
13+
[environ "1.0.0"]]
14+
:min-lein-version "2.0.0"
15+
:plugins [[lein-ring "0.9.7"]
16+
[environ/environ.lein "0.3.1"]]
17+
:hooks [environ.leiningen.hooks]
18+
:ring {:handler facebook-example.core/app}
19+
:uberjar-name "facebook-example-standalone.jar"
20+
:profiles {:default [:base :dev :user]
21+
#_:production #_{:env {:production false}}})

resources/doc/images/echo-bot.png

48.8 KB
Loading
67.6 KB
Loading

resources/doc/images/ngrok.png

63.7 KB
Loading
126 KB
Loading
150 KB
Loading
22.3 KB
Loading

src/facebook_example/core.clj

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
(ns facebook-example.core
2+
(:require [compojure.core :refer :all]
3+
[compojure.route :as route]
4+
[ring.middleware.defaults :refer :all]
5+
[ring.middleware.json :refer [wrap-json-params]]
6+
[ring.middleware.keyword-params :refer [wrap-keyword-params]]
7+
[facebook-example.facebook :as fb]
8+
; Dependencies via Heroku Example
9+
[compojure.handler :refer [site]]
10+
[clojure.java.io :as io]
11+
[ring.adapter.jetty :as jetty]
12+
[environ.core :refer [env]]))
13+
14+
(defn splash []
15+
{:status 200
16+
:headers {"Content-Type" "text/plain"}
17+
:body "Hello Lemming :)"})
18+
19+
(defroutes fb-routes
20+
(GET "/" [] (splash))
21+
(POST "/webhook" request (fb/route-request request) {:status 200})
22+
(GET "/webhook" request (fb/webhook-is-valid? request)))
23+
24+
(def app
25+
(-> (wrap-defaults fb-routes api-defaults)
26+
(wrap-keyword-params)
27+
(wrap-json-params)))
28+
29+
(defn -main [& args]
30+
(println "Started up"))

src/facebook_example/facebook.clj

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
(ns facebook-example.facebook
2+
(:gen-class)
3+
(:require [clojure.string :as s]
4+
[facebook-example.messages :as msg]))
5+
6+
(defn webhook-is-valid? [request]
7+
(let [params (:params request)]
8+
(println "Incoming Webhook Request:")
9+
(println request)
10+
(if (= true (= (params "hub.mode") "subscribe")
11+
(= (params "hub.verify_token") (System/getenv "FB_PAGE_ACCESS_TOKEN")))
12+
{:status 200 :body (params "hub.challenge")}
13+
{:status 403})))
14+
15+
(defn processText [senderID text]
16+
(cond
17+
(s/includes? (s/lower-case text) "help") (msg/sendTextMessage [senderID "Hi there, happy to help :)"])
18+
(s/includes? (s/lower-case text) "image") (msg/sendImageMessage [senderID "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c5/M101_hires_STScI-PRC2006-10a.jpg/1280px-M101_hires_STScI-PRC2006-10a.jpg"])
19+
(s/includes? (s/lower-case text) "quick reply") (msg/sendQuickReply [senderID])
20+
; If no rules apply echo the user's text input
21+
:else (msg/sendTextMessage [senderID text])))
22+
23+
; Process Received Message Event by Facebook
24+
(defn receivedMessage [event]
25+
(println "Messaging Event:")
26+
(println event)
27+
(let [senderID (get-in event [:sender :id]) recipientID (get-in event [:recipient :id]) timeOfMessage (get-in event [:timestamp]) message (get-in event [:message])]
28+
(println (str "Received message for user " senderID " and page " recipientID " at " timeOfMessage " with message:"))
29+
(println message)
30+
; TODO: Check for text (onText ?), attachments (onAttachments ?)
31+
; or quick_reply (onQuickReply) in :message tree here
32+
; TODO: Simplify function to send a message vs.
33+
; (msg/sendTextMessage (receivedMessage messagingEvent))
34+
(let [messageText (message :text)]
35+
(cond
36+
; Check for :text
37+
(contains? message :text) (processText senderID messageText)
38+
; Check for :attachments
39+
(contains? message :attachments) (msg/sendTextMessage [senderID "Message with attachment received"])))))
40+
41+
(defn route-request [request]
42+
(let [data (get-in request [:params])]
43+
(println "Incoming Request:")
44+
(println request)
45+
(when (= (:object data) "page")
46+
(doseq [pageEntry (:entry data)]
47+
(doseq [messagingEvent (:messaging pageEntry)]
48+
; Check for message (onMessage) or postback (onPostback) here
49+
(cond (contains? messagingEvent :message) (receivedMessage messagingEvent)
50+
(contains? messagingEvent :postback) (msg/sendTextMessage (receivedMessage messagingEvent))
51+
:else (println (str "Webhook received unknown messagingEvent: " messagingEvent))))))))

src/facebook_example/messages.clj

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
(ns facebook-example.messages
2+
(:require [org.httpkit.client :as http]
3+
[clojure.data.json :as json]))
4+
5+
(defn sendAPI [messageData]
6+
(try
7+
(let [response (http/post "https://graph.facebook.com/v2.6/me/messages"
8+
{:query-params {"access_token" (System/getenv "FB_PAGE_ACCESS_TOKEN")}
9+
:headers {"Content-Type" "application/json"}
10+
:body (json/write-str messageData)
11+
:insecure? true})]
12+
(println "Response to FB:")
13+
(println @response))
14+
(catch Exception e (str "caught exception: " (.getMessage e)))))
15+
16+
(defn sendTextMessage [[recipientId messageText]]
17+
(let [messageData {:recipient {:id recipientId} :message {:text messageText}}]
18+
(println messageData)
19+
(sendAPI messageData)))
20+
21+
(defn sendImageMessage [[recipientId imageUrl]]
22+
(let [messageData {:recipient {:id recipientId}
23+
:message {:attachment {:type "image"
24+
:payload {:url imageUrl}}}}]
25+
(println messageData)
26+
(sendAPI messageData)))
27+
28+
(defn sendQuickReply [[recipientId]]
29+
(let [messageData {:recipient {:id recipientId}
30+
:message {:text "What's your favorite movie genre?"
31+
:quick_replies [{:content_type "text"
32+
:title "Action"
33+
:payload "DEVELOPER_DEFINED_PAYLOAD_FOR_PICKING_ACTION"}
34+
{:content_type "text"
35+
:title "Comedy"
36+
:payload "DEVELOPER_DEFINED_PAYLOAD_FOR_PICKING_COMEDY"}
37+
{:content_type "text"
38+
:title "Drama"
39+
:payload "DEVELOPER_DEFINED_PAYLOAD_FOR_PICKING_DRAMA"}]}}]
40+
(println messageData)
41+
(sendAPI messageData)))
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
(ns compojure-bot.handler-test
2+
(:require [clojure.test :refer :all]
3+
[ring.mock.request :as mock]
4+
[compojure-bot.handler :refer :all]))
5+
6+
(deftest test-app
7+
(testing "main route"
8+
(let [response (app (mock/request :get "/"))]
9+
(is (= (:status response) 200))
10+
(is (= (:body response) "Hello World"))))
11+
12+
(testing "not-found route"
13+
(let [response (app (mock/request :get "/invalid"))]
14+
(is (= (:status response) 404)))))

0 commit comments

Comments
 (0)