choiceqr 0.1.0 → 0.2.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 +4 -4
- data/README.md +20 -1
- data/lib/choiceqr/version.rb +1 -1
- data/lib/choiceqr/webhook_event.rb +122 -0
- data/lib/choiceqr.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c1977ab8cbeaec88217f43e89bdc837caccb65f844e1a8dfb0916395e8d25d23
|
|
4
|
+
data.tar.gz: 670d2b1b9edbe47c72ef1e2f0f86822deba3f7df451431bad0313ad5ffe2d863
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 157e389e0d57323bff53ea4f82ebc81c8c8eebc2f6df3d3f7072a073699b77a97be15334a744a0614d4305f305fcb7909d12d72a8ae430d7648709a1c490f6c7
|
|
7
|
+
data.tar.gz: 8fc87c2cdb3958d62122a9e2c50ea8d06b04dfb648b5526c69bed1f4195463935dbeaf5bac5f2f5a219ceebba7a5f87de96c00b47d879e15012a6637559b3436
|
data/README.md
CHANGED
|
@@ -228,7 +228,26 @@ client = ChoiceQR::Client.new(
|
|
|
228
228
|
|
|
229
229
|
## Webhooks
|
|
230
230
|
|
|
231
|
-
ChoiceQR pushes events (menu changes, new orders, booking updates, …) to a Webhook URL you configure when creating your application — there is no API for managing webhook subscriptions, so
|
|
231
|
+
ChoiceQR pushes events (menu changes, new orders, booking updates, …) to a Webhook URL you configure when creating your application — there is no API for managing webhook subscriptions, so there's no `client.webhooks`. `ChoiceQR::WebhookEvent` parses the payload your endpoint receives:
|
|
232
|
+
|
|
233
|
+
```ruby
|
|
234
|
+
post "/webhooks/choiceqr" do
|
|
235
|
+
event = ChoiceQR::WebhookEvent.parse(request.body.read)
|
|
236
|
+
|
|
237
|
+
case event.type
|
|
238
|
+
when "dish.created", "dish.changed"
|
|
239
|
+
Dish.upsert_from_choiceqr(event.data) # same shape as Dishes#get
|
|
240
|
+
when "order.created"
|
|
241
|
+
Order.create_from_choiceqr(event.data)
|
|
242
|
+
when "section.positionChanged"
|
|
243
|
+
Section.reorder(event.data.items) # array of section ids
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
`event.data`'s shape depends on `event.type` — usually the same entity schema the matching resource method returns, but `*.positionChanged` events carry `{items: [...ids]}` and `*.removed` events carry just an id. `ChoiceQR::WebhookEvent::TYPES` lists every documented event type (not enforced — an unrecognized `type` still parses fine). See [Webhooks](https://open-api.choiceqr.com/docs/content/webhooks) for the full type → shape mapping.
|
|
249
|
+
|
|
250
|
+
**ChoiceQR does not document a signature or secret for verifying a webhook's authenticity.** `WebhookEvent` parses the payload; it does not, and cannot, confirm the request actually came from ChoiceQR.
|
|
232
251
|
|
|
233
252
|
## Development
|
|
234
253
|
|
data/lib/choiceqr/version.rb
CHANGED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
require "json"
|
|
2
|
+
|
|
3
|
+
module ChoiceQR
|
|
4
|
+
# Wraps an incoming webhook event payload — the thing your own server
|
|
5
|
+
# receives at the Webhook URL configured for your application (see
|
|
6
|
+
# https://open-api.choiceqr.com/docs/content/application), not something
|
|
7
|
+
# this gem calls the API for. ChoiceQR has no API for managing webhook
|
|
8
|
+
# subscriptions (the URL is set once in the app dashboard), so there is no
|
|
9
|
+
# corresponding client.webhooks resource — this class only parses the
|
|
10
|
+
# payload shape.
|
|
11
|
+
#
|
|
12
|
+
# IMPORTANT: ChoiceQR does not document a signature or secret for
|
|
13
|
+
# verifying that a webhook request genuinely came from ChoiceQR. This
|
|
14
|
+
# class parses the payload; it does not, and cannot, authenticate it.
|
|
15
|
+
#
|
|
16
|
+
# Usage (e.g. inside a Rack/Sinatra/Rails webhook endpoint):
|
|
17
|
+
#
|
|
18
|
+
# event = ChoiceQR::WebhookEvent.parse(request.body.read)
|
|
19
|
+
# event.id # => "unique_id"
|
|
20
|
+
# event.type # => "dish.created"
|
|
21
|
+
# event.lang_code # => "en"
|
|
22
|
+
# event.var_symbol # => company id
|
|
23
|
+
#
|
|
24
|
+
# case event.type
|
|
25
|
+
# when "dish.created", "dish.changed"
|
|
26
|
+
# event.data.name # data is the same Dish shape #dishes.get returns
|
|
27
|
+
# when "section.positionChanged"
|
|
28
|
+
# event.data.items # => array of section ids
|
|
29
|
+
# when /\.removed\z/
|
|
30
|
+
# event.data.id # => {_id: "..."} → :id
|
|
31
|
+
# end
|
|
32
|
+
#
|
|
33
|
+
# See https://open-api.choiceqr.com/docs/content/webhooks for the full
|
|
34
|
+
# event type → data shape mapping.
|
|
35
|
+
class WebhookEvent
|
|
36
|
+
# Every event type ChoiceQR documents, for reference — not enforced:
|
|
37
|
+
# #type is whatever string the payload contains, so an event type added
|
|
38
|
+
# to the API later still parses fine here.
|
|
39
|
+
TYPES = %w[
|
|
40
|
+
place.changed
|
|
41
|
+
sectionInfo.changed
|
|
42
|
+
section.created section.changed section.positionChanged section.removed
|
|
43
|
+
category.created category.changed category.positionChanged category.removed
|
|
44
|
+
dish.created dish.changed dish.positionChanged dish.removed
|
|
45
|
+
dishOption.changed
|
|
46
|
+
menuLabel.created menuLabel.changed menuLabel.removed
|
|
47
|
+
option.created option.changed option.positionChanged option.removed
|
|
48
|
+
import.full.done
|
|
49
|
+
marketplace.acceptance.enabled marketplace.acceptance.disabled
|
|
50
|
+
order.created order.accepted order.cancelled order.closed order.delivery.update
|
|
51
|
+
order.qrPayment.completed order.qrPayment.error
|
|
52
|
+
].freeze
|
|
53
|
+
|
|
54
|
+
# +payload+ is a JSON String (e.g. a raw request body) or an
|
|
55
|
+
# already-parsed Hash.
|
|
56
|
+
def self.parse(payload)
|
|
57
|
+
new(payload.is_a?(String) ? JSON.parse(payload) : payload)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def initialize(attributes)
|
|
61
|
+
@resource = Resource.new(attributes)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def id
|
|
65
|
+
@resource.id
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# The event type, e.g. "dish.created", "order.qrPayment.completed" — see
|
|
69
|
+
# TYPES.
|
|
70
|
+
def type
|
|
71
|
+
@resource.type
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def lang_code
|
|
75
|
+
@resource.lang_code
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Uniq identifier of the company the event belongs to.
|
|
79
|
+
def var_symbol
|
|
80
|
+
@resource.var_symbol
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# The event-specific payload. Its shape depends on #type — see the class
|
|
84
|
+
# docs above and https://open-api.choiceqr.com/docs/content/webhooks.
|
|
85
|
+
def data
|
|
86
|
+
@resource.data
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Hash-style access, for any envelope field not covered by a named
|
|
90
|
+
# reader above.
|
|
91
|
+
def [](key)
|
|
92
|
+
@resource[key]
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def to_h
|
|
96
|
+
@resource.to_h
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def inspect
|
|
100
|
+
"#<#{self.class.name} type=#{type.inspect} id=#{id.inspect}>"
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def to_s
|
|
104
|
+
inspect
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def respond_to_missing?(name, include_private = false)
|
|
108
|
+
@resource.respond_to?(name, include_private) || super
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Delegates to the underlying Resource, so any envelope field not given
|
|
112
|
+
# a named reader above (or a documented-but-misspelled one) is still
|
|
113
|
+
# reachable by dot access.
|
|
114
|
+
def method_missing(name, *, &)
|
|
115
|
+
if @resource.respond_to?(name)
|
|
116
|
+
@resource.public_send(name, *, &)
|
|
117
|
+
else
|
|
118
|
+
super
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
data/lib/choiceqr.rb
CHANGED
|
@@ -3,6 +3,7 @@ require_relative "choiceqr/errors"
|
|
|
3
3
|
require_relative "choiceqr/configuration"
|
|
4
4
|
require_relative "choiceqr/key_transformer"
|
|
5
5
|
require_relative "choiceqr/resource"
|
|
6
|
+
require_relative "choiceqr/webhook_event"
|
|
6
7
|
require_relative "choiceqr/resources/base"
|
|
7
8
|
require_relative "choiceqr/resources/place"
|
|
8
9
|
require_relative "choiceqr/resources/section_info"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: choiceqr
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Stockbird Team
|
|
@@ -142,6 +142,7 @@ files:
|
|
|
142
142
|
- lib/choiceqr/resources/section_info.rb
|
|
143
143
|
- lib/choiceqr/resources/sections.rb
|
|
144
144
|
- lib/choiceqr/version.rb
|
|
145
|
+
- lib/choiceqr/webhook_event.rb
|
|
145
146
|
homepage: https://github.com/stockbird-app/choiceqr
|
|
146
147
|
licenses:
|
|
147
148
|
- MIT
|