megalabs_sms 0.1.0
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 +7 -0
- data/README.md +113 -0
- data/lib/megalabs_sms/version.rb +5 -0
- data/lib/megalabs_sms.rb +178 -0
- data/spec/megalabs_sms/client_spec.rb +72 -0
- data/spec/spec_helper.rb +11 -0
- metadata +116 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 514e53d5f271af0a42284dd94de370448da8ff6dcafebf05dd140d3f2810f6ee
|
4
|
+
data.tar.gz: 68a2127266570145e574a6df04a2210c29394b51521e6ffdf53566363d98fbc4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 01136beb138bf4639efe0116996d8c20ad3a80d9d6f3bf915df1e2c0f632819f473e40f89f6df8c37996153aba6e3b1efe26ab6c53bd6e7705a189083864a8ae
|
7
|
+
data.tar.gz: 4093d7da0fe27621c8adaf161f0c357b01427becf11e2d73e003a880c59e0b01edfdb305acef2a78d303e017a110adaf82d6abe3dc44d95c562b09dbe341b9ab
|
data/README.md
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
# MegalabsSms
|
2
|
+
|
3
|
+
Простой и удобный гем для отправки SMS через A2P API от Megalabs (Мегафон). Создан для разработчиков, которые хотят быстро и эффективно интегрировать отправку SMS в свои Ruby-приложения.
|
4
|
+
|
5
|
+
## Установка
|
6
|
+
|
7
|
+
Добавьте эту строку в `Gemfile` вашего приложения:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'megalabs_sms'
|
11
|
+
```
|
12
|
+
|
13
|
+
И затем выполните:
|
14
|
+
|
15
|
+
```bash
|
16
|
+
$ bundle install
|
17
|
+
```
|
18
|
+
|
19
|
+
Или установите гем напрямую:
|
20
|
+
|
21
|
+
```bash
|
22
|
+
$ gem install megalabs_sms
|
23
|
+
```
|
24
|
+
|
25
|
+
## Использование
|
26
|
+
|
27
|
+
### Базовый пример
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
require 'megalabs_sms'
|
31
|
+
|
32
|
+
# Создаем клиент
|
33
|
+
client = MegalabsSms::Client.new(
|
34
|
+
'ваш_логин',
|
35
|
+
'ваш_пароль'
|
36
|
+
)
|
37
|
+
|
38
|
+
# Отправляем SMS
|
39
|
+
client.send_sms(
|
40
|
+
'SenderName', # имя отправителя
|
41
|
+
'+79001234567', # номер получателя
|
42
|
+
'Привет! Это тестовое сообщение.' # текст сообщения
|
43
|
+
)
|
44
|
+
```
|
45
|
+
|
46
|
+
### Дополнительные возможности
|
47
|
+
|
48
|
+
#### Задержка между запросами
|
49
|
+
|
50
|
+
Если вам нужно добавить задержку между запросами (например, чтобы не превысить лимиты API):
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
client = MegalabsSms::Client.new(
|
54
|
+
'ваш_логин',
|
55
|
+
'ваш_пароль',
|
56
|
+
sleep_time: 1.0 # задержка в 1 секунду между запросами
|
57
|
+
)
|
58
|
+
```
|
59
|
+
|
60
|
+
#### Тестовый режим
|
61
|
+
|
62
|
+
Для тестирования можно использовать режим эмуляции:
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
# Эмуляция успешной отправки
|
66
|
+
client = MegalabsSms::Client.new(
|
67
|
+
'ваш_логин',
|
68
|
+
'ваш_пароль',
|
69
|
+
success_stub: true
|
70
|
+
)
|
71
|
+
|
72
|
+
# Эмуляция ошибки отправки
|
73
|
+
client = MegalabsSms::Client.new(
|
74
|
+
'ваш_логин',
|
75
|
+
'ваш_пароль',
|
76
|
+
error_stub: true
|
77
|
+
)
|
78
|
+
```
|
79
|
+
|
80
|
+
## Обработка ошибок
|
81
|
+
|
82
|
+
Гем автоматически обрабатывает различные ошибки и возвращает понятные сообщения:
|
83
|
+
|
84
|
+
- При отсутствии учетных данных
|
85
|
+
- При проблемах с сетью
|
86
|
+
- При ошибках API
|
87
|
+
- При проблемах с форматом данных
|
88
|
+
|
89
|
+
## Разработка
|
90
|
+
|
91
|
+
После клонирования репозитория, установите зависимости:
|
92
|
+
|
93
|
+
```bash
|
94
|
+
$ bundle install
|
95
|
+
```
|
96
|
+
|
97
|
+
Запуск тестов:
|
98
|
+
|
99
|
+
```bash
|
100
|
+
$ bundle exec rspec
|
101
|
+
```
|
102
|
+
|
103
|
+
## Лицензия
|
104
|
+
|
105
|
+
Гем доступен как open source под лицензией MIT.
|
106
|
+
|
107
|
+
## Поддержка
|
108
|
+
|
109
|
+
Если у вас возникли вопросы или проблемы, пожалуйста, создайте issue в репозитории проекта.
|
110
|
+
|
111
|
+
## Автор
|
112
|
+
|
113
|
+
- Vitalii Dementev - [@DementevVV](https://github.com/DementevVV)
|
data/lib/megalabs_sms.rb
ADDED
@@ -0,0 +1,178 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'json'
|
5
|
+
require_relative 'megalabs_sms/version'
|
6
|
+
|
7
|
+
#
|
8
|
+
# Главный модуль для взаимодействия с API Megalabs, включая отправку SMS.
|
9
|
+
#
|
10
|
+
module MegalabsSms
|
11
|
+
# Класс для взаимодействия с API Megalabs для отправки SMS
|
12
|
+
class Client
|
13
|
+
#
|
14
|
+
# Конструктор, инициализирующий параметры клиента:
|
15
|
+
#
|
16
|
+
# @param api_user [String] логин для Basic Auth
|
17
|
+
# @param api_password [String] пароль для Basic Auth
|
18
|
+
# @param sleep_time [Float] время задержки в секундах (по умолчанию 0)
|
19
|
+
# @param success_stub [Boolean] эмулировать успешную отправку?
|
20
|
+
# @param error_stub [Boolean] эмулировать ошибку отправки?
|
21
|
+
#
|
22
|
+
# @raise [ArgumentError] если api_user или api_password отсутствуют или пусты
|
23
|
+
#
|
24
|
+
def initialize(api_user,
|
25
|
+
api_password,
|
26
|
+
sleep_time: 0,
|
27
|
+
success_stub: false,
|
28
|
+
error_stub: false)
|
29
|
+
raise ArgumentError, 'api_user is required' if api_user.nil? || api_user.strip.empty?
|
30
|
+
raise ArgumentError, 'api_password is required' if api_password.nil? || api_password.strip.empty?
|
31
|
+
|
32
|
+
@api_user = api_user
|
33
|
+
@api_password = api_password
|
34
|
+
@sleep_time = sleep_time
|
35
|
+
@success_stub = success_stub
|
36
|
+
@error_stub = error_stub
|
37
|
+
end
|
38
|
+
|
39
|
+
#
|
40
|
+
# Метод для форматирования сообщений логирования
|
41
|
+
#
|
42
|
+
# @param message [String] исходное сообщение для логирования
|
43
|
+
#
|
44
|
+
# @return [String] отформатированное сообщение с префиксом модуля
|
45
|
+
#
|
46
|
+
def log_message(message)
|
47
|
+
"[MegalabsSms] #{message}"
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Метод для отправки SMS через сервис Megalabs.
|
52
|
+
#
|
53
|
+
# @param from [String] имя/номер отправителя
|
54
|
+
# @param to [String] номер телефона получателя
|
55
|
+
# @param message [String] текст сообщения
|
56
|
+
#
|
57
|
+
# @return [String] статус отправки или текст ошибки
|
58
|
+
#
|
59
|
+
def send_sms(from, to, message)
|
60
|
+
return handle_stub_response if stub_enabled?
|
61
|
+
|
62
|
+
request = build_request(from, to, message)
|
63
|
+
send_request(request)
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
#
|
69
|
+
# Проверяет, включен ли режим эмуляции ответов
|
70
|
+
#
|
71
|
+
# @return [Boolean] true если включена эмуляция успеха или ошибки, false в противном случае
|
72
|
+
#
|
73
|
+
def stub_enabled?
|
74
|
+
@error_stub || @success_stub
|
75
|
+
end
|
76
|
+
|
77
|
+
#
|
78
|
+
# Обрабатывает эмуляцию ответов
|
79
|
+
#
|
80
|
+
# @return [String] сообщение об успехе или ошибке эмуляции
|
81
|
+
#
|
82
|
+
def handle_stub_response
|
83
|
+
return log_message('Stubbed error: SMS not sent') if @error_stub
|
84
|
+
|
85
|
+
log_message('Stubbed success: SMS would be sent') if @success_stub
|
86
|
+
end
|
87
|
+
|
88
|
+
#
|
89
|
+
# Создает HTTP-запрос для отправки SMS
|
90
|
+
#
|
91
|
+
# @param from [String] имя отправителя
|
92
|
+
# @param to [String] номер телефона получателя
|
93
|
+
# @param message [String] текст сообщения
|
94
|
+
#
|
95
|
+
# @return [Net::HTTP::Post] объект HTTP-запроса
|
96
|
+
#
|
97
|
+
def build_request(from, to, message)
|
98
|
+
uri = URI('https://a2p-api.megalabs.ru/sms/v1/sms')
|
99
|
+
request = Net::HTTP::Post.new(uri)
|
100
|
+
request.basic_auth(@api_user, @api_password)
|
101
|
+
request.content_type = 'application/json'
|
102
|
+
request.body = build_request_body(from, to, message)
|
103
|
+
request
|
104
|
+
end
|
105
|
+
|
106
|
+
#
|
107
|
+
# Создает HTTP-запрос для отправки SMS
|
108
|
+
#
|
109
|
+
# @param from [String] имя/номер отправителя
|
110
|
+
# @param to [String] <description>
|
111
|
+
# @param message [String] <description>
|
112
|
+
#
|
113
|
+
# @return [Net::HTTP::Post] объект HTTP-запроса
|
114
|
+
#
|
115
|
+
def build_request_body(from, to, message)
|
116
|
+
{
|
117
|
+
from: from,
|
118
|
+
to: to.gsub(/\D/, '').to_i,
|
119
|
+
message: message
|
120
|
+
}.to_json
|
121
|
+
end
|
122
|
+
|
123
|
+
#
|
124
|
+
# Отправляет HTTP-запрос
|
125
|
+
#
|
126
|
+
# @param request [Net::HTTP::Post] объект HTTP-запроса
|
127
|
+
#
|
128
|
+
# @return [String] тело ответа или сообщение об ошибке
|
129
|
+
#
|
130
|
+
def send_request(request)
|
131
|
+
uri = URI('https://a2p-api.megalabs.ru/sms/v1/sms')
|
132
|
+
response_body = perform_http_request(uri, request)
|
133
|
+
sleep(@sleep_time) if @sleep_time.positive?
|
134
|
+
response_body
|
135
|
+
end
|
136
|
+
|
137
|
+
#
|
138
|
+
# Выполняет HTTP-запрос
|
139
|
+
#
|
140
|
+
# @param uri [URI] URI-адрес для запроса
|
141
|
+
# @param request [Net::HTTP::Post] объект HTTP-запроса
|
142
|
+
#
|
143
|
+
# @return [String] тело ответа или сообщение об ошибке
|
144
|
+
#
|
145
|
+
def perform_http_request(uri, request)
|
146
|
+
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
|
147
|
+
http.request(request)
|
148
|
+
end
|
149
|
+
|
150
|
+
if response.is_a?(Net::HTTPSuccess)
|
151
|
+
process_http_response(response.body)
|
152
|
+
else
|
153
|
+
log_message("Failed to send: #{response}")
|
154
|
+
end
|
155
|
+
rescue StandardError => e
|
156
|
+
log_message("Exception occurred: #{e.message}")
|
157
|
+
end
|
158
|
+
|
159
|
+
#
|
160
|
+
# Обрабатывает тело ответа HTTP и возвращает корректное сообщение.
|
161
|
+
# Если статус ответа не соответствует ожидаемому, возвращает сообщение об ошибке.
|
162
|
+
#
|
163
|
+
# @param raw_body [String] оригинальный ответ от HTTP-запроса
|
164
|
+
#
|
165
|
+
# @return [String] либо оригинальное тело (если все хорошо), либо сообщение об ошибке
|
166
|
+
#
|
167
|
+
def process_http_response(raw_body)
|
168
|
+
body = raw_body.dup.force_encoding('UTF-8')
|
169
|
+
parsed = JSON.parse(body)
|
170
|
+
result = parsed.dig('result', 'status')
|
171
|
+
return body if result&.fetch('code', nil)&.zero? && result&.fetch('description', '')&.downcase == 'ok'
|
172
|
+
|
173
|
+
log_message("Failed to send: #{body}")
|
174
|
+
rescue JSON::ParserError => e
|
175
|
+
log_message("Failed to parse JSON: #{e.message}")
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
# rubocop:disable Metrics/BlockLength
|
6
|
+
|
7
|
+
RSpec.describe MegalabsSms::Client do
|
8
|
+
let(:api_user) { 'test_user' }
|
9
|
+
let(:api_password) { 'test_password' }
|
10
|
+
let(:sleep_time) { 0 }
|
11
|
+
let(:from) { 'TestSender' }
|
12
|
+
let(:to) { '+70001234567' }
|
13
|
+
let(:message) { 'Hello from RSpec!' }
|
14
|
+
|
15
|
+
subject(:client) do
|
16
|
+
described_class.new(
|
17
|
+
api_user,
|
18
|
+
api_password,
|
19
|
+
sleep_time: sleep_time,
|
20
|
+
success_stub: success_stub,
|
21
|
+
error_stub: error_stub
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with stub responses' do
|
26
|
+
context 'when success_stub is true' do
|
27
|
+
let(:success_stub) { true }
|
28
|
+
let(:error_stub) { false }
|
29
|
+
|
30
|
+
it 'returns a success message (stub)' do
|
31
|
+
result = client.send_sms(from, to, message)
|
32
|
+
expect(result).to eq('[MegalabsSms] Stubbed success: SMS would be sent')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when error_stub is true' do
|
37
|
+
let(:success_stub) { false }
|
38
|
+
let(:error_stub) { true }
|
39
|
+
|
40
|
+
it 'returns an error message (stub)' do
|
41
|
+
result = client.send_sms(from, to, message)
|
42
|
+
expect(result).to eq('[MegalabsSms] Stubbed error: SMS not sent')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'with real HTTP request' do
|
48
|
+
let(:success_stub) { false }
|
49
|
+
let(:error_stub) { false }
|
50
|
+
let(:valid_response) do
|
51
|
+
'{"result":{"msg_id":"id","status":{"code":0,"description":"ok"}}}'
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'makes an HTTP request' do
|
55
|
+
stub_request(:post, 'https://a2p-api.megalabs.ru/sms/v1/sms')
|
56
|
+
.to_return(status: 200, body: valid_response, headers: { 'Content-Type': 'application/json' })
|
57
|
+
|
58
|
+
result = client.send_sms(from, to, message)
|
59
|
+
expect(result).to eq(valid_response)
|
60
|
+
expect(WebMock).to have_requested(:post, 'https://a2p-api.megalabs.ru/sms/v1/sms')
|
61
|
+
.with(body: {
|
62
|
+
from: from,
|
63
|
+
# rubocop:disable Style/NumericLiterals
|
64
|
+
to: 70001234567,
|
65
|
+
# rubocop:enable Style/NumericLiterals
|
66
|
+
message: message
|
67
|
+
}.to_json)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# rubocop:enable Metrics/BlockLength
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: megalabs_sms
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Vitalii Dementev
|
8
|
+
bindir: bin
|
9
|
+
cert_chain: []
|
10
|
+
date: 2025-03-13 00:00:00.000000000 Z
|
11
|
+
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: net-http
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - "~>"
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: 0.6.0
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - "~>"
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: 0.6.0
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: ostruct
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.6.0
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 0.6.0
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: rspec
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
type: :development
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: webmock
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
type: :development
|
62
|
+
prerelease: false
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
name: yard
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
type: :development
|
76
|
+
prerelease: false
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
description: This gem provides a simple interface to send SMS using the Megalabs A2P
|
83
|
+
API.
|
84
|
+
email:
|
85
|
+
- v@dementev.dev
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- README.md
|
91
|
+
- lib/megalabs_sms.rb
|
92
|
+
- lib/megalabs_sms/version.rb
|
93
|
+
- spec/megalabs_sms/client_spec.rb
|
94
|
+
- spec/spec_helper.rb
|
95
|
+
homepage: https://github.com/DementevVV/megalabs_sms.git
|
96
|
+
licenses:
|
97
|
+
- MIT
|
98
|
+
metadata: {}
|
99
|
+
rdoc_options: []
|
100
|
+
require_paths:
|
101
|
+
- lib
|
102
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: 2.7.0
|
107
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
requirements: []
|
113
|
+
rubygems_version: 3.6.5
|
114
|
+
specification_version: 4
|
115
|
+
summary: Ruby gem for sending SMS via the Megalabs API
|
116
|
+
test_files: []
|