roistat 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/.ruby-version +1 -0
- data/CHANGELOG.md +18 -0
- data/LICENSE.txt +21 -0
- data/README.md +757 -0
- data/Rakefile +12 -0
- data/docs/ru/README.md +142 -0
- data/lefthook.yml +8 -0
- data/lib/generators/roistat/install/install_generator.rb +13 -0
- data/lib/generators/roistat/install/templates/roistat.rb +13 -0
- data/lib/roistat/client.rb +220 -0
- data/lib/roistat/configuration.rb +17 -0
- data/lib/roistat/errors.rb +18 -0
- data/lib/roistat/resources/access.rb +25 -0
- data/lib/roistat/resources/analytics.rb +68 -0
- data/lib/roistat/resources/base.rb +31 -0
- data/lib/roistat/resources/billing.rb +17 -0
- data/lib/roistat/resources/calltracking.rb +102 -0
- data/lib/roistat/resources/channels.rb +28 -0
- data/lib/roistat/resources/clients.rb +38 -0
- data/lib/roistat/resources/dashboards.rb +13 -0
- data/lib/roistat/resources/emailtracking.rb +16 -0
- data/lib/roistat/resources/events.rb +42 -0
- data/lib/roistat/resources/indicators.rb +13 -0
- data/lib/roistat/resources/lead_hunter.rb +8 -0
- data/lib/roistat/resources/leads.rb +33 -0
- data/lib/roistat/resources/managers.rb +33 -0
- data/lib/roistat/resources/mediaplan.rb +23 -0
- data/lib/roistat/resources/orders.rb +76 -0
- data/lib/roistat/resources/projects.rb +30 -0
- data/lib/roistat/resources/proxy_leads.rb +18 -0
- data/lib/roistat/resources/sms.rb +15 -0
- data/lib/roistat/resources/speech.rb +68 -0
- data/lib/roistat/resources/statistics.rb +8 -0
- data/lib/roistat/resources/visits.rb +23 -0
- data/lib/roistat/resources/vpbx.rb +100 -0
- data/lib/roistat/resources/widgets.rb +17 -0
- data/lib/roistat/response.rb +88 -0
- data/lib/roistat/version.rb +5 -0
- data/lib/roistat.rb +66 -0
- data/mise.toml +14 -0
- data/sig/roistat.rbs +251 -0
- metadata +187 -0
data/Rakefile
ADDED
data/docs/ru/README.md
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Roistat — документация на русском
|
|
2
|
+
|
|
3
|
+
How-to для разработчиков, которые подключают гем `roistat` к приложению на Ruby или Rails.
|
|
4
|
+
|
|
5
|
+
**Предпосылки:** Ruby 3+, ключ API Roistat, id проекта. Полные таблицы методов — в [корневом README](../../README.md) (английский).
|
|
6
|
+
|
|
7
|
+
Официальные справочники Roistat:
|
|
8
|
+
|
|
9
|
+
- [help-ru](https://help-ru.roistat.com/API/methods/about/) — основная инвентаризация путей
|
|
10
|
+
- [help-en](https://help.roistat.com/API/methods/about/) — дашборды, виджеты и часть путей access/counter
|
|
11
|
+
|
|
12
|
+
## Содержание
|
|
13
|
+
|
|
14
|
+
- [Установка](#установка)
|
|
15
|
+
- [Конфигурация](#конфигурация)
|
|
16
|
+
- [Клиенты](#клиенты)
|
|
17
|
+
- [Группы ресурсов](#группы-ресурсов)
|
|
18
|
+
- [Ответы и ошибки](#ответы-и-ошибки)
|
|
19
|
+
- [Разработка](#разработка)
|
|
20
|
+
|
|
21
|
+
## Установка
|
|
22
|
+
|
|
23
|
+
Добавьте гем в Gemfile:
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
gem "roistat"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Затем:
|
|
30
|
+
|
|
31
|
+
```fish
|
|
32
|
+
bundle install
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Rails
|
|
36
|
+
|
|
37
|
+
```fish
|
|
38
|
+
bundle exec rails generate roistat:install
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Генератор создаёт `config/initializers/roistat.rb` со всеми опциями и привязкой к ENV.
|
|
42
|
+
|
|
43
|
+
## Конфигурация
|
|
44
|
+
|
|
45
|
+
### Глобальная (удобно для Rails)
|
|
46
|
+
|
|
47
|
+
```ruby
|
|
48
|
+
Roistat.configure do |config|
|
|
49
|
+
config.api_key = ENV.fetch("ROISTAT_API_KEY")
|
|
50
|
+
config.project = ENV.fetch("ROISTAT_PROJECT_ID")
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
Roistat.client.projects.list
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Опции
|
|
57
|
+
|
|
58
|
+
| Опция | Обязательна | По умолчанию | Назначение |
|
|
59
|
+
|-------|-------------|--------------|------------|
|
|
60
|
+
| `api_key` | да | — | ключ в заголовке `Api-key` |
|
|
61
|
+
| `project` | для project-scoped вызовов | — | query `project` |
|
|
62
|
+
| `base_url` | нет | `https://cloud.roistat.com/api/v1` | базовый URL |
|
|
63
|
+
| `timeout` | нет | `30` | таймаут запроса (сек) |
|
|
64
|
+
| `open_timeout` | нет | `10` | таймаут открытия соединения |
|
|
65
|
+
| `binary_tempfile_threshold` | нет | `1048576` (1 MiB) | порог для `Tempfile` |
|
|
66
|
+
|
|
67
|
+
Каждый запрос уходит с заголовком `Api-key`. Параметр `key` в query гем не использует.
|
|
68
|
+
|
|
69
|
+
## Клиенты
|
|
70
|
+
|
|
71
|
+
### Общий клиент
|
|
72
|
+
|
|
73
|
+
`Roistat.client` собирается из глобальной конфигурации.
|
|
74
|
+
|
|
75
|
+
### Отдельный клиент
|
|
76
|
+
|
|
77
|
+
Удобно для нескольких проектов, джобов и скриптов:
|
|
78
|
+
|
|
79
|
+
```ruby
|
|
80
|
+
client = Roistat::Client.new(
|
|
81
|
+
api_key: ENV.fetch("ROISTAT_API_KEY"),
|
|
82
|
+
project: "12345"
|
|
83
|
+
)
|
|
84
|
+
client.orders.list(limit: 10)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Низкоуровневый HTTP
|
|
88
|
+
|
|
89
|
+
Если для пути ещё нет resource-метода:
|
|
90
|
+
|
|
91
|
+
```ruby
|
|
92
|
+
client.get("project/calltracking/phone/list", params: {limit: 10})
|
|
93
|
+
client.post("project/events/send", body: {name: "purchase"})
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Группы ресурсов
|
|
97
|
+
|
|
98
|
+
Ниже — точки входа. Сигнатуры и примеры смотрите в [английском README](../../README.md#resource-apis).
|
|
99
|
+
|
|
100
|
+
| Группа | Клиент | Примеры задач |
|
|
101
|
+
|--------|--------|---------------|
|
|
102
|
+
| Projects | `client.projects` | список проектов, модули / counter list |
|
|
103
|
+
| Access | `client.access` | права пользователей (RU и EN пути) |
|
|
104
|
+
| Dashboards / Widgets | `client.dashboards`, `client.widgets` | дашборды и данные виджетов (EN) |
|
|
105
|
+
| Billing | `client.billing` | транзакции и Excel-экспорт |
|
|
106
|
+
| Calltracking | `client.calltracking` | скрипты, номера, звонки |
|
|
107
|
+
| Orders / proxy / leads | `client.orders`, `client.proxy_leads`, `client.leads` | сделки и лиды |
|
|
108
|
+
| Managers / lead hunter | `client.managers`, `client.lead_hunter` | менеджеры и охотник за лидами |
|
|
109
|
+
| Clients / visits / events | `client.clients`, `client.visits`, `client.events` | клиенты, визиты, события |
|
|
110
|
+
| Analytics / channels | `client.analytics`, `client.channels` | отчёты и источники |
|
|
111
|
+
| Statistics / indicators | `client.statistics`, `client.indicators` | дневная статистика и индикаторы |
|
|
112
|
+
| Email / SMS / mediaplan | `client.emailtracking`, `client.sms`, `client.mediaplan` | почта, SMS-отчёт, медиаплан |
|
|
113
|
+
| Speech / VPBX | `client.speech`, `client.vpbx` | речевая аналитика и облачная АТС |
|
|
114
|
+
|
|
115
|
+
Мутирующие методы (create / update / delete / buy / send) меняют данные в Roistat. Используйте их осознанно.
|
|
116
|
+
|
|
117
|
+
## Ответы и ошибки
|
|
118
|
+
|
|
119
|
+
- JSON-эндпоинты возвращают разобранный Hash (строковые ключи).
|
|
120
|
+
- Бинарные ответы: `String`, если тело ≤ 1 MiB; иначе `Tempfile` (закройте и удалите файл после использования).
|
|
121
|
+
|
|
122
|
+
| Код Roistat `error` | Исключение |
|
|
123
|
+
|---------------------|------------|
|
|
124
|
+
| `authentication_failed` | `Roistat::AuthenticationError` |
|
|
125
|
+
| `authorization_failed` | `Roistat::AuthorizationError` |
|
|
126
|
+
| `access_denied` | `Roistat::AccessDeniedError` |
|
|
127
|
+
| `request_limit_error` | `Roistat::RateLimitError` |
|
|
128
|
+
| прочее | `Roistat::Error` |
|
|
129
|
+
|
|
130
|
+
Ошибки конфигурации (пустой ключ или project) поднимают `Roistat::ConfigurationError` до HTTP.
|
|
131
|
+
|
|
132
|
+
## Разработка
|
|
133
|
+
|
|
134
|
+
```fish
|
|
135
|
+
bin/setup
|
|
136
|
+
bundle exec rake
|
|
137
|
+
# или: mise test ; and mise lint
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Интерактивная консоль гема: `bin/console`.
|
|
141
|
+
|
|
142
|
+
Багрепорты и PR: https://github.com/alec-c4/roistat
|
data/lefthook.yml
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
|
|
5
|
+
class Roistat::Generators::InstallGenerator < Rails::Generators::Base
|
|
6
|
+
source_root File.expand_path("templates", __dir__)
|
|
7
|
+
|
|
8
|
+
desc "Creates a Roistat initializer with all configuration options"
|
|
9
|
+
|
|
10
|
+
def create_initializer_file
|
|
11
|
+
template "roistat.rb", "config/initializers/roistat.rb"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
Roistat.configure do |config|
|
|
4
|
+
# Required for project-scoped API calls.
|
|
5
|
+
config.api_key = ENV.fetch("ROISTAT_API_KEY")
|
|
6
|
+
config.project = ENV.fetch("ROISTAT_PROJECT_ID")
|
|
7
|
+
|
|
8
|
+
# Optional overrides.
|
|
9
|
+
# config.base_url = ENV.fetch("ROISTAT_BASE_URL", "https://cloud.roistat.com/api/v1")
|
|
10
|
+
# config.timeout = ENV.fetch("ROISTAT_TIMEOUT", 30).to_i
|
|
11
|
+
# config.open_timeout = ENV.fetch("ROISTAT_OPEN_TIMEOUT", 10).to_i
|
|
12
|
+
# config.binary_tempfile_threshold = ENV.fetch("ROISTAT_BINARY_TEMPFILE_THRESHOLD", 1_048_576).to_i
|
|
13
|
+
end
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "httpx"
|
|
4
|
+
require "json"
|
|
5
|
+
|
|
6
|
+
class Roistat::Client
|
|
7
|
+
attr_reader :api_key, :project, :base_url, :timeout, :open_timeout, :binary_tempfile_threshold
|
|
8
|
+
|
|
9
|
+
def initialize(
|
|
10
|
+
api_key:,
|
|
11
|
+
project: nil,
|
|
12
|
+
project_required: true,
|
|
13
|
+
base_url: nil,
|
|
14
|
+
timeout: nil,
|
|
15
|
+
open_timeout: nil,
|
|
16
|
+
binary_tempfile_threshold: nil
|
|
17
|
+
)
|
|
18
|
+
config = Roistat.configuration
|
|
19
|
+
|
|
20
|
+
@api_key = api_key
|
|
21
|
+
@project = project
|
|
22
|
+
@project_required = project_required
|
|
23
|
+
@base_url = base_url || config.base_url
|
|
24
|
+
@timeout = timeout || config.timeout
|
|
25
|
+
@open_timeout = open_timeout || config.open_timeout
|
|
26
|
+
@binary_tempfile_threshold = binary_tempfile_threshold || config.binary_tempfile_threshold
|
|
27
|
+
|
|
28
|
+
validate_credentials!
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def get(path, params: {}, parse: :json)
|
|
32
|
+
request(:get, path, params: params, parse: parse)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def post(path, params: {}, body: nil, parse: :json)
|
|
36
|
+
request(:post, path, params: params, body: body, parse: parse)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def post_multipart(path, params: {}, form: {}, parse: :json)
|
|
40
|
+
validate_project! if @project_required
|
|
41
|
+
|
|
42
|
+
query = params.dup
|
|
43
|
+
query[:project] = project if project && !query.key?(:project) && !query.key?("project")
|
|
44
|
+
|
|
45
|
+
headers = {
|
|
46
|
+
"Api-key" => api_key,
|
|
47
|
+
"Accept" => "application/json"
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
http_response = session.request(
|
|
51
|
+
"POST",
|
|
52
|
+
url_for(path),
|
|
53
|
+
params: stringify_keys(query),
|
|
54
|
+
headers: headers,
|
|
55
|
+
form: normalize_multipart_form(form)
|
|
56
|
+
)
|
|
57
|
+
Roistat::Response.parse(
|
|
58
|
+
http_response,
|
|
59
|
+
parse: parse,
|
|
60
|
+
binary_tempfile_threshold: binary_tempfile_threshold
|
|
61
|
+
)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def request(method, path, params: {}, body: nil, parse: :json)
|
|
65
|
+
validate_project! if @project_required
|
|
66
|
+
|
|
67
|
+
query = params.dup
|
|
68
|
+
query[:project] = project if project && !query.key?(:project) && !query.key?("project")
|
|
69
|
+
|
|
70
|
+
headers = {
|
|
71
|
+
"Api-key" => api_key,
|
|
72
|
+
"Accept" => "application/json"
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
options = {params: stringify_keys(query), headers: headers}
|
|
76
|
+
if body
|
|
77
|
+
headers["Content-Type"] = "application/json"
|
|
78
|
+
options[:json] = body
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
http_response = session.request(method.to_s.upcase, url_for(path), **options)
|
|
82
|
+
Roistat::Response.parse(
|
|
83
|
+
http_response,
|
|
84
|
+
parse: parse,
|
|
85
|
+
binary_tempfile_threshold: binary_tempfile_threshold
|
|
86
|
+
)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def projects
|
|
90
|
+
@projects ||= Roistat::Resources::Projects.new(self)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def access
|
|
94
|
+
@access ||= Roistat::Resources::Access.new(self)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def dashboards
|
|
98
|
+
@dashboards ||= Roistat::Resources::Dashboards.new(self)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def widgets
|
|
102
|
+
@widgets ||= Roistat::Resources::Widgets.new(self)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def billing
|
|
106
|
+
@billing ||= Roistat::Resources::Billing.new(self)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def calltracking
|
|
110
|
+
@calltracking ||= Roistat::Resources::Calltracking.new(self)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def orders
|
|
114
|
+
@orders ||= Roistat::Resources::Orders.new(self)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def proxy_leads
|
|
118
|
+
@proxy_leads ||= Roistat::Resources::ProxyLeads.new(self)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def leads
|
|
122
|
+
@leads ||= Roistat::Resources::Leads.new(self)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def managers
|
|
126
|
+
@managers ||= Roistat::Resources::Managers.new(self)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def clients
|
|
130
|
+
@clients ||= Roistat::Resources::Clients.new(self)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def visits
|
|
134
|
+
@visits ||= Roistat::Resources::Visits.new(self)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def events
|
|
138
|
+
@events ||= Roistat::Resources::Events.new(self)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def analytics
|
|
142
|
+
@analytics ||= Roistat::Resources::Analytics.new(self)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def channels
|
|
146
|
+
@channels ||= Roistat::Resources::Channels.new(self)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def statistics
|
|
150
|
+
@statistics ||= Roistat::Resources::Statistics.new(self)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def indicators
|
|
154
|
+
@indicators ||= Roistat::Resources::Indicators.new(self)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def lead_hunter
|
|
158
|
+
@lead_hunter ||= Roistat::Resources::LeadHunter.new(self)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def emailtracking
|
|
162
|
+
@emailtracking ||= Roistat::Resources::Emailtracking.new(self)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def sms
|
|
166
|
+
@sms ||= Roistat::Resources::Sms.new(self)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def mediaplan
|
|
170
|
+
@mediaplan ||= Roistat::Resources::Mediaplan.new(self)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def speech
|
|
174
|
+
@speech ||= Roistat::Resources::Speech.new(self)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def vpbx
|
|
178
|
+
@vpbx ||= Roistat::Resources::Vpbx.new(self)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
private
|
|
182
|
+
|
|
183
|
+
def validate_credentials!
|
|
184
|
+
raise Roistat::ConfigurationError, "api_key must be present" if blank?(api_key)
|
|
185
|
+
validate_project! if @project_required
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def validate_project!
|
|
189
|
+
raise Roistat::ConfigurationError, "project must be present" if blank?(project)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def blank?(value)
|
|
193
|
+
value.nil? || value.to_s.strip.empty?
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def url_for(path)
|
|
197
|
+
"#{base_url.to_s.chomp("/")}/#{path.to_s.delete_prefix("/")}"
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def session
|
|
201
|
+
@session ||= HTTPX.with(
|
|
202
|
+
timeout: {
|
|
203
|
+
request_timeout: timeout,
|
|
204
|
+
connect_timeout: open_timeout
|
|
205
|
+
}
|
|
206
|
+
)
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def stringify_keys(hash)
|
|
210
|
+
hash.transform_keys(&:to_s)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def normalize_multipart_form(form)
|
|
214
|
+
form.transform_keys(&:to_s).transform_values do |value|
|
|
215
|
+
next value if value.respond_to?(:read) || value.is_a?(String)
|
|
216
|
+
|
|
217
|
+
value.to_s
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Roistat::Configuration
|
|
4
|
+
DEFAULT_BASE_URL = "https://cloud.roistat.com/api/v1"
|
|
5
|
+
DEFAULT_TIMEOUT = 30
|
|
6
|
+
DEFAULT_OPEN_TIMEOUT = 10
|
|
7
|
+
DEFAULT_BINARY_TEMPFILE_THRESHOLD = 1 * 1024 * 1024
|
|
8
|
+
|
|
9
|
+
attr_accessor :api_key, :project, :base_url, :timeout, :open_timeout, :binary_tempfile_threshold
|
|
10
|
+
|
|
11
|
+
def initialize
|
|
12
|
+
@base_url = DEFAULT_BASE_URL
|
|
13
|
+
@timeout = DEFAULT_TIMEOUT
|
|
14
|
+
@open_timeout = DEFAULT_OPEN_TIMEOUT
|
|
15
|
+
@binary_tempfile_threshold = DEFAULT_BINARY_TEMPFILE_THRESHOLD
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Roistat::Error < StandardError
|
|
4
|
+
attr_reader :code, :http_status, :response_body
|
|
5
|
+
|
|
6
|
+
def initialize(message = nil, code: nil, http_status: nil, response_body: nil)
|
|
7
|
+
@code = code
|
|
8
|
+
@http_status = http_status
|
|
9
|
+
@response_body = response_body
|
|
10
|
+
super(message || code || self.class.name)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class Roistat::ConfigurationError < Roistat::Error; end
|
|
15
|
+
class Roistat::AuthenticationError < Roistat::Error; end
|
|
16
|
+
class Roistat::AuthorizationError < Roistat::Error; end
|
|
17
|
+
class Roistat::AccessDeniedError < Roistat::Error; end
|
|
18
|
+
class Roistat::RateLimitError < Roistat::Error; end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Roistat::Resources::Access < Roistat::Resources::Base
|
|
4
|
+
# GET /project/permissions/user/list — help-ru.
|
|
5
|
+
def user_list
|
|
6
|
+
client.get("project/permissions/user/list")
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# GET|POST /project/access/get-authorized-users — help-en.
|
|
10
|
+
def authorized_users(method: :get)
|
|
11
|
+
case method.to_sym
|
|
12
|
+
when :get
|
|
13
|
+
client.get("project/access/get-authorized-users")
|
|
14
|
+
when :post
|
|
15
|
+
client.post("project/access/get-authorized-users")
|
|
16
|
+
else
|
|
17
|
+
raise ArgumentError, "method must be :get or :post"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# POST /project/access/change — help-en.
|
|
22
|
+
def change(**body)
|
|
23
|
+
client.post("project/access/change", body: body)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Roistat::Resources::Analytics < Roistat::Resources::Base
|
|
4
|
+
# POST /project/analytics/data
|
|
5
|
+
def data(**body)
|
|
6
|
+
post_optional_body("project/analytics/data", body)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# POST /project/analytics/data/export/excel
|
|
10
|
+
def data_export_excel(**body)
|
|
11
|
+
client.post("project/analytics/data/export/excel", body: body, parse: :binary)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# POST /project/analytics/metrics-new
|
|
15
|
+
def metrics_new(**body)
|
|
16
|
+
post_optional_body("project/analytics/metrics-new", body)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# POST /project/analytics/dimensions
|
|
20
|
+
def dimensions(**body)
|
|
21
|
+
post_optional_body("project/analytics/dimensions", body)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# POST /project/analytics/dimension-values
|
|
25
|
+
def dimension_values(**body)
|
|
26
|
+
post_optional_body("project/analytics/dimension-values", body)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# POST /project/analytics/attribution-models
|
|
30
|
+
def attribution_models(**body)
|
|
31
|
+
post_optional_body("project/analytics/attribution-models", body)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# POST /project/analytics/list-orders
|
|
35
|
+
def list_orders(**body)
|
|
36
|
+
post_optional_body("project/analytics/list-orders", body)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# GET /project/analytics/metrics/custom/list
|
|
40
|
+
def custom_metrics_list(**params)
|
|
41
|
+
client.get("project/analytics/metrics/custom/list", params: params)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# POST /project/analytics/metrics/custom/manual/value/list
|
|
45
|
+
def custom_manual_value_list(**body)
|
|
46
|
+
post_optional_body("project/analytics/metrics/custom/manual/value/list", body)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# POST /project/analytics/metrics/custom/manual/value/add
|
|
50
|
+
def custom_manual_value_add(**body)
|
|
51
|
+
client.post("project/analytics/metrics/custom/manual/value/add", body: body)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# POST /project/analytics/metrics/custom/manual/value/delete
|
|
55
|
+
def custom_manual_value_delete(**body)
|
|
56
|
+
client.post("project/analytics/metrics/custom/manual/value/delete", body: body)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# POST /project/reports/funnel/data
|
|
60
|
+
def funnel_data(**body)
|
|
61
|
+
post_optional_body("project/reports/funnel/data", body)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# POST /project/analytics/event/add
|
|
65
|
+
def event_add(**body)
|
|
66
|
+
client.post("project/analytics/event/add", body: body)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Roistat::Resources::Base
|
|
4
|
+
attr_reader :client
|
|
5
|
+
|
|
6
|
+
def initialize(client)
|
|
7
|
+
@client = client
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def api_key_client
|
|
13
|
+
@api_key_client ||= Roistat::Client.new(
|
|
14
|
+
api_key: client.api_key,
|
|
15
|
+
project: nil,
|
|
16
|
+
project_required: false,
|
|
17
|
+
base_url: client.base_url,
|
|
18
|
+
timeout: client.timeout,
|
|
19
|
+
open_timeout: client.open_timeout,
|
|
20
|
+
binary_tempfile_threshold: client.binary_tempfile_threshold
|
|
21
|
+
)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def post_optional_body(path, body)
|
|
25
|
+
if body.nil? || body.empty?
|
|
26
|
+
client.post(path)
|
|
27
|
+
else
|
|
28
|
+
client.post(path, body: body)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Roistat::Resources::Billing < Roistat::Resources::Base
|
|
4
|
+
# POST /user/billing/transactions/list
|
|
5
|
+
def transactions_list(period:)
|
|
6
|
+
client.post("user/billing/transactions/list", body: {period: period})
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# POST /user/billing/transactions/list/export/excel
|
|
10
|
+
def transactions_export_excel(period:)
|
|
11
|
+
client.post(
|
|
12
|
+
"user/billing/transactions/list/export/excel",
|
|
13
|
+
body: {period: period},
|
|
14
|
+
parse: :binary
|
|
15
|
+
)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Roistat::Resources::Calltracking < Roistat::Resources::Base
|
|
4
|
+
# POST /project/calltracking/script/list
|
|
5
|
+
def script_list(**body)
|
|
6
|
+
post("project/calltracking/script/list", body: body)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# POST /project/calltracking/script/create
|
|
10
|
+
def script_create(**body)
|
|
11
|
+
client.post("project/calltracking/script/create", body: body)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# POST /project/calltracking/script/update
|
|
15
|
+
def script_update(**body)
|
|
16
|
+
client.post("project/calltracking/script/update", body: body)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# POST /project/calltracking/script/delete
|
|
20
|
+
def script_delete(id:)
|
|
21
|
+
client.post("project/calltracking/script/delete", body: {id: id})
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# POST /project/calltracking/phone/list
|
|
25
|
+
def phone_list(**body)
|
|
26
|
+
post("project/calltracking/phone/list", body: body)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# POST /project/calltracking/phone/prefix/list
|
|
30
|
+
def phone_prefix_list(**body)
|
|
31
|
+
post("project/calltracking/phone/prefix/list", body: body)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# POST /project/calltracking/phone/create
|
|
35
|
+
def phone_create(phones:)
|
|
36
|
+
client.post("project/calltracking/phone/create", body: {phones: phones})
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# POST /project/calltracking/phone/buy
|
|
40
|
+
def phone_buy(prefix:, count:)
|
|
41
|
+
client.post("project/calltracking/phone/buy", body: {prefix: prefix, count: count})
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# POST /project/calltracking/phone/update
|
|
45
|
+
def phone_update(**body)
|
|
46
|
+
client.post("project/calltracking/phone/update", body: body)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# POST /project/calltracking/phone/delete
|
|
50
|
+
def phone_delete(phones:)
|
|
51
|
+
client.post("project/calltracking/phone/delete", body: {phones: phones})
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# POST /project/calltracking/call/list
|
|
55
|
+
def call_list(**body)
|
|
56
|
+
post("project/calltracking/call/list", body: body)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# POST /project/calltracking/call/update
|
|
60
|
+
def call_update(**body)
|
|
61
|
+
client.post("project/calltracking/call/update", body: body)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# POST /project/calltracking/call/delete
|
|
65
|
+
def call_delete(ids:)
|
|
66
|
+
client.post("project/calltracking/call/delete", body: {ids: ids})
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# POST /project/calltracking/call/{callId}/file
|
|
70
|
+
def call_file(call_id:)
|
|
71
|
+
client.post("project/calltracking/call/#{call_id}/file", parse: :binary)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# POST /project/calltracking/call/xls/export
|
|
75
|
+
def call_xls_export(period:)
|
|
76
|
+
client.post(
|
|
77
|
+
"project/calltracking/call/xls/export",
|
|
78
|
+
body: {period: period},
|
|
79
|
+
parse: :binary
|
|
80
|
+
)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# POST /project/calltracking/data
|
|
84
|
+
def data(period:)
|
|
85
|
+
client.post("project/calltracking/data", body: {period: period})
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# POST /project/phone-call
|
|
89
|
+
def phone_call(**body)
|
|
90
|
+
client.post("project/phone-call", body: body)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
|
|
95
|
+
def post(path, body:)
|
|
96
|
+
if body.nil? || body.empty?
|
|
97
|
+
client.post(path)
|
|
98
|
+
else
|
|
99
|
+
client.post(path, body: body)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|