Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/Otann/morse
Browse files Browse the repository at this point in the history
  • Loading branch information
i-love-ramen committed Sep 22, 2018
2 parents 3b6b9aa + 35ced71 commit 908b07b
Show file tree
Hide file tree
Showing 8 changed files with 305 additions and 154 deletions.
30 changes: 30 additions & 0 deletions .circleci/config.yml
@@ -0,0 +1,30 @@
version: 2
jobs:
build:
docker:
- image: circleci/clojure:lein-2.7.1
working_directory: ~/repo

environment:
LEIN_ROOT: "true"
JVM_OPTS: -Xmx3200m

steps:
- checkout

- restore_cache:
keys:
- v1-dependencies-{{ checksum "project.clj" }}
# fallback to using the latest cache if no exact match is found
- v1-dependencies-

- run: lein deps

- save_cache:
paths:
- ~/.m2
key: v1-dependencies-{{ checksum "project.clj" }}

- run: lein with-profile test cloverage --codecov

- run: bash <(curl -s https://codecov.io/bash)
38 changes: 25 additions & 13 deletions README.md
@@ -1,6 +1,8 @@
# Morse

[![Circle CI](https://circleci.com/gh/Otann/morse.svg?style=shield&no-cache=2)](https://circleci.com/gh/Otann/morse)
[![Circle CI](https://circleci.com/gh/Otann/morse.svg?style=shield&no-cache=5)](https://circleci.com/gh/Otann/morse)
[![Clojars](https://img.shields.io/clojars/v/morse.svg)](https://clojars.org/morse)
[![codecov](https://codecov.io/gh/Otann/morse/branch/master/graph/badge.svg)](https://codecov.io/gh/Otann/morse)

<img width="30%"
align="right" padding="5px"
Expand All @@ -9,11 +11,10 @@

Morse is a client for [Telegram](https://telegram.org) [Bot API](https://core.telegram.org/bots/api) for the [Clojure](http://clojure.org) programming language.

[![Clojars Project](http://clojars.org/morse/latest-version.svg?&no-cache=6)](https://clojars.org/morse)

## Installation

Add `[morse "0.2.4"]` to the dependency section in your project.clj file.
Add `[morse "0.4.0"]` to the dependency section in your project.clj file.

There is also a template which you can use to bootstrap your project:

Expand All @@ -22,12 +23,12 @@ There is also a template which you can use to bootstrap your project:
export TELEGRAM_TOKEN=...
lein run

## Detecting user's actions
## Detecting user's actions

Telegram sends updates about events in chats in form of
[Update](https://core.telegram.org/bots/api#update) objects.

Inside those there could be commands, inline queries and many more.
Inside those there could be commands, inline queries and many more.
To help you with these Morse provides you helpers and some macros in
`morse.handlers` namespace.

Expand All @@ -38,7 +39,7 @@ you'll find similarities here:
(ns user
(:require [morse.handlers :as h]
[morse.api :as t]))

(def token "YOUR-BIG-SECRET")

; This will define bot-api function, which later could be
Expand All @@ -48,20 +49,20 @@ you'll find similarities here:
; This could be done in form of a function:
(h/command-fn "start" (fn [{{id :id :as chat} :chat}]
(println "Bot joined new chat: " chat)
(t/send-text token id "Welcome!")))
(t/send-text token id "Welcome!")))

; You can use short syntax for same purposes
; Destructuring works same way as in function above
(h/command "help" {{id :id :as chat} :chat}
(println "Help was requested in " chat)
(t/send-text token id "Help is on the way"))

; Handlers will be applied until there are any of those
; returns non-nil result processing update.
; Note that sending stuff to the user returns non-nil

; Note that sending stuff to the user returns non-nil
; response from Telegram API.

; So match-all catch-through case would look something like this:
(h/message message (println "Intercepted message:" message)))

Expand Down Expand Up @@ -101,7 +102,7 @@ in a similar form:
### Callbacks

You can provide handlers for [Callbacks](https://core.telegram.org/bots/api#answercallbackquery)
which are sent from [inline keyboards](https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating)
which are sent from [inline keyboards](https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating)

```clojure
(callback-fn (fn [data] (println "Received callback: " inline)))
Expand Down Expand Up @@ -251,8 +252,19 @@ Sends an answer to an inline query.
:gif_url "http://funnygifs/gif.gif"}])
```

### [`answerCallbackQuery`](https://core.telegram.org/bots/api#answercallbackquery)

Sends an answer to an callback query sent from inline keyboards.

```clojure
(api/answer-callback token
callback-query-id
text
show-alert)
```

## License

Copyright © 2016 Anton Chebotaev
Copyright © 2017 Anton Chebotaev

Distributed under the Eclipse Public License either version 1.0.
21 changes: 10 additions & 11 deletions project.clj
@@ -1,21 +1,23 @@
(defproject morse "0.2.5-SNAPSHOT"
(defproject morse "0.4.0"
:description "Telegram Bot API"

:url "https://github.com/otann/morse/"

:dependencies [[org.clojure/clojure "1.8.0" :scope "provided"]
[org.clojure/tools.macro "0.1.5"]
[org.clojure/core.async "0.2.374"]
[org.clojure/core.async "0.3.465"]
[org.clojure/tools.logging "0.3.1"]
[clj-stacktrace "0.2.8"]
[cheshire "5.5.0"]
[clj-http "2.1.0"]]
[clj-http "3.7.0"]]

:plugins [[lein-cloverage "1.0.10"]]

:profiles {:uberjar {:aot :all}
:dev {:dependencies [[clj-http-fake "1.0.2"]]
:plugins [[com.jakemccrary/lein-test-refresh "0.14.0"]
[com.taoensso/timbre "4.1.4"]
[venantius/ultra "0.4.1"]]}}
:test {:dependencies [[clj-http-fake "1.0.3"]]
:plugins [[pjstadig/humane-test-output "0.8.2"]
[com.jakemccrary/lein-test-refresh "0.14.0"]
[com.taoensso/timbre "4.1.4"]]}}

;; Artifact deployment info
:scm {:name "git"
Expand All @@ -28,10 +30,7 @@
["change" "version" "leiningen.release/bump-version" "release"]
["vcs" "commit"]
["vcs" "tag"]
["deploy" "clojars"]
["change" "version" "leiningen.release/bump-version"]
["vcs" "commit"]
["echo" "-e" "Now run:\\n\\n lein vcs push\\n"]]
["deploy" "clojars"]]

:pom-addition [:developers [:developer
[:name "Anton Chebotaev"]
Expand Down
99 changes: 65 additions & 34 deletions src/morse/api.clj
@@ -1,27 +1,36 @@
(ns morse.api
(:require [clojure.tools.logging :as log]
[clj-http.client :as http]
[clojure.string :as string])
[clojure.string :as string]
[cheshire.core :as json]
[clojure.core.async :as a])
(:import (java.io File)))


(def base-url "https://api.telegram.org/bot")


(defn get-updates
(defn get-updates-async
"Receive updates from Bot via long-polling endpoint"
[token {:keys [limit offset timeout]}]
(let [url (str base-url token "/getUpdates")
query {:timeout (or timeout 1)
:offset (or offset 0)
:limit (or limit 100)}
resp (http/get url {:as :json
:query-params query
:throw-exceptions false})]
(if (-> resp :status (< 300))
(-> resp :body :result)
(log/error "Telegram returned" (:status resp)
"from /getUpdates:" (:body resp)))))
([token {:keys [limit offset timeout]}]
(let [url (str base-url token "/getUpdates")
query {:timeout (or timeout 1)
:offset (or offset 0)
:limit (or limit 100)}
request {:query-params query
:async? true}
result (a/chan)
on-success (fn [resp]
(if-let [data (-> resp :body (json/parse-string true) :result)]
(a/put! result data)
(a/put! result ::error))
(a/close! result))
on-failure (fn [err]
(log/debug err "Exception while getting updates from Telegram API")
(a/put! result ::error)
(a/close! result))]
(http/get url request on-success on-failure)
result)))


(defn set-webhook
Expand All @@ -36,35 +45,45 @@
"Sends message to the chat"
([token chat-id text] (send-text token chat-id {} text))
([token chat-id options text]
(let [url (str base-url token "/sendMessage")
(let [url (str base-url token "/sendMessage")
body (into {:chat_id chat-id :text text} options)
resp (http/post url {:content-type :json
:as :json
:form-params body})]
:as :json
:form-params body})]
(-> resp :body))))

(defn edit-text
"Edits a sent message
(https://core.telegram.org/bots/api#editmessagetext)"
([token chat-id message-id text] (edit-text token chat-id message-id {} text))
([token chat-id message-id options text]
(let [url (str base-url token "/editMessageText")
query (into {:chat_id chat-id :text text :message_id message-id} options)
resp (http/post url {:content-type :json
:as :json
:form-params query})
]
(-> resp :body))))
(let [url (str base-url token "/editMessageText")
query (into {:chat_id chat-id :text text :message_id message-id} options)
resp (http/post url {:content-type :json
:as :json
:form-params query})
]
(-> resp :body))))

(defn delete-text
"Removing a message from the chat"
[token chat-id message-id]
(let [url (str base-url token "/deleteMessage")
query {:chat_id chat-id :message_id message-id}
resp (http/post url {:content-type :json
:as :json
:form-params query})]
(-> resp :body)))

(defn send-file [token chat-id options file method field filename]
"Helper function to send various kinds of files as multipart-encoded"
(let [url (str base-url token method)
base-form [{:part-name "chat_id" :content (str chat-id)}
{:part-name field :content file :name filename}]
(let [url (str base-url token method)
base-form [{:part-name "chat_id" :content (str chat-id)}
{:part-name field :content file :name filename}]
options-form (for [[key value] options]
{:part-name (name key) :content value})
form (into base-form options-form)
resp (http/post url {:as :json :multipart form})]
form (into base-form options-form)
resp (http/post url {:as :json :multipart form})]
(-> resp :body)))


Expand Down Expand Up @@ -134,11 +153,23 @@
"Sends an answer to an inline query"
([token inline-query-id results] (answer-inline token inline-query-id {} results))
([token inline-query-id options results]
(let [url (str base-url token "/answerInlineQuery")
body (into {:inline_query_id inline-query-id :results results} options)
resp (http/post url {:content-type :json
:as :json
:form-params body})]
(let [url (str base-url token "/answerInlineQuery")
body (into {:inline_query_id inline-query-id :results results} options)
resp (http/post url {:content-type :json
:as :json
:form-params body})]
(-> resp :body))))

(defn answer-callback
"Sends an answer to an callback query"
([token callback-query-id] (answer-callback token callback-query-id "" false))
([token callback-query-id text] (answer-callback token callback-query-id text false))
([token callback-query-id text show-alert]
(let [url (str base-url token "/answerCallbackQuery")
body {:callback_query_id callback-query-id :text text :show_alert show-alert}
resp (http/post url {:content-type :json
:as :json
:form-params body})]
(-> resp :body))))

(def telegram-file-api "https://api.telegram.org/file")
Expand Down

0 comments on commit 908b07b

Please sign in to comment.