telegrams 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -1
- data/README.md +2 -123
- data/lib/telegrams/version.rb +1 -1
- data/lib/telegrams.rb +2 -36
- metadata +18 -11
- data/lib/telegrams/client.rb +0 -49
- data/lib/telegrams/configuration.rb +0 -103
- data/lib/telegrams/error.rb +0 -3
- data/lib/telegrams/formatter.rb +0 -70
- data/lib/telegrams/send_message_job.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 07f64a28ab74c341a147501d87ca332f32d7f7b17ae43525248a8b0761013ff5
|
4
|
+
data.tar.gz: 46362b2dab6ae4609988360dd7afbd2a98ce910cf360db1205f5318b3fe4316e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 235e0542ccb49d34b4751118b2f809a4c4dabf641e68b11a5f9f20641cd51122aa9446811f11de6b6d943edcae4bc426e3e6b4532fdd8a0857112514f14dc69c
|
7
|
+
data.tar.gz: 29f8aa12a72cd6d64fc8b2620b228ffdcefd688867bb389015a9781e30a68ca280c79b111cf48c7b75b6ccde3e726df8a9184b3cce35bca5b19fd9d1ea44f523
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,124 +1,3 @@
|
|
1
|
-
#
|
1
|
+
# You're probably looking for the `telegrama` gem
|
2
2
|
|
3
|
-
[
|
4
|
-
|
5
|
-
Send quick, simple admin / logging Telegram messages via a Telegram bot.
|
6
|
-
|
7
|
-
I'm making this gem because I'm tired of copy-pasting the same Telegram wrapper from Rails project to Rails project just to send myself admin messages and notifications. The goal with this gem is to provide a straightforward, minimal API to send Telegram messages reliably. All I want to do is this:
|
8
|
-
|
9
|
-
```ruby
|
10
|
-
Telegrams.send_message("Important admin notification!")
|
11
|
-
```
|
12
|
-
|
13
|
-
This is useful for Rails developers using Telegram messages for notifications, admin alerts, errors, logs, daily summaries, and status updates.
|
14
|
-
|
15
|
-
## Quick start
|
16
|
-
|
17
|
-
Add telegrams to your Gemfile:
|
18
|
-
|
19
|
-
```ruby
|
20
|
-
gem 'telegrams'
|
21
|
-
```
|
22
|
-
|
23
|
-
Then run:
|
24
|
-
|
25
|
-
```bash
|
26
|
-
bundle install
|
27
|
-
```
|
28
|
-
|
29
|
-
Then, create an initializer file under `config/initializers/telegrams.rb` and set your credentials:
|
30
|
-
|
31
|
-
```ruby
|
32
|
-
Telegrams.configure do |config|
|
33
|
-
config.bot_token = Rails.application.credentials.dig(Rails.env.to_sym, :telegram, :bot_token)
|
34
|
-
config.chat_id = Rails.application.credentials.dig(Rails.env.to_sym, :telegram, :chat_id)
|
35
|
-
config.default_parse_mode = 'MarkdownV2'
|
36
|
-
|
37
|
-
# Default formatting options
|
38
|
-
config.formatting_options = {
|
39
|
-
escape_markdown: true, # Escape markdown special characters
|
40
|
-
obfuscate_emails: false, # Off by default, enable if needed (it anonymizes email addresses in the message to things like abc...d@gmail.com)
|
41
|
-
escape_html: false, # Optionally escape HTML characters
|
42
|
-
truncate: 4096 # Truncate if message exceeds Telegram's limit (or a custom limit)
|
43
|
-
}
|
44
|
-
|
45
|
-
config.deliver_message_async = false # Enable async message delivery with ActiveJob (enqueue the send_message call to offload message sending from the request cycle)
|
46
|
-
config.deliver_message_queue = 'default' # Use a custom ActiveJob queue
|
47
|
-
end
|
48
|
-
```
|
49
|
-
|
50
|
-
Done!
|
51
|
-
|
52
|
-
You can now send Telegram messages using your bot:
|
53
|
-
|
54
|
-
```ruby
|
55
|
-
Telegrams.send_message("Hey, this is your Rails app speaking via Telegram!")
|
56
|
-
```
|
57
|
-
|
58
|
-
## Advanced options
|
59
|
-
|
60
|
-
### Obfuscate emails in the message
|
61
|
-
|
62
|
-
Sometimes you want to report user actions including a sufficiently identifiable but otherwise anonymous user email. For example, when someone makes gets a refund, you may want to send a message like `john.doe21@email.com got refunded $XX.XX` – but there may be other people / employees in the group chat, so instead of leaking personal, private information, just turn on the `obfuscate_emails` option and the message will automatically get formatted as: `joh...1@email.com got refunded $XX.XX`
|
63
|
-
|
64
|
-
### Overriding defaults with options
|
65
|
-
|
66
|
-
You can pass an options hash to `Telegrams.send_message` to override default behavior on a per‑message basis:
|
67
|
-
|
68
|
-
- **`chat_id`**
|
69
|
-
*Override the default chat ID set in your configuration.*
|
70
|
-
**Usage Example:**
|
71
|
-
```ruby
|
72
|
-
Telegrams.send_message("Hello, alternate group!", chat_id: alternate_chat_id)
|
73
|
-
```
|
74
|
-
|
75
|
-
- **`parse_mode`**
|
76
|
-
*Override the default parse mode (default is `"MarkdownV2"`).*
|
77
|
-
**Usage Example:**
|
78
|
-
```ruby
|
79
|
-
Telegrams.send_message("Hello, world!", parse_mode: "HTML")
|
80
|
-
```
|
81
|
-
|
82
|
-
- **`disable_web_page_preview`**
|
83
|
-
*Enable or disable web page previews (default is `true`).*
|
84
|
-
**Usage Example:**
|
85
|
-
```ruby
|
86
|
-
Telegrams.send_message("Check out this link: https://example.com", disable_web_page_preview: false)
|
87
|
-
```
|
88
|
-
|
89
|
-
- **`formatting`**
|
90
|
-
*A hash that overrides the default formatting options provided in the configuration. Available keys include:*
|
91
|
-
- `escape_markdown` (Boolean): Automatically escape Telegram Markdown special characters.
|
92
|
-
- `obfuscate_emails` (Boolean): Obfuscate email addresses found in the message.
|
93
|
-
- `escape_html` (Boolean): Escape HTML entities.
|
94
|
-
- `truncate` (Integer): Maximum allowed message length (default is `4096`).
|
95
|
-
|
96
|
-
**Usage Example:**
|
97
|
-
```ruby
|
98
|
-
Telegrams.send_message("Contact: john.doe@example.com", formatting: { obfuscate_emails: true })
|
99
|
-
```
|
100
|
-
|
101
|
-
### Asynchronous message delivery
|
102
|
-
|
103
|
-
For production environments or high-traffic applications, you might want to offload message delivery to a background job. Our gem supports asynchronous delivery via ActiveJob.
|
104
|
-
|
105
|
-
With `deliver_message_async` setting enabled, calling:
|
106
|
-
```ruby
|
107
|
-
Telegrams.send_message("Hello asynchronously!")
|
108
|
-
```
|
109
|
-
|
110
|
-
will enqueue a job on the specified queue (`deliver_message_queue`) rather than sending the message immediately.
|
111
|
-
|
112
|
-
## Development
|
113
|
-
|
114
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
115
|
-
|
116
|
-
To install this gem onto your local machine, run `bundle exec rake install`.
|
117
|
-
|
118
|
-
## Contributing
|
119
|
-
|
120
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/rameerez/telegrams. Our code of conduct is: just be nice and make your mom proud of what you do and post online.
|
121
|
-
|
122
|
-
## License
|
123
|
-
|
124
|
-
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
3
|
+
Head to [`telegrama`](https://github.com/rameerez/telegrama)
|
data/lib/telegrams/version.rb
CHANGED
data/lib/telegrams.rb
CHANGED
@@ -1,42 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Require standard libraries that our gem depends on
|
4
|
-
require "net/http"
|
5
|
-
require "uri"
|
6
|
-
require "json"
|
7
|
-
require "cgi"
|
8
|
-
|
9
|
-
# Require our gem files
|
10
|
-
require_relative "telegrams/error"
|
11
3
|
require_relative "telegrams/version"
|
12
|
-
require_relative "telegrams/configuration"
|
13
|
-
require_relative "telegrams/formatter"
|
14
|
-
require_relative "telegrams/client"
|
15
|
-
require_relative "telegrams/send_message_job"
|
16
4
|
|
17
5
|
module Telegrams
|
18
|
-
class
|
19
|
-
|
20
|
-
def configuration
|
21
|
-
@configuration ||= Configuration.new
|
22
|
-
end
|
23
|
-
|
24
|
-
def configure
|
25
|
-
yield(configuration)
|
26
|
-
configuration.validate!
|
27
|
-
end
|
28
|
-
|
29
|
-
# Sends a message using the configured settings.
|
30
|
-
# Before sending, we validate the configuration.
|
31
|
-
# This way, if nothing’s been set up, we get a descriptive error instead of a low-level one.
|
32
|
-
def send_message(message, options = {})
|
33
|
-
configuration.validate!
|
34
|
-
if configuration.deliver_message_async
|
35
|
-
SendMessageJob.set(queue: configuration.deliver_message_queue).perform_later(message, options)
|
36
|
-
else
|
37
|
-
Client.new.send_message(message, options)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
6
|
+
class Error < StandardError; end
|
7
|
+
# Your code goes here...
|
42
8
|
end
|
metadata
CHANGED
@@ -1,17 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: telegrams
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Javi R
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
10
|
date: 2025-02-18 00:00:00.000000000 Z
|
11
|
-
dependencies:
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: telegrama
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - "~>"
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: 0.1.1
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - "~>"
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: 0.1.1
|
26
|
+
description: You're probably looking for the telegrama gem instead
|
15
27
|
email:
|
16
28
|
- rubygems@rameerez.com
|
17
29
|
executables: []
|
@@ -23,11 +35,6 @@ files:
|
|
23
35
|
- README.md
|
24
36
|
- Rakefile
|
25
37
|
- lib/telegrams.rb
|
26
|
-
- lib/telegrams/client.rb
|
27
|
-
- lib/telegrams/configuration.rb
|
28
|
-
- lib/telegrams/error.rb
|
29
|
-
- lib/telegrams/formatter.rb
|
30
|
-
- lib/telegrams/send_message_job.rb
|
31
38
|
- lib/telegrams/version.rb
|
32
39
|
- sig/telegrams.rbs
|
33
40
|
homepage: https://github.com/rameerez/telegrams
|
@@ -55,5 +62,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
55
62
|
requirements: []
|
56
63
|
rubygems_version: 3.6.2
|
57
64
|
specification_version: 4
|
58
|
-
summary:
|
65
|
+
summary: You're probably looking for the telegrama gem instead
|
59
66
|
test_files: []
|
data/lib/telegrams/client.rb
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
module Telegrams
|
2
|
-
class Client
|
3
|
-
def send_message(message, options = {})
|
4
|
-
# Allow chat ID override; fallback to config default
|
5
|
-
chat_id = options.delete(:chat_id) || Telegrams.configuration.chat_id
|
6
|
-
|
7
|
-
# Allow runtime formatting options, merging with configured defaults
|
8
|
-
formatting_opts = options.delete(:formatting) || {}
|
9
|
-
formatted_message = Formatter.format(message, formatting_opts)
|
10
|
-
|
11
|
-
payload = {
|
12
|
-
chat_id: chat_id,
|
13
|
-
text: formatted_message,
|
14
|
-
parse_mode: options[:parse_mode] || Telegrams.configuration.default_parse_mode,
|
15
|
-
disable_web_page_preview: options.fetch(:disable_web_page_preview, true)
|
16
|
-
}
|
17
|
-
|
18
|
-
perform_request(payload)
|
19
|
-
end
|
20
|
-
|
21
|
-
private
|
22
|
-
|
23
|
-
def perform_request(payload)
|
24
|
-
uri = URI("https://api.telegram.org/bot#{Telegrams.configuration.bot_token}/sendMessage")
|
25
|
-
request = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')
|
26
|
-
request.body = payload.to_json
|
27
|
-
|
28
|
-
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
|
29
|
-
http.request(request)
|
30
|
-
end
|
31
|
-
|
32
|
-
unless response.is_a?(Net::HTTPSuccess)
|
33
|
-
error_info = JSON.parse(response.body) rescue {}
|
34
|
-
error_description = error_info["description"] || response.body
|
35
|
-
logger.error("Telegrams API error for chat_id #{payload[:chat_id]}: #{error_description}")
|
36
|
-
raise Error, "Telegram API error for chat_id #{payload[:chat_id]}: #{error_description}"
|
37
|
-
end
|
38
|
-
|
39
|
-
response
|
40
|
-
rescue StandardError => e
|
41
|
-
logger.error("Failed to send Telegram message: #{e.message}")
|
42
|
-
raise Error, "Failed to send Telegram message: #{e.message}"
|
43
|
-
end
|
44
|
-
|
45
|
-
def logger
|
46
|
-
defined?(Rails) && Rails.respond_to?(:logger) ? Rails.logger : Logger.new($stdout)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
@@ -1,103 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Telegrams
|
4
|
-
class Configuration
|
5
|
-
|
6
|
-
# Your Telegram Bot API token
|
7
|
-
attr_accessor :bot_token
|
8
|
-
|
9
|
-
# Default chat ID for sending messages.
|
10
|
-
# You can override this on the fly when sending messages.
|
11
|
-
attr_accessor :chat_id
|
12
|
-
|
13
|
-
# Default parse mode for messages (e.g. "MarkdownV2" or "HTML").
|
14
|
-
attr_accessor :default_parse_mode
|
15
|
-
|
16
|
-
# Whether to disable web page previews by default.
|
17
|
-
attr_accessor :disable_web_page_preview
|
18
|
-
|
19
|
-
# =========================================
|
20
|
-
# Formatting Options
|
21
|
-
# =========================================
|
22
|
-
|
23
|
-
# Formatting options used by the Formatter module.
|
24
|
-
# Available keys:
|
25
|
-
# :escape_markdown (Boolean) - Escape Telegram markdown special characters.
|
26
|
-
# :obfuscate_emails (Boolean) - Obfuscate email addresses found in messages.
|
27
|
-
# :escape_html (Boolean) - Escape HTML entities (<, >, &).
|
28
|
-
# :truncate (Integer) - Maximum allowed message length.
|
29
|
-
attr_accessor :formatting_options
|
30
|
-
|
31
|
-
# Whether to deliver messages asynchronously via ActiveJob.
|
32
|
-
# Defaults to false
|
33
|
-
attr_accessor :deliver_message_async
|
34
|
-
|
35
|
-
# The ActiveJob queue name to use when enqueuing messages.
|
36
|
-
# Defaults to 'default'
|
37
|
-
attr_accessor :deliver_message_queue
|
38
|
-
|
39
|
-
def initialize
|
40
|
-
# Credentials (must be set via initializer)
|
41
|
-
@bot_token = nil
|
42
|
-
@chat_id = nil
|
43
|
-
|
44
|
-
# Defaults for message formatting
|
45
|
-
@default_parse_mode = 'MarkdownV2'
|
46
|
-
@disable_web_page_preview = true
|
47
|
-
|
48
|
-
# Sensible defaults for formatting options.
|
49
|
-
@formatting_options = {
|
50
|
-
escape_markdown: true,
|
51
|
-
obfuscate_emails: false,
|
52
|
-
escape_html: false,
|
53
|
-
truncate: 4096
|
54
|
-
}
|
55
|
-
|
56
|
-
@deliver_message_async = false
|
57
|
-
@deliver_message_queue = 'default'
|
58
|
-
end
|
59
|
-
|
60
|
-
# Validate the configuration.
|
61
|
-
# Raise descriptive errors if required settings are missing or invalid.
|
62
|
-
def validate!
|
63
|
-
validate_bot_token!
|
64
|
-
validate_default_parse_mode!
|
65
|
-
validate_formatting_options!
|
66
|
-
true
|
67
|
-
end
|
68
|
-
|
69
|
-
private
|
70
|
-
|
71
|
-
def validate_bot_token!
|
72
|
-
if bot_token.nil? || bot_token.strip.empty?
|
73
|
-
raise ArgumentError, "Telegrams configuration error: bot_token cannot be blank."
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def validate_default_parse_mode!
|
78
|
-
allowed_modes = ['MarkdownV2', 'HTML', nil]
|
79
|
-
unless allowed_modes.include?(default_parse_mode)
|
80
|
-
raise ArgumentError, "Telegrams configuration error: default_parse_mode must be one of #{allowed_modes.inspect}."
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def validate_formatting_options!
|
85
|
-
unless formatting_options.is_a?(Hash)
|
86
|
-
raise ArgumentError, "Telegrams configuration error: formatting_options must be a hash."
|
87
|
-
end
|
88
|
-
|
89
|
-
%i[escape_markdown obfuscate_emails escape_html].each do |key|
|
90
|
-
if formatting_options.key?(key) && ![true, false].include?(formatting_options[key])
|
91
|
-
raise ArgumentError, "Telegrams configuration error: formatting_options[:#{key}] must be true or false."
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
if formatting_options.key?(:truncate)
|
96
|
-
truncate_val = formatting_options[:truncate]
|
97
|
-
unless truncate_val.is_a?(Integer) && truncate_val.positive?
|
98
|
-
raise ArgumentError, "Telegrams configuration error: formatting_options[:truncate] must be a positive integer."
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
data/lib/telegrams/error.rb
DELETED
data/lib/telegrams/formatter.rb
DELETED
@@ -1,70 +0,0 @@
|
|
1
|
-
module Telegrams
|
2
|
-
module Formatter
|
3
|
-
MARKDOWN_SPECIAL_CHARS = %w[_ * [ ] ( ) ~ ` > # + - = | { } . !].freeze
|
4
|
-
# Characters that should always be escaped in Telegram messages, even when Markdown is enabled
|
5
|
-
ALWAYS_ESCAPE_CHARS = %w[. !].freeze
|
6
|
-
# Characters used for Markdown formatting that need special handling
|
7
|
-
MARKDOWN_FORMAT_CHARS = %w[* _].freeze
|
8
|
-
|
9
|
-
def self.format(text, options = {})
|
10
|
-
# Merge defaults with any runtime overrides
|
11
|
-
defaults = Telegrams.configuration.formatting_options || {}
|
12
|
-
opts = defaults.merge(options)
|
13
|
-
|
14
|
-
text = text.to_s
|
15
|
-
text = obfuscate_emails(text) if opts[:obfuscate_emails]
|
16
|
-
text = escape_html(text) if opts[:escape_html]
|
17
|
-
if opts[:escape_markdown]
|
18
|
-
text = escape_markdown(text)
|
19
|
-
else
|
20
|
-
# When Markdown is enabled (escape_markdown: false), we still need to escape some special characters
|
21
|
-
text = escape_special_chars(text)
|
22
|
-
end
|
23
|
-
text = truncate(text, opts[:truncate]) if opts[:truncate]
|
24
|
-
text
|
25
|
-
end
|
26
|
-
|
27
|
-
def self.escape_markdown(text)
|
28
|
-
MARKDOWN_SPECIAL_CHARS.each do |char|
|
29
|
-
text = text.gsub(/(?<!\\)#{Regexp.escape(char)}/, "\\#{char}")
|
30
|
-
end
|
31
|
-
text
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.escape_special_chars(text)
|
35
|
-
# First escape non-formatting special characters
|
36
|
-
ALWAYS_ESCAPE_CHARS.each do |char|
|
37
|
-
text = text.gsub(/(?<!\\)#{Regexp.escape(char)}/, "\\#{char}")
|
38
|
-
end
|
39
|
-
|
40
|
-
# Then handle formatting characters (* and _) by only escaping them when they're not paired
|
41
|
-
MARKDOWN_FORMAT_CHARS.each do |char|
|
42
|
-
# Count unescaped occurrences
|
43
|
-
count = text.scan(/(?<!\\)#{Regexp.escape(char)}/).count
|
44
|
-
|
45
|
-
if count.odd?
|
46
|
-
# If we have an odd count, escape all occurrences that aren't already escaped
|
47
|
-
text = text.gsub(/(?<!\\)#{Regexp.escape(char)}/, "\\#{char}")
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
text
|
52
|
-
end
|
53
|
-
|
54
|
-
def self.obfuscate_emails(text)
|
55
|
-
text.gsub(/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/) do |email|
|
56
|
-
local, domain = email.split('@')
|
57
|
-
obfuscated_local = local.length > 4 ? "#{local[0..2]}...#{local[-1]}" : "#{local[0]}..."
|
58
|
-
"#{obfuscated_local}@#{domain}"
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def self.escape_html(text)
|
63
|
-
text.gsub(/[<>&]/, '<' => '<', '>' => '>', '&' => '&')
|
64
|
-
end
|
65
|
-
|
66
|
-
def self.truncate(text, max_length)
|
67
|
-
text.length > max_length ? text[0, max_length] : text
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|