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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ae7b173896a5f9c90fe0ddb584cdee97044f914ca5d9fa958fb99d4087352bec
4
- data.tar.gz: 4991d2ef06af4fea3cdbc390acfa1727ac39df0532117374245c4d5db0b05fa1
3
+ metadata.gz: 07f64a28ab74c341a147501d87ca332f32d7f7b17ae43525248a8b0761013ff5
4
+ data.tar.gz: 46362b2dab6ae4609988360dd7afbd2a98ce910cf360db1205f5318b3fe4316e
5
5
  SHA512:
6
- metadata.gz: baea9f341a7d4ab9dee90cfdb99e215fbc420f2b6a4de584f13e74bf17cfec37825ef34c65b0c6815f0e90bd77431ff6c032c15adc302521fe20a4ff88dec542
7
- data.tar.gz: 373788d9afe6f9eb005733c89bef79c8d4ace52396da1594dda3fc7bae450c115c9f6444d95e095e736ffd7b90cc388c778f0e92d963fb3a53c6ebbd2e37a93d
6
+ metadata.gz: 235e0542ccb49d34b4751118b2f809a4c4dabf641e68b11a5f9f20641cd51122aa9446811f11de6b6d943edcae4bc426e3e6b4532fdd8a0857112514f14dc69c
7
+ data.tar.gz: 29f8aa12a72cd6d64fc8b2620b228ffdcefd688867bb389015a9781e30a68ca280c79b111cf48c7b75b6ccde3e726df8a9184b3cce35bca5b19fd9d1ea44f523
data/CHANGELOG.md CHANGED
@@ -1,4 +1,6 @@
1
- ## [Unreleased]
1
+ ## [0.1.1] - 2025-02-18
2
+
3
+ - Rebranded and moved permanently to the `telegrama` gem
2
4
 
3
5
  ## [0.1.0] - 2025-02-18
4
6
 
data/README.md CHANGED
@@ -1,124 +1,3 @@
1
- # 💬 `telegrams` a tiny wrapper to send admin Telegram messages
1
+ # You're probably looking for the `telegrama` gem
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/telegrams.svg)](https://badge.fury.io/rb/telegrams)
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)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Telegrams
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.1"
5
5
  end
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 << self
19
- # Returns the configuration object.
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.0
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
- description: Send quick, simple admin / logging Telegram messages via a Telegram bot.
13
- Useful for Rails developers using Telegram messages for notifications, admin alerts,
14
- daily summaries, and status updates. Integrates with the Telegram Bot API.
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: A tiny wrapper to send Telegram admin messages via the Telegram Bot API.
65
+ summary: You're probably looking for the telegrama gem instead
59
66
  test_files: []
@@ -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
@@ -1,3 +0,0 @@
1
- module Telegrams
2
- class Error < StandardError; end
3
- end
@@ -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(/[<>&]/, '<' => '&lt;', '>' => '&gt;', '&' => '&amp;')
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
@@ -1,9 +0,0 @@
1
- module Telegrams
2
- class SendMessageJob < ActiveJob::Base
3
- # No default queue provided here -- it's passed from the job call instead
4
-
5
- def perform(message, options = {})
6
- Client.new.send_message(message, options)
7
- end
8
- end
9
- end