roistat 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: dc3ca5eb2fe6830464f24590db99766e8c47a187446b3d796893e4ef4baf2701
4
- data.tar.gz: bcbb3c3a15ec149839e00c6ec9cc30f428c7ad285230d3190c93bb271b9af085
3
+ metadata.gz: 9873e205875775701ebef069abc68ec70b403bac27fb3e264af27a66f0305b38
4
+ data.tar.gz: 89b775556fc61133d16453a1482ae1e369c98da2c81210ff497f98e51fdbfdcf
5
5
  SHA512:
6
- metadata.gz: e09ebca699583d9c4d35cd9a9fdeb7c6c788041c58172589590c3ebffec1427b0919304fbe52d479d3362ab6d4635651b81c2ce34c8dac78bc51578d4b787f85
7
- data.tar.gz: 99a0d714445b30a106af7350d006913b1b9ae937c53ad9da276e20dde24bd9e28e8a5c5cf9a6a5e75bea43bae0aef55202d2260fa346a6ff4d41ca818d451f1d
6
+ metadata.gz: 4f86543be62749ddb2f4f57a9bc3a67634d69438c83f9878dc5be52ac03e450bccd9383fde491086ea7b08a1d2ce81b79109e0379399b27217716b0ebe668042
7
+ data.tar.gz: eaffd7ee92d8e4ef316e2a0bb910ea1ae20ff381459b475148b225172256309194dd0f252e5516e471fdbc695f8130780769f23e01f15508602b47bfb4a674b5
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ ## [0.1.1] — 2026-07-23
2
+
3
+ ### Fixed
4
+
5
+ - Escape IDs interpolated into request paths (`orders`, `dashboards`, `calltracking`, `events`, `indicators`, `emailtracking`, `proxy_leads`, `widgets`) so values containing `/`, `?`, `#`, or spaces can't corrupt the request path or inject query parameters
6
+ - `widgets.data(method: :get)` now forwards extra keyword arguments as query params instead of silently dropping them
7
+
8
+ ### Changed
9
+
10
+ - Centralized empty-body handling in `Roistat::Client#request`; resource classes now call `client.post` directly instead of a per-class `post`/`post_optional_body` helper
11
+
1
12
  ## [0.1.0] — 2026-07-22
2
13
 
3
14
  ### Added
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Ruby wrapper for the [Roistat REST API](https://help-ru.roistat.com/API/methods/about/).
4
4
 
5
- **[Документация на русском](docs/ru/README.md)**
5
+ **[Документация на русском](docs/ru/README.md)** · **[Demo](https://github.com/alec-c4/roistat_demo)**
6
6
 
7
7
  The gem sends every request with the `Api-key` header (never as a `key` query param). Project-scoped calls also send `project` in the query string.
8
8
 
@@ -741,10 +741,13 @@ Interactive console:
741
741
  bin/console
742
742
  ```
743
743
 
744
+ Read-only playground: [roistat_demo](https://github.com/alec-c4/roistat_demo).
745
+
744
746
  Release:
745
747
 
746
748
  ```bash
747
- mise release
749
+ mise release # build gem, create tag, push gem + tag
750
+ mise github-release # create GitHub Release for v$VERSION (needs gh + existing tag)
748
751
  # or: bundle exec rake release
749
752
  ```
750
753
 
data/docs/ru/README.md CHANGED
@@ -4,6 +4,8 @@ How-to для разработчиков, которые подключают г
4
4
 
5
5
  **Предпосылки:** Ruby 3+, ключ API Roistat, id проекта. Полные таблицы методов — в [корневом README](../../README.md) (английский).
6
6
 
7
+ Демо с read-only вызовами: [roistat_demo](https://github.com/alec-c4/roistat_demo).
8
+
7
9
  Официальные справочники Roistat:
8
10
 
9
11
  - [help-ru](https://help-ru.roistat.com/API/methods/about/) — основная инвентаризация путей
@@ -139,4 +141,6 @@ bundle exec rake
139
141
 
140
142
  Интерактивная консоль гема: `bin/console`.
141
143
 
144
+ Демо-репозиторий: [roistat_demo](https://github.com/alec-c4/roistat_demo).
145
+
142
146
  Багрепорты и PR: https://github.com/alec-c4/roistat
@@ -73,7 +73,7 @@ class Roistat::Client
73
73
  }
74
74
 
75
75
  options = {params: stringify_keys(query), headers: headers}
76
- if body
76
+ if present_body?(body)
77
77
  headers["Content-Type"] = "application/json"
78
78
  options[:json] = body
79
79
  end
@@ -193,6 +193,10 @@ class Roistat::Client
193
193
  value.nil? || value.to_s.strip.empty?
194
194
  end
195
195
 
196
+ def present_body?(body)
197
+ body && !(body.respond_to?(:empty?) && body.empty?)
198
+ end
199
+
196
200
  def url_for(path)
197
201
  "#{base_url.to_s.chomp("/")}/#{path.to_s.delete_prefix("/")}"
198
202
  end
@@ -3,7 +3,7 @@
3
3
  class Roistat::Resources::Analytics < Roistat::Resources::Base
4
4
  # POST /project/analytics/data
5
5
  def data(**body)
6
- post_optional_body("project/analytics/data", body)
6
+ client.post("project/analytics/data", body: body)
7
7
  end
8
8
 
9
9
  # POST /project/analytics/data/export/excel
@@ -13,27 +13,27 @@ class Roistat::Resources::Analytics < Roistat::Resources::Base
13
13
 
14
14
  # POST /project/analytics/metrics-new
15
15
  def metrics_new(**body)
16
- post_optional_body("project/analytics/metrics-new", body)
16
+ client.post("project/analytics/metrics-new", body: body)
17
17
  end
18
18
 
19
19
  # POST /project/analytics/dimensions
20
20
  def dimensions(**body)
21
- post_optional_body("project/analytics/dimensions", body)
21
+ client.post("project/analytics/dimensions", body: body)
22
22
  end
23
23
 
24
24
  # POST /project/analytics/dimension-values
25
25
  def dimension_values(**body)
26
- post_optional_body("project/analytics/dimension-values", body)
26
+ client.post("project/analytics/dimension-values", body: body)
27
27
  end
28
28
 
29
29
  # POST /project/analytics/attribution-models
30
30
  def attribution_models(**body)
31
- post_optional_body("project/analytics/attribution-models", body)
31
+ client.post("project/analytics/attribution-models", body: body)
32
32
  end
33
33
 
34
34
  # POST /project/analytics/list-orders
35
35
  def list_orders(**body)
36
- post_optional_body("project/analytics/list-orders", body)
36
+ client.post("project/analytics/list-orders", body: body)
37
37
  end
38
38
 
39
39
  # GET /project/analytics/metrics/custom/list
@@ -43,7 +43,7 @@ class Roistat::Resources::Analytics < Roistat::Resources::Base
43
43
 
44
44
  # POST /project/analytics/metrics/custom/manual/value/list
45
45
  def custom_manual_value_list(**body)
46
- post_optional_body("project/analytics/metrics/custom/manual/value/list", body)
46
+ client.post("project/analytics/metrics/custom/manual/value/list", body: body)
47
47
  end
48
48
 
49
49
  # POST /project/analytics/metrics/custom/manual/value/add
@@ -58,7 +58,7 @@ class Roistat::Resources::Analytics < Roistat::Resources::Base
58
58
 
59
59
  # POST /project/reports/funnel/data
60
60
  def funnel_data(**body)
61
- post_optional_body("project/reports/funnel/data", body)
61
+ client.post("project/reports/funnel/data", body: body)
62
62
  end
63
63
 
64
64
  # POST /project/analytics/event/add
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "erb"
4
+
3
5
  class Roistat::Resources::Base
4
6
  attr_reader :client
5
7
 
@@ -21,11 +23,10 @@ class Roistat::Resources::Base
21
23
  )
22
24
  end
23
25
 
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
26
+ # Escapes a value for safe interpolation into a URL path segment (IDs may
27
+ # be arbitrary external strings, e.g. CRM order ids), so characters like
28
+ # "/", "?", "#" can't alter the request path or inject query parameters.
29
+ def escape_path_segment(value)
30
+ ERB::Util.url_encode(value.to_s)
30
31
  end
31
32
  end
@@ -3,7 +3,7 @@
3
3
  class Roistat::Resources::Calltracking < Roistat::Resources::Base
4
4
  # POST /project/calltracking/script/list
5
5
  def script_list(**body)
6
- post("project/calltracking/script/list", body: body)
6
+ client.post("project/calltracking/script/list", body: body)
7
7
  end
8
8
 
9
9
  # POST /project/calltracking/script/create
@@ -23,12 +23,12 @@ class Roistat::Resources::Calltracking < Roistat::Resources::Base
23
23
 
24
24
  # POST /project/calltracking/phone/list
25
25
  def phone_list(**body)
26
- post("project/calltracking/phone/list", body: body)
26
+ client.post("project/calltracking/phone/list", body: body)
27
27
  end
28
28
 
29
29
  # POST /project/calltracking/phone/prefix/list
30
30
  def phone_prefix_list(**body)
31
- post("project/calltracking/phone/prefix/list", body: body)
31
+ client.post("project/calltracking/phone/prefix/list", body: body)
32
32
  end
33
33
 
34
34
  # POST /project/calltracking/phone/create
@@ -53,7 +53,7 @@ class Roistat::Resources::Calltracking < Roistat::Resources::Base
53
53
 
54
54
  # POST /project/calltracking/call/list
55
55
  def call_list(**body)
56
- post("project/calltracking/call/list", body: body)
56
+ client.post("project/calltracking/call/list", body: body)
57
57
  end
58
58
 
59
59
  # POST /project/calltracking/call/update
@@ -68,7 +68,7 @@ class Roistat::Resources::Calltracking < Roistat::Resources::Base
68
68
 
69
69
  # POST /project/calltracking/call/{callId}/file
70
70
  def call_file(call_id:)
71
- client.post("project/calltracking/call/#{call_id}/file", parse: :binary)
71
+ client.post("project/calltracking/call/#{escape_path_segment(call_id)}/file", parse: :binary)
72
72
  end
73
73
 
74
74
  # POST /project/calltracking/call/xls/export
@@ -89,14 +89,4 @@ class Roistat::Resources::Calltracking < Roistat::Resources::Base
89
89
  def phone_call(**body)
90
90
  client.post("project/phone-call", body: body)
91
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
92
  end
@@ -3,12 +3,12 @@
3
3
  class Roistat::Resources::Channels < Roistat::Resources::Base
4
4
  # POST /project/analytics/source/list
5
5
  def source_list(**body)
6
- post_optional_body("project/analytics/source/list", body)
6
+ client.post("project/analytics/source/list", body: body)
7
7
  end
8
8
 
9
9
  # POST /project/analytics/source/cost/list
10
10
  def cost_list(**body)
11
- post_optional_body("project/analytics/source/cost/list", body)
11
+ client.post("project/analytics/source/cost/list", body: body)
12
12
  end
13
13
 
14
14
  # POST /project/analytics/source/cost/add
@@ -3,7 +3,7 @@
3
3
  class Roistat::Resources::Clients < Roistat::Resources::Base
4
4
  # POST /project/clients
5
5
  def list(**body)
6
- post("project/clients", body: body)
6
+ client.post("project/clients", body: body)
7
7
  end
8
8
 
9
9
  # POST /project/clients/import — body is a JSON array
@@ -18,21 +18,11 @@ class Roistat::Resources::Clients < Roistat::Resources::Base
18
18
 
19
19
  # POST /project/clients/campaign/list
20
20
  def campaign_list(**body)
21
- post("project/clients/campaign/list", body: body)
21
+ client.post("project/clients/campaign/list", body: body)
22
22
  end
23
23
 
24
24
  # POST /project/clients/campaign/contact/list
25
25
  def campaign_contact_list(**body)
26
- post("project/clients/campaign/contact/list", body: body)
27
- end
28
-
29
- private
30
-
31
- def post(path, body:)
32
- if body.nil? || body.empty?
33
- client.post(path)
34
- else
35
- client.post(path, body: body)
36
- end
26
+ client.post("project/clients/campaign/contact/list", body: body)
37
27
  end
38
28
  end
@@ -8,6 +8,6 @@ class Roistat::Resources::Dashboards < Roistat::Resources::Base
8
8
 
9
9
  # GET /project/dashboards/{dashboardId}/widgets
10
10
  def widgets(dashboard_id:)
11
- client.get("project/dashboards/#{dashboard_id}/widgets")
11
+ client.get("project/dashboards/#{escape_path_segment(dashboard_id)}/widgets")
12
12
  end
13
13
  end
@@ -3,13 +3,14 @@
3
3
  class Roistat::Resources::Emailtracking < Roistat::Resources::Base
4
4
  # POST /project/emailtracking/email/list
5
5
  def list(**body)
6
- post_optional_body("project/emailtracking/email/list", body)
6
+ client.post("project/emailtracking/email/list", body: body)
7
7
  end
8
8
 
9
9
  # GET /project/emailtracking/email/{email_id}/attachment/{attachment_id}
10
10
  def attachment(email_id:, attachment_id:)
11
11
  client.get(
12
- "project/emailtracking/email/#{email_id}/attachment/#{attachment_id}",
12
+ "project/emailtracking/email/#{escape_path_segment(email_id)}/attachment/" \
13
+ "#{escape_path_segment(attachment_id)}",
13
14
  parse: :binary
14
15
  )
15
16
  end
@@ -27,16 +27,6 @@ class Roistat::Resources::Events < Roistat::Resources::Base
27
27
 
28
28
  # POST /project/events/meta/{eventId}/archive — body is a JSON array
29
29
  def archive(event_id:, events:)
30
- client.post("project/events/meta/#{event_id}/archive", body: events)
31
- end
32
-
33
- private
34
-
35
- def post(path, body:)
36
- if body.nil? || body.empty?
37
- client.post(path)
38
- else
39
- client.post(path, body: body)
40
- end
30
+ client.post("project/events/meta/#{escape_path_segment(event_id)}/archive", body: events)
41
31
  end
42
32
  end
@@ -8,6 +8,6 @@ class Roistat::Resources::Indicators < Roistat::Resources::Base
8
8
 
9
9
  # POST /project/health/indicator/{indicatorId}/run-script
10
10
  def run_script(indicator_id:)
11
- client.post("project/health/indicator/#{indicator_id}/run-script")
11
+ client.post("project/health/indicator/#{escape_path_segment(indicator_id)}/run-script")
12
12
  end
13
13
  end
@@ -3,12 +3,12 @@
3
3
  class Roistat::Resources::Leads < Roistat::Resources::Base
4
4
  # POST /project/leads/lead/list
5
5
  def list(**body)
6
- post("project/leads/lead/list", body: body)
6
+ client.post("project/leads/lead/list", body: body)
7
7
  end
8
8
 
9
9
  # POST /project/leads/status/list
10
10
  def status_list(**body)
11
- post("project/leads/status/list", body: body)
11
+ client.post("project/leads/status/list", body: body)
12
12
  end
13
13
 
14
14
  # POST /project/leads/lead/create
@@ -20,14 +20,4 @@ class Roistat::Resources::Leads < Roistat::Resources::Base
20
20
  def update(**body)
21
21
  client.post("project/leads/lead/update", body: body)
22
22
  end
23
-
24
- private
25
-
26
- def post(path, body:)
27
- if body.nil? || body.empty?
28
- client.post(path)
29
- else
30
- client.post(path, body: body)
31
- end
32
- end
33
23
  end
@@ -3,7 +3,7 @@
3
3
  class Roistat::Resources::Managers < Roistat::Resources::Base
4
4
  # POST /project/integration/manager/list
5
5
  def list(**body)
6
- post("project/integration/manager/list", body: body)
6
+ client.post("project/integration/manager/list", body: body)
7
7
  end
8
8
 
9
9
  # POST /project/integration/manager/add
@@ -20,14 +20,4 @@ class Roistat::Resources::Managers < Roistat::Resources::Base
20
20
  def delete(id:)
21
21
  client.post("project/integration/manager/delete", body: {id: id})
22
22
  end
23
-
24
- private
25
-
26
- def post(path, body:)
27
- if body.nil? || body.empty?
28
- client.post(path)
29
- else
30
- client.post(path, body: body)
31
- end
32
- end
33
23
  end
@@ -3,7 +3,7 @@
3
3
  class Roistat::Resources::Mediaplan < Roistat::Resources::Base
4
4
  # POST /project/mediaplan/target/list
5
5
  def target_list(**body)
6
- post_optional_body("project/mediaplan/target/list", body)
6
+ client.post("project/mediaplan/target/list", body: body)
7
7
  end
8
8
 
9
9
  # POST /project/mediaplan/target/create
@@ -3,7 +3,7 @@
3
3
  class Roistat::Resources::Orders < Roistat::Resources::Base
4
4
  # POST /project/integration/order/list
5
5
  def list(**body)
6
- post("project/integration/order/list", body: body)
6
+ client.post("project/integration/order/list", body: body)
7
7
  end
8
8
 
9
9
  # POST /project/add-orders — body is a JSON array
@@ -13,17 +13,17 @@ class Roistat::Resources::Orders < Roistat::Resources::Base
13
13
 
14
14
  # GET /project/orders/{orderId}/info
15
15
  def info(order_id:)
16
- client.get("project/orders/#{order_id}/info")
16
+ client.get("project/orders/#{escape_path_segment(order_id)}/info")
17
17
  end
18
18
 
19
19
  # GET /project/orders/{orderId}/external-url
20
20
  def external_url(order_id:)
21
- client.get("project/orders/#{order_id}/external-url")
21
+ client.get("project/orders/#{escape_path_segment(order_id)}/external-url")
22
22
  end
23
23
 
24
24
  # POST /project/integration/status/list
25
25
  def status_list(**body)
26
- post("project/integration/status/list", body: body)
26
+ client.post("project/integration/status/list", body: body)
27
27
  end
28
28
 
29
29
  # POST /project/set-statuses — body is a JSON array
@@ -33,20 +33,20 @@ class Roistat::Resources::Orders < Roistat::Resources::Base
33
33
 
34
34
  # POST /project/analytics/order-custom-fields
35
35
  def custom_fields(**body)
36
- post("project/analytics/order-custom-fields", body: body)
36
+ client.post("project/analytics/order-custom-fields", body: body)
37
37
  end
38
38
 
39
39
  # POST /project/integration/order/{orderId}/status/update
40
40
  def status_update(order_id:, status_id:)
41
41
  client.post(
42
- "project/integration/order/#{order_id}/status/update",
42
+ "project/integration/order/#{escape_path_segment(order_id)}/status/update",
43
43
  body: {status_id: status_id}
44
44
  )
45
45
  end
46
46
 
47
47
  # POST /project/integration/order/{orderId}/goal/update
48
48
  def goal_update(order_id:, **body)
49
- client.post("project/integration/order/#{order_id}/goal/update", body: body)
49
+ client.post("project/integration/order/#{escape_path_segment(order_id)}/goal/update", body: body)
50
50
  end
51
51
 
52
52
  # POST /project/integration/order/update
@@ -56,21 +56,11 @@ class Roistat::Resources::Orders < Roistat::Resources::Base
56
56
 
57
57
  # POST /project/integration/order/{orderId}/delete
58
58
  def delete(order_id:)
59
- client.post("project/integration/order/#{order_id}/delete")
59
+ client.post("project/integration/order/#{escape_path_segment(order_id)}/delete")
60
60
  end
61
61
 
62
62
  # POST /project/integration/order/delete
63
63
  def delete_many(ids:)
64
64
  client.post("project/integration/order/delete", body: {ids: ids})
65
65
  end
66
-
67
- private
68
-
69
- def post(path, body:)
70
- if body.nil? || body.empty?
71
- client.post(path)
72
- else
73
- client.post(path, body: body)
74
- end
75
- end
76
66
  end
@@ -13,6 +13,6 @@ class Roistat::Resources::ProxyLeads < Roistat::Resources::Base
13
13
 
14
14
  # GET /project/proxy-leads/{proxyLeadId}
15
15
  def get(id:)
16
- client.get("project/proxy-leads/#{id}")
16
+ client.get("project/proxy-leads/#{escape_path_segment(id)}")
17
17
  end
18
18
  end
@@ -3,7 +3,7 @@
3
3
  class Roistat::Resources::Speech < Roistat::Resources::Base
4
4
  # POST /project/speech/call/list
5
5
  def call_list(**body)
6
- post_optional_body("project/speech/call/list", body)
6
+ client.post("project/speech/call/list", body: body)
7
7
  end
8
8
 
9
9
  # POST /project/speech/call/list/export/excel
@@ -28,12 +28,12 @@ class Roistat::Resources::Speech < Roistat::Resources::Base
28
28
 
29
29
  # POST /project/speech/call/transcription/list
30
30
  def call_transcription_list(**body)
31
- post_optional_body("project/speech/call/transcription/list", body)
31
+ client.post("project/speech/call/transcription/list", body: body)
32
32
  end
33
33
 
34
34
  # POST /project/speech/dictionary/list
35
35
  def dictionary_list(**body)
36
- post_optional_body("project/speech/dictionary/list", body)
36
+ client.post("project/speech/dictionary/list", body: body)
37
37
  end
38
38
 
39
39
  # POST /project/speech/dictionary/custom/create
@@ -53,12 +53,12 @@ class Roistat::Resources::Speech < Roistat::Resources::Base
53
53
 
54
54
  # POST /project/speech/dictionary/custom/phrase/list
55
55
  def dictionary_custom_phrase_list(**body)
56
- post_optional_body("project/speech/dictionary/custom/phrase/list", body)
56
+ client.post("project/speech/dictionary/custom/phrase/list", body: body)
57
57
  end
58
58
 
59
59
  # POST /project/speech/settings/list
60
60
  def settings_list(**body)
61
- post_optional_body("project/speech/settings/list", body)
61
+ client.post("project/speech/settings/list", body: body)
62
62
  end
63
63
 
64
64
  # POST /project/speech/settings/update
@@ -3,21 +3,11 @@
3
3
  class Roistat::Resources::Visits < Roistat::Resources::Base
4
4
  # POST /project/site/visit/list
5
5
  def list(**body)
6
- post("project/site/visit/list", body: body)
6
+ client.post("project/site/visit/list", body: body)
7
7
  end
8
8
 
9
9
  # POST /project/site/visit/params/update
10
10
  def params_update(**body)
11
11
  client.post("project/site/visit/params/update", body: body)
12
12
  end
13
-
14
- private
15
-
16
- def post(path, body:)
17
- if body.nil? || body.empty?
18
- client.post(path)
19
- else
20
- client.post(path, body: body)
21
- end
22
- end
23
13
  end
@@ -3,12 +3,12 @@
3
3
  class Roistat::Resources::Vpbx < Roistat::Resources::Base
4
4
  # POST /project/vpbx/call/list
5
5
  def call_list(**body)
6
- post_optional_body("project/vpbx/call/list", body)
6
+ client.post("project/vpbx/call/list", body: body)
7
7
  end
8
8
 
9
9
  # POST /project/vpbx/operator/list
10
10
  def operator_list(**body)
11
- post_optional_body("project/vpbx/operator/list", body)
11
+ client.post("project/vpbx/operator/list", body: body)
12
12
  end
13
13
 
14
14
  # POST /project/vpbx/operator/create
@@ -28,7 +28,7 @@ class Roistat::Resources::Vpbx < Roistat::Resources::Base
28
28
 
29
29
  # POST /project/vpbx/operator/group/list
30
30
  def operator_group_list(**body)
31
- post_optional_body("project/vpbx/operator/group/list", body)
31
+ client.post("project/vpbx/operator/group/list", body: body)
32
32
  end
33
33
 
34
34
  # POST /project/vpbx/operator/group/create
@@ -83,7 +83,7 @@ class Roistat::Resources::Vpbx < Roistat::Resources::Base
83
83
 
84
84
  # POST /project/vpbx/report/data
85
85
  def report_data(**body)
86
- post_optional_body("project/vpbx/report/data", body)
86
+ client.post("project/vpbx/report/data", body: body)
87
87
  end
88
88
 
89
89
  # POST /project/vpbx/settings/update
@@ -3,13 +3,13 @@
3
3
  class Roistat::Resources::Widgets < Roistat::Resources::Base
4
4
  # GET|POST /project/widget/{widgetId}/data — help-en; curl usually POSTs.
5
5
  def data(widget_id:, method: :post, **body)
6
- path = "project/widget/#{widget_id}/data"
6
+ path = "project/widget/#{escape_path_segment(widget_id)}/data"
7
7
 
8
8
  case method.to_sym
9
9
  when :get
10
- client.get(path)
10
+ client.get(path, params: body)
11
11
  when :post
12
- post_optional_body(path, body)
12
+ client.post(path, body: body)
13
13
  else
14
14
  raise ArgumentError, "method must be :get or :post"
15
15
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Roistat
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.1"
5
5
  end
data/mise.toml CHANGED
@@ -12,3 +12,15 @@ run = "bundle exec rubocop"
12
12
  [tasks.release]
13
13
  description = "Build and publish the gem (rake release)"
14
14
  run = "bundle exec rake release"
15
+
16
+ [tasks.github-release]
17
+ description = "Create a GitHub Release for the current VERSION tag"
18
+ run = """
19
+ version="$(ruby -e 'require_relative \"lib/roistat/version\"; print Roistat::VERSION')"
20
+ tag="v${version}"
21
+ if ! git rev-parse "${tag}" >/dev/null 2>&1; then
22
+ echo "Missing tag ${tag}. Create and push it first (or run mise release)." >&2
23
+ exit 1
24
+ fi
25
+ gh release create "${tag}" --title "${tag}" --generate-notes
26
+ """
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: roistat
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
  - Alexey Poimtsev