niazpardaz_sms 1.0.2

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.
@@ -0,0 +1,36 @@
1
+ ===============================================================================
2
+
3
+ NiazpardazSms با موفقیت نصب شد!
4
+
5
+ ===============================================================================
6
+
7
+ مراحل بعدی:
8
+
9
+ 1. فایل config/initializers/niazpardaz_sms.rb را باز کنید
10
+
11
+ 2. کلید API خود را تنظیم کنید:
12
+ - از متغیر محیطی NIAZPARDAZ_API_KEY استفاده کنید
13
+ - یا مستقیماً در فایل وارد کنید (توصیه نمی‌شود)
14
+
15
+ 3. نمونه استفاده:
16
+
17
+ # ارسال پیامک
18
+ client = NiazpardazSms.client
19
+ result = client.send_sms(
20
+ from_number: '10001234',
21
+ to_number: '09123456789',
22
+ message: 'سلام!'
23
+ )
24
+
25
+ if result.success?
26
+ puts "ارسال موفق! شناسه: #{result.batch_sms_id}"
27
+ else
28
+ puts "خطا: #{result.result_description}"
29
+ end
30
+
31
+ ===============================================================================
32
+
33
+ مستندات کامل:
34
+ https://github.com/NiazpardazSms/niazpardaz-sms-ruby
35
+
36
+ ===============================================================================
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ # پیکربندی NiazpardazSms
4
+ #
5
+ # برای اطلاعات بیشتر به مستندات مراجعه کنید:
6
+ # https://github.com/NiazpardazSms/niazpardaz-sms-ruby
7
+
8
+ NiazpardazSms.configure do |config|
9
+ # کلید API دریافتی از پنل نیازپرداز
10
+ # می‌توانید از متغیر محیطی استفاده کنید:
11
+ config.default_api_key = ENV.fetch('NIAZPARDAZ_API_KEY', nil)
12
+
13
+ # زمان انتظار برای درخواست‌ها (ثانیه)
14
+ # config.default_timeout = 30
15
+
16
+ # آدرس پایه API (فقط در صورت نیاز تغییر دهید)
17
+ # config.default_base_url = 'https://login.niazpardaz.ir/api/v2/RestWebApi'
18
+ end
@@ -0,0 +1,331 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require 'json'
5
+ require 'time'
6
+
7
+ module NiazpardazSms
8
+ # کلاینت اصلی برای کار با API پیامکی نیازپرداز
9
+ class Client
10
+ DEFAULT_BASE_URL = 'https://login.niazpardaz.ir/api/v2/RestWebApi'
11
+ DEFAULT_TIMEOUT = 30
12
+
13
+ attr_reader :api_key
14
+ attr_accessor :base_url, :timeout
15
+
16
+ # سازنده با کلید API
17
+ #
18
+ # @param api_key [String] کلید API دریافتی از پنل
19
+ # @param options [Hash] تنظیمات اختیاری
20
+ # @option options [String] :base_url آدرس پایه API
21
+ # @option options [Integer] :timeout زمان انتظار (ثانیه)
22
+ # @option options [Faraday::Connection] :connection اتصال سفارشی Faraday
23
+ def initialize(api_key, options = {})
24
+ raise Errors::ValidationError, 'کلید API نمی‌تواند خالی باشد' if api_key.nil? || api_key.strip.empty?
25
+
26
+ @api_key = api_key
27
+ @base_url = options[:base_url] || DEFAULT_BASE_URL
28
+ @timeout = options[:timeout] || DEFAULT_TIMEOUT
29
+ @connection = options[:connection]
30
+ end
31
+
32
+ # ========== ارسال پیامک ==========
33
+
34
+ # ارسال پیامک تکی
35
+ #
36
+ # @param from_number [String] شماره فرستنده
37
+ # @param to_number [String] شماره گیرنده
38
+ # @param message [String] متن پیامک
39
+ # @param is_flash [Boolean] آیا فلش باشد؟
40
+ # @param send_delay [Integer, nil] تاخیر ارسال (ثانیه)
41
+ # @return [Models::SendBatchSmsResult] نتیجه ارسال
42
+ def send_sms(from_number:, to_number:, message:, is_flash: false, send_delay: nil)
43
+ validate_presence!(from_number: from_number, to_number: to_number, message: message)
44
+
45
+ send_bulk_sms(
46
+ from_number: from_number,
47
+ to_numbers: [to_number],
48
+ message: message,
49
+ is_flash: is_flash,
50
+ send_delay: send_delay
51
+ )
52
+ end
53
+
54
+ # ارسال پیامک گروهی (یک متن به چند شماره)
55
+ #
56
+ # @param from_number [String] شماره فرستنده
57
+ # @param to_numbers [Array<String>] لیست شماره گیرندگان
58
+ # @param message [String] متن پیامک
59
+ # @param is_flash [Boolean] آیا فلش باشد؟
60
+ # @param send_delay [Integer, nil] تاخیر ارسال
61
+ # @return [Models::SendBatchSmsResult] نتیجه ارسال
62
+ def send_bulk_sms(from_number:, to_numbers:, message:, is_flash: false, send_delay: nil)
63
+ validate_presence!(from_number: from_number, to_numbers: to_numbers, message: message)
64
+
65
+ payload = {
66
+ fromNumber: from_number,
67
+ messageContent: message,
68
+ toNumbers: Array(to_numbers).join(','),
69
+ isFlash: is_flash,
70
+ sendDelay: send_delay
71
+ }
72
+
73
+ result = post('/SendBatchSms', payload)
74
+ Models::SendBatchSmsResult.new(result)
75
+ end
76
+
77
+ # ارسال پیامک LikeToLike (هر شماره پیام مخصوص خودش)
78
+ #
79
+ # @param from_number [String] شماره فرستنده
80
+ # @param to_numbers [Array<String>] لیست شماره گیرندگان
81
+ # @param messages [Array<String>] لیست پیام‌ها (هم‌طول با گیرندگان)
82
+ # @param is_flash [Boolean] آیا فلش باشد؟
83
+ # @return [Models::SendLikeToLikeResult] نتیجه ارسال
84
+ def send_sms_like_to_like(from_number:, to_numbers:, messages:, is_flash: false)
85
+ validate_presence!(from_number: from_number, to_numbers: to_numbers, messages: messages)
86
+
87
+ payload = {
88
+ fromNumber: from_number,
89
+ messageContents: Array(messages).join(','),
90
+ toNumbers: Array(to_numbers).join(','),
91
+ isFlash: is_flash
92
+ }
93
+
94
+ result = post('/SendSmsLikeToLike', payload)
95
+ Models::SendLikeToLikeResult.new(result)
96
+ end
97
+
98
+ # ارسال پیامک صوتی OTP
99
+ #
100
+ # @param from_number [String] شماره فرستنده
101
+ # @param to_number [String] شماره گیرنده
102
+ # @param otp [String] کد OTP
103
+ # @param is_flash [Boolean] آیا فلش باشد؟
104
+ # @param send_delay [Integer, nil] تاخیر ارسال
105
+ # @return [Models::SendBatchSmsResult] نتیجه ارسال
106
+ def send_voice_otp(from_number:, to_number:, otp:, is_flash: false, send_delay: nil)
107
+ validate_presence!(from_number: from_number, to_number: to_number, otp: otp)
108
+
109
+ payload = {
110
+ fromNumber: from_number,
111
+ messageContent: otp,
112
+ toNumbers: to_number,
113
+ sendDelay: send_delay,
114
+ isFlash: is_flash
115
+ }
116
+
117
+ result = post('/SendVoiceOtp', payload)
118
+ Models::SendBatchSmsResult.new(result)
119
+ end
120
+
121
+ # ========== گزارش تحویل ==========
122
+
123
+ # گزارش تحویل پیامک گروهی
124
+ #
125
+ # @param batch_sms_id [Integer] شناسه ارسال گروهی
126
+ # @param page_index [Integer] شماره صفحه
127
+ # @param page_size [Integer] تعداد رکورد در صفحه
128
+ # @return [Models::BatchDeliveryResult] نتیجه گزارش
129
+ def get_batch_delivery(batch_sms_id:, page_index: 1, page_size: 100)
130
+ payload = {
131
+ batchSmsId: batch_sms_id,
132
+ index: page_index,
133
+ count: page_size
134
+ }
135
+
136
+ result = post('/GetBatchDelivery', payload)
137
+ Models::BatchDeliveryResult.new(result)
138
+ end
139
+
140
+ # گزارش تحویل پیامک LikeToLike
141
+ #
142
+ # @param sms_id [Integer] شناسه پیامک
143
+ # @return [Models::BatchDeliveryResult] نتیجه گزارش
144
+ def get_delivery_like_to_like(sms_id:)
145
+ payload = { smsId: sms_id }
146
+
147
+ result = post('/GetDeliveryLikeToLike', payload)
148
+ Models::BatchDeliveryResult.new(result)
149
+ end
150
+
151
+ # ========== حساب کاربری ==========
152
+
153
+ # دریافت اعتبار حساب
154
+ #
155
+ # @return [Models::CreditResult] نتیجه اعتبار
156
+ def get_credit
157
+ result = post('/GetCredit', {})
158
+ Models::CreditResult.new(result)
159
+ end
160
+
161
+ # دریافت لیست شماره‌های فرستنده
162
+ #
163
+ # @return [Models::SenderNumbersResult] نتیجه شماره‌ها
164
+ def get_sender_numbers
165
+ result = post('/GetSenderNumbers', {})
166
+ Models::SenderNumbersResult.new(result)
167
+ end
168
+
169
+ # ========== صندوق ورودی ==========
170
+
171
+ # دریافت تعداد پیامک‌های دریافتی
172
+ #
173
+ # @param is_read [Boolean] فقط خوانده شده‌ها؟
174
+ # @return [Models::InboxCountResult] نتیجه تعداد
175
+ def get_inbox_count(is_read: false)
176
+ payload = { isRead: is_read }
177
+
178
+ result = post('/GetInboxCount', payload)
179
+ Models::InboxCountResult.new(result)
180
+ end
181
+
182
+ # دریافت پیامک‌ها
183
+ #
184
+ # @param message_type [Integer] نوع پیامک
185
+ # @param from_numbers [String] شماره‌های فرستنده (با کاما جدا شده)
186
+ # @param page_index [Integer] شماره صفحه
187
+ # @param page_size [Integer] تعداد رکورد در صفحه
188
+ # @return [Models::MessagesResult] نتیجه پیامک‌ها
189
+ def get_messages(message_type:, from_numbers:, page_index: 1, page_size: 100)
190
+ payload = {
191
+ messageType: message_type,
192
+ fromNumbers: from_numbers,
193
+ index: page_index,
194
+ count: page_size
195
+ }
196
+
197
+ result = post('/GetMessages', payload)
198
+ Models::MessagesResult.new(result)
199
+ end
200
+
201
+ # دریافت پیامک‌ها بر اساس بازه زمانی
202
+ #
203
+ # @param message_type [Integer] نوع پیامک
204
+ # @param from_numbers [String] شماره‌های فرستنده (با کاما جدا شده)
205
+ # @param from_date [Time, DateTime, String] تاریخ شروع
206
+ # @param to_date [Time, DateTime, String] تاریخ پایان
207
+ # @return [Models::MessagesResult] نتیجه پیامک‌ها
208
+ def get_messages_by_date_range(message_type:, from_numbers:, from_date:, to_date:)
209
+ payload = {
210
+ messageType: message_type,
211
+ fromNumbers: from_numbers,
212
+ fromDate: format_datetime(from_date),
213
+ toDate: format_datetime(to_date)
214
+ }
215
+
216
+ result = post('/GetMessagesByDateRange', payload)
217
+ Models::MessagesResult.new(result)
218
+ end
219
+
220
+ # ========== لیست سیاه ==========
221
+
222
+ # استخراج شماره‌های لیست سیاه مخابرات
223
+ #
224
+ # @param numbers [Array<String>] لیست شماره‌ها
225
+ # @return [Models::BlacklistNumbersResult] نتیجه
226
+ def extract_telecom_blacklist_numbers(numbers:)
227
+ validate_presence!(numbers: numbers)
228
+
229
+ payload = { numbers: Array(numbers).join(',') }
230
+
231
+ result = post('/ExtractTelecomBlacklistNumbers', payload)
232
+ Models::BlacklistNumbersResult.new(result)
233
+ end
234
+
235
+ # بررسی اینکه آیا شماره در لیست سیاه مخابرات هست؟
236
+ #
237
+ # @param number [String] شماره موبایل
238
+ # @return [Models::IsBlacklistResult] نتیجه
239
+ def number_is_in_telecom_blacklist(number:)
240
+ validate_presence!(number: number)
241
+
242
+ payload = { number: number }
243
+
244
+ result = post('/NumberIsInTelecomBlacklist', payload)
245
+ Models::IsBlacklistResult.new(result)
246
+ end
247
+
248
+ # ========== اعتبارسنجی ==========
249
+
250
+ # بررسی محتوای پیامک (فیلتر کلمات)
251
+ #
252
+ # @param message [String] متن پیامک
253
+ # @return [Models::CheckContentResult] نتیجه
254
+ def check_sms_content(message:)
255
+ validate_presence!(message: message)
256
+
257
+ payload = { message: message }
258
+
259
+ result = post('/CheckSmsContent', payload)
260
+ Models::CheckContentResult.new(result)
261
+ end
262
+
263
+ private
264
+
265
+ def connection
266
+ @connection ||= Faraday.new(url: @base_url) do |faraday|
267
+ faraday.request :json
268
+ faraday.response :json, content_type: /\bjson$/
269
+ faraday.adapter Faraday.default_adapter
270
+ faraday.options.timeout = @timeout
271
+ faraday.options.open_timeout = @timeout
272
+ end
273
+ end
274
+
275
+ def post(endpoint, payload)
276
+ response = connection.post(endpoint) do |req|
277
+ req.headers['Content-Type'] = 'application/json'
278
+ req.headers['X-API-Key'] = @api_key
279
+ req.body = payload.to_json
280
+ end
281
+
282
+ handle_response(response)
283
+ rescue Faraday::ConnectionFailed, Faraday::TimeoutError => e
284
+ raise Errors::NetworkError, "خطا در ارتباط با سرور: #{e.message}"
285
+ end
286
+
287
+ def handle_response(response)
288
+ unless response.success?
289
+ raise Errors::ApiError.new(
290
+ "خطا در ارتباط با سرور: #{response.status}",
291
+ response.status,
292
+ http_status: response.status,
293
+ response_body: response.body
294
+ )
295
+ end
296
+
297
+ body = response.body
298
+ body = JSON.parse(body) if body.is_a?(String)
299
+
300
+ if body.nil?
301
+ raise Errors::ApiError.new('پاسخ نامعتبر از سرور')
302
+ end
303
+
304
+ unless body['success']
305
+ error_message = body['errorMessage'] || 'خطای نامشخص'
306
+ raise Errors::ApiError.new(error_message)
307
+ end
308
+
309
+ body['result']
310
+ end
311
+
312
+ def validate_presence!(**params)
313
+ params.each do |key, value|
314
+ if value.nil? || (value.respond_to?(:empty?) && value.empty?)
315
+ raise Errors::ValidationError, "پارامتر #{key} نمی‌تواند خالی باشد"
316
+ end
317
+ end
318
+ end
319
+
320
+ def format_datetime(value)
321
+ case value
322
+ when Time, DateTime
323
+ value.iso8601
324
+ when String
325
+ value
326
+ else
327
+ value.to_s
328
+ end
329
+ end
330
+ end
331
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NiazpardazSms
4
+ module Errors
5
+ # خطای پایه برای تمام خطاهای نیازپرداز
6
+ class NiazpardazError < StandardError
7
+ attr_reader :error_code
8
+
9
+ def initialize(message = nil, error_code = nil)
10
+ @error_code = error_code
11
+ super(message)
12
+ end
13
+ end
14
+
15
+ # خطای مربوط به API نیازپرداز
16
+ class ApiError < NiazpardazError
17
+ attr_reader :http_status, :response_body
18
+
19
+ def initialize(message = nil, error_code = nil, http_status: nil, response_body: nil)
20
+ @http_status = http_status
21
+ @response_body = response_body
22
+ super(message, error_code)
23
+ end
24
+ end
25
+
26
+ # خطای اعتبارسنجی پارامترها
27
+ class ValidationError < NiazpardazError; end
28
+
29
+ # خطای شبکه
30
+ class NetworkError < NiazpardazError; end
31
+
32
+ # خطای احراز هویت
33
+ class AuthenticationError < ApiError; end
34
+
35
+ # خطای محدودیت درخواست
36
+ class RateLimitError < ApiError; end
37
+
38
+ # خطای سرور
39
+ class ServerError < ApiError; end
40
+ end
41
+ end
@@ -0,0 +1,261 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NiazpardazSms
4
+ module Models
5
+ # کلاس پایه برای تمام پاسخ‌ها
6
+ class BaseResponse
7
+ attr_reader :raw_response
8
+
9
+ def initialize(data = {})
10
+ @raw_response = data
11
+ end
12
+
13
+ def success?
14
+ false
15
+ end
16
+ end
17
+
18
+ # نتیجه ارسال پیامک گروهی
19
+ class SendBatchSmsResult < BaseResponse
20
+ attr_reader :batch_sms_id, :result_code
21
+
22
+ def initialize(data = {})
23
+ super
24
+ @batch_sms_id = data['batchSmsId']
25
+ @result_code = data['resultCode']
26
+ end
27
+
28
+ def success?
29
+ SendResultCode.success?(@result_code)
30
+ end
31
+
32
+ def result_description
33
+ SendResultCode.description(@result_code)
34
+ end
35
+ end
36
+
37
+ # نتیجه ارسال پیامک LikeToLike
38
+ class SendLikeToLikeResult < BaseResponse
39
+ attr_reader :sms_id, :result_code
40
+
41
+ def initialize(data = {})
42
+ super
43
+ @sms_id = data['smsId']
44
+ @result_code = data['resultCode']
45
+ end
46
+
47
+ def success?
48
+ SendResultCode.success?(@result_code)
49
+ end
50
+
51
+ def result_description
52
+ SendResultCode.description(@result_code)
53
+ end
54
+ end
55
+
56
+ # نتیجه گزارش تحویل
57
+ class BatchDeliveryResult < BaseResponse
58
+ attr_reader :result_code, :numbers, :delivery_status
59
+
60
+ def initialize(data = {})
61
+ super
62
+ @result_code = data['resultCode']
63
+ @numbers = data['numbers'] || []
64
+ @delivery_status = data['deliveryStatus'] || []
65
+ end
66
+
67
+ def success?
68
+ DeliveryResultCode.success?(@result_code)
69
+ end
70
+
71
+ def result_description
72
+ DeliveryResultCode.description(@result_code)
73
+ end
74
+
75
+ # برگرداندن وضعیت تحویل به صورت hash
76
+ def delivery_hash
77
+ @numbers.zip(@delivery_status).to_h
78
+ end
79
+ end
80
+
81
+ # نتیجه دریافت اعتبار
82
+ class CreditResult < BaseResponse
83
+ attr_reader :credit, :result_code
84
+
85
+ def initialize(data = {})
86
+ super
87
+ @credit = data['credit']&.to_f
88
+ @result_code = data['resultCode']
89
+ end
90
+
91
+ def success?
92
+ CreditResultCode.success?(@result_code)
93
+ end
94
+
95
+ def result_description
96
+ CreditResultCode.description(@result_code)
97
+ end
98
+ end
99
+
100
+ # نتیجه دریافت شماره‌های فرستنده
101
+ class SenderNumbersResult < BaseResponse
102
+ attr_reader :senders, :result_code
103
+
104
+ def initialize(data = {})
105
+ super
106
+ @senders = data['senders'] || []
107
+ @result_code = data['resultCode']
108
+ end
109
+
110
+ def success?
111
+ SenderNumbersResultCode.success?(@result_code)
112
+ end
113
+
114
+ def result_description
115
+ SenderNumbersResultCode.description(@result_code)
116
+ end
117
+ end
118
+
119
+ # نتیجه دریافت تعداد پیامک‌های دریافتی
120
+ class InboxCountResult < BaseResponse
121
+ attr_reader :inbox_count, :result_code
122
+
123
+ def initialize(data = {})
124
+ super
125
+ @inbox_count = data['inboxCount']
126
+ @result_code = data['resultCode']
127
+ end
128
+
129
+ def success?
130
+ InboxCountResultCode.success?(@result_code)
131
+ end
132
+
133
+ def result_description
134
+ InboxCountResultCode.description(@result_code)
135
+ end
136
+ end
137
+
138
+ # اطلاعات پیامک
139
+ class MessageInfo
140
+ attr_reader :message_id, :user_id, :tariff, :content, :action_date_time,
141
+ :message_type, :sender, :receiver, :flash, :pages, :lang,
142
+ :status, :send_status, :send_method, :cost, :title, :count,
143
+ :sent, :desc, :not_sent, :money_is_refunded, :is_read
144
+
145
+ def initialize(data = {})
146
+ @message_id = data['messageId']
147
+ @user_id = data['userId']
148
+ @tariff = data['tariff']&.to_f
149
+ @content = data['content']
150
+ @action_date_time = parse_datetime(data['actionDateTime'])
151
+ @message_type = data['messageType']
152
+ @sender = data['sender']
153
+ @receiver = data['receiver']
154
+ @flash = data['flash']
155
+ @pages = data['pages']
156
+ @lang = data['lang']
157
+ @status = data['status']
158
+ @send_status = data['sendStatus']
159
+ @send_method = data['sendMethod']
160
+ @cost = data['cost']&.to_f
161
+ @title = data['title']
162
+ @count = data['count']
163
+ @sent = data['sent']
164
+ @desc = data['desc']
165
+ @not_sent = data['notSent']
166
+ @money_is_refunded = data['moneyIsRefunded']
167
+ @is_read = data['isRead']
168
+ end
169
+
170
+ private
171
+
172
+ def parse_datetime(value)
173
+ return nil if value.nil?
174
+
175
+ Time.parse(value.to_s)
176
+ rescue ArgumentError
177
+ nil
178
+ end
179
+ end
180
+
181
+ # نتیجه دریافت پیامک‌ها
182
+ class MessagesResult < BaseResponse
183
+ attr_reader :messages, :result_code
184
+
185
+ def initialize(data = {})
186
+ super
187
+ @result_code = data['resultCode']
188
+ @messages = (data['messages'] || []).map { |m| MessageInfo.new(m) }
189
+ end
190
+
191
+ def success?
192
+ @result_code.zero?
193
+ end
194
+ end
195
+
196
+ # نتیجه استخراج شماره‌های لیست سیاه
197
+ class BlacklistNumbersResult < BaseResponse
198
+ attr_reader :blacklist_numbers, :result_code
199
+
200
+ def initialize(data = {})
201
+ super
202
+ @blacklist_numbers = data['blackListNumbers'] || []
203
+ @result_code = data['resultCode']
204
+ end
205
+
206
+ def success?
207
+ BlacklistResultCode.success?(@result_code)
208
+ end
209
+
210
+ def result_description
211
+ BlacklistResultCode.description(@result_code)
212
+ end
213
+ end
214
+
215
+ # نتیجه بررسی شماره در لیست سیاه
216
+ class IsBlacklistResult < BaseResponse
217
+ attr_reader :is_black, :result_code
218
+
219
+ def initialize(data = {})
220
+ super
221
+ @is_black = data['isBlack']
222
+ @result_code = data['resultCode']
223
+ end
224
+
225
+ def success?
226
+ BlacklistResultCode.success?(@result_code)
227
+ end
228
+
229
+ def result_description
230
+ BlacklistResultCode.description(@result_code)
231
+ end
232
+
233
+ def blacklisted?
234
+ @is_black == true
235
+ end
236
+ end
237
+
238
+ # نتیجه بررسی محتوای پیامک
239
+ class CheckContentResult < BaseResponse
240
+ attr_reader :is_valid, :result_code
241
+
242
+ def initialize(data = {})
243
+ super
244
+ @is_valid = data['isValid']
245
+ @result_code = data['resultCode']
246
+ end
247
+
248
+ def success?
249
+ CheckContentResultCode.success?(@result_code)
250
+ end
251
+
252
+ def result_description
253
+ CheckContentResultCode.description(@result_code)
254
+ end
255
+
256
+ def valid?
257
+ @is_valid == true
258
+ end
259
+ end
260
+ end
261
+ end