giftbit 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,60 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://testbedapp.giftbit.com/papi/v1/marketplace/vendors
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - application/json
12
+ Accept-Encoding:
13
+ - gzip, deflate
14
+ User-Agent:
15
+ - rest-client/2.0.0 (darwin16.3.0 x86_64) ruby/2.4.0p0
16
+ Authorization:
17
+ - Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJTSEEyNTYifQ==.TFdWYU5VTVhzK3JFaVhHT2p5VDRHNFRsUk1ybnk2V2E4TDNDSW5meEdXdTVERUJNeHlDTEU1K216Qk1hb3Q4QlZaTVJvWndjR2ZoS01xc3gzdnZMUHdQckN1Z0kreG9rYVF3c1JjUjNkNlNLVmROQTlJb0hvMmpHdkx2REh3NXE=.cu7N3bPxGg8fPxFsIUcjyOISwn+29YpB0l7YDHwkMDg=
18
+ Content-Type:
19
+ - application/json
20
+ Host:
21
+ - testbedapp.giftbit.com
22
+ response:
23
+ status:
24
+ code: 200
25
+ message: OK
26
+ headers:
27
+ Content-Type:
28
+ - application/json;charset=UTF-8
29
+ Content-Length:
30
+ - '6443'
31
+ Connection:
32
+ - keep-alive
33
+ Cache-Control:
34
+ - no-cache="set-cookie"
35
+ - private, max-age=60
36
+ Date:
37
+ - Tue, 14 Feb 2017 19:41:58 GMT
38
+ Expires:
39
+ - Tue, 14 Feb 2017 19:42:59 GMT
40
+ Last-Modified:
41
+ - Tue, 14 Feb 2017 19:41:59 GMT
42
+ P3p:
43
+ - CP="Giftbit"
44
+ Server:
45
+ - Apache-Coyote/1.1
46
+ X-Frame-Options:
47
+ - SAMEORIGIN
48
+ X-Cache:
49
+ - Miss from cloudfront
50
+ Via:
51
+ - 1.1 84760d59a7d324aa7adc2bf9d8f7fd4b.cloudfront.net (CloudFront)
52
+ X-Amz-Cf-Id:
53
+ - eB12IajU_EKqKyvMESo_-rMEv8hflBnPBkHRf6R1iGvGRN3O1IRR-g==
54
+ body:
55
+ encoding: ASCII-8BIT
56
+ string: !binary |-
57
+ eyJ2ZW5kb3JzIjpbeyJpZCI6ODYsIm5hbWUiOiJBbWF6b24uY2EiLCJpbWFnZV91cmwiOiJodHRwczovL3VwbG9hZGVkaW1hZ2VzdGVzdGJlZC5naWZ0Yml0LmNvbS8xNDEvYW1hem9uY2EtOWNiMTRjZWYtOGI3OC00YzE1LWJmZDYtMmRhNDFiNDk1Y2E0LmpwZyIsImRpc2NsYWltZXIiOiIqQW1hem9uLmNhIEdpZnQgQ2VydGlmaWNhdGVzIChcIkdDc1wiKSBzb2xkIGJ5IEtpaW5kIEluYy4gREJBIEdpZnRiaXQsIGFuIGF1dGhvcml6ZWQgYW5kIGluZGVwZW5kZW50IHJlc2VsbGVyIG9mIEFtYXpvbi5jYSBHaWZ0IENlcnRpZmljYXRlcy4gR0NzIGFyZSByZWRlZW1hYmxlIG9ubHkgZm9yIGVsaWdpYmxlIHByb2R1Y3RzIG9uIEFtYXpvbi5jYS4gUmV0dXJuIHBvbGljaWVzIGZvciBwcm9kdWN0cyBhcmUgYXZhaWxhYmxlIG9uIEFtYXpvbi5jYS4gRXhjZXB0IGFzIHJlcXVpcmVkIGJ5IGxhdywgR0NzIGNhbm5vdCBiZSByZWxvYWRlZCwgcmVzb2xkLCB0cmFuc2ZlcnJlZCBmb3IgdmFsdWUsIHJlZGVlbWVkIGZvciBjYXNoIG9yIGFwcGxpZWQgdG8gYW55IG90aGVyIGFjY291bnQuIFRvIHZpZXcgYSBHQyBiYWxhbmNlIG9yIGZvciBtb3JlIGluZm9ybWF0aW9uIGFib3V0IHlvdXIgR0MsIHZpc2l0IFwiWW91ciBBY2NvdW50XCIgb24gQW1hem9uLmNhIG9yIGNvbnRhY3QgdXMgYXQgd3d3LmFtYXpvbi5jYS9jb250YWN0LXVzLiBHQ3MgY2Fubm90IGJlIHVzZWQgdG8gcHVyY2hhc2Ugb3RoZXIgR0NzLiBBbWF6b24gaXMgbm90IHJlc3BvbnNpYmxlIGlmIGEgR0MgaXMgbG9zdCwgc3RvbGVuLCBkZXN0cm95ZWQgb3IgdXNlZCB3aXRob3V0IHBlcm1pc3Npb24uIEZvciBjb21wbGV0ZSB0ZXJtcyBhbmQgY29uZGl0aW9ucywgc2VlIHd3dy5hbWF6b24uY2EvZ2MtbGVnYWwuIEdDcyBhcmUgaXNzdWVkIGJ5IEFtYXpvbi5jb20uY2EsIEluYy4sIGEgRGVsYXdhcmUgY29ycG9yYXRpb24uIEFsbCBBbWF6b24gwq4sIOKEoiAmIMKpIGFyZSBJUCBvZiBBbWF6b24uY29tLCBJbmMuIG9yIGl0cyBhZmZpbGlhdGVzLiBObyBleHBpcmF0aW9uIGRhdGUgb3Igc2VydmljZSBmZWVzLiJ9LHsiaWQiOjc5LCJuYW1lIjoiQW1hem9uIiwiaW1hZ2VfdXJsIjoiaHR0cHM6Ly91cGxvYWRlZGltYWdlc3Rlc3RiZWQuZ2lmdGJpdC5jb20vODAvYW1hem9uLTMwZWM4ZjdhLTYxNmEtNDZhYS1hYTNmLWNhZmJjYTEwYmRkYy5qcGciLCJkaXNjbGFpbWVyIjoiQW1hem9uLmNvbSBHaWZ0IENhcmRzIChcIkdDc1wiKSBzb2xkIGJ5IEtpaW5kIEluYy4sIGFuIGF1dGhvcml6ZWQgYW5kIGluZGVwZW5kZW50IHJlc2VsbGVyIG9mIEFtYXpvbi5jb20gR2lmdCBDYXJkcy4gRXhjZXB0IGFzIHJlcXVpcmVkIGJ5IGxhdywgR0NzIGNhbm5vdCBiZSB0cmFuc2ZlcnJlZCBmb3IgdmFsdWUgb3IgcmVkZWVtZWQgZm9yIGNhc2guIEdDcyBtYXkgYmUgdXNlZCBvbmx5IGZvciBwdXJjaGFzZXMgb2YgZWxpZ2libGUgZ29vZHMgYXQgQW1hem9uLmNvbSBvciBjZXJ0YWluIG9mIGl0cyBhZmZpbGlhdGVkIHdlYnNpdGVzLiBGb3IgY29tcGxldGUgdGVybXMgYW5kIGNvbmRpdGlvbnMsIHNlZSB3d3cuYW1hem9uLmNvbS9nYy1sZWdhbC4gR0NzIGFyZSBpc3N1ZWQgYnkgQUNJIEdpZnQgQ2FyZHMsIEluYy4sIGEgV2FzaGluZ3RvbiBjb3Jwb3JhdGlvbi4gwqkswq4s4oSiIEFtYXpvbi5jb20gSW5jLiBhbmQvb3IgaXRzIGFmZmlsaWF0ZXMsIDIwMTMuIE5vIGV4cGlyYXRpb24gZGF0ZSBvciBzZXJ2aWNlIGZlZXMuIn0seyJpZCI6MTMxLCJuYW1lIjoiV2FsbWFydCIsImltYWdlX3VybCI6Imh0dHBzOi8vdXBsb2FkZWRpbWFnZXN0ZXN0YmVkLmdpZnRiaXQuY29tLzIyNi9XYWxtYXJ0bG9nby04MzIwZWJlMS1hNWJhLTQxYmItYTVlMC0wYjM4OGMwZDY4MzMucG5nIn0seyJpZCI6ODAsIm5hbWUiOiJpVHVuZXMgQ2FuYWRhIiwiaW1hZ2VfdXJsIjoiaHR0cHM6Ly91cGxvYWRlZGltYWdlc3Rlc3RiZWQuZ2lmdGJpdC5jb20vMTA1L2lUdW5lczItZTU3MmVhY2ItZTU1MC00MmMxLTk5MWItZGU0YmJiNjQ3NWYwLmpwZyIsImRpc2NsYWltZXIiOiJNYWMgYW5kIE9TIFggYXJlIHRyYWRlbWFya3Mgb2YgQXBwbGUgSW5jLiwgcmVnaXN0ZXJlZCBpbiB0aGUgVS5TLiBhbmQgb3RoZXIgY291bnRyaWVzLiBpVHVuZXMgaXMgYSByZWdpc3RlcmVkIHRyYWRlbWFyayBvZiBBcHBsZSBJbmMuLCBBbGwgcmlnaHRzIHJlc2VydmVkLiJ9LHsiaWQiOjgxLCJuYW1lIjoiaVR1bmVzIFVTQSIsImltYWdlX3VybCI6Imh0dHBzOi8vdXBsb2FkZWRpbWFnZXN0ZXN0YmVkLmdpZnRiaXQuY29tLzEwNi9pVHVuZXMyLTQ4OTdjODJhLTViZGQtNDI3Ni04NTUyLTU0MzQzOGU3MDkxYy5qcGciLCJkaXNjbGFpbWVyIjoiTWFjIGFuZCBPUyBYIGFyZSB0cmFkZW1hcmtzIG9mIEFwcGxlIEluYy4sIHJlZ2lzdGVyZWQgaW4gdGhlIFUuUy4gYW5kIG90aGVyIGNvdW50cmllcy4gaVR1bmVzIGlzIGEgcmVnaXN0ZXJlZCB0cmFkZW1hcmsgb2YgQXBwbGUgSW5jLiwgQWxsIHJpZ2h0cyByZXNlcnZlZC4ifSx7ImlkIjoxMDgsIm5hbWUiOiJUYXJnZXQiLCJpbWFnZV91cmwiOiJodHRwczovL3VwbG9hZGVkaW1hZ2VzdGVzdGJlZC5naWZ0Yml0LmNvbS8xNjEvdGFyZ2V0LTNhOTlmYjJkLTAwZTgtNDg0ZC1hMjJmLTRlOTY2MTZjMDM0Yi5QTkciLCJkaXNjbGFpbWVyIjoiVGhlIEJ1bGxzZXllIERlc2lnbiwgVGFyZ2V0IGFuZCBUYXJnZXQgR2lmdENhcmRzwq4gYXJlIHJlZ2lzdGVyZWQgdHJhZGVtYXJrcyBvZiBUYXJnZXQgQnJhbmRzLCBJbmMuIFRlcm1zIGFuZCBjb25kaXRpb25zIGFyZSBhcHBsaWVkIHRvIGdpZnQgY2FyZHMuIFRhcmdldCBpcyBub3QgYSBwYXJ0aWNpcGF0aW5nIHBhcnRuZXIgaW4gb3Igc3BvbnNvciBvZiB0aGlzIG9mZmVyLiJ9LHsiaWQiOjY5LCJuYW1lIjoiVGhlIEdhcCIsImltYWdlX3VybCI6Imh0dHBzOi8vdXBsb2FkZWRpbWFnZXN0ZXN0YmVkLmdpZnRiaXQuY29tLzcwL2dhcC1iODI0ZmEyMC04MzMwLTQ5NjEtYTIxNy0xOTA4NjY0MWUxYzMucG5nIn0seyJpZCI6MSwibmFtZSI6IjIlIEphenogQ29mZmVlIiwiaW1hZ2VfdXJsIjoiaHR0cHM6Ly91cGxvYWRlZGltYWdlc3Rlc3RiZWQuZ2lmdGJpdC5jb20vMi8ycGVyZ2lmdGRmYTIwMDVmNmFiYzQ5ODVhZGIxODllMmZhNDBjOGEyLTRmM2JlMzllLTQyMGEtNDgwMy04Y2U3LWJlNmZiNDZkOTk0Zi5wbmcifSx7ImlkIjoxMDEsIm5hbWUiOiJNb250YW5hJ3MgQ29va2hvdXNlIiwiaW1hZ2VfdXJsIjoiaHR0cHM6Ly91cGxvYWRlZGltYWdlc3Rlc3RiZWQuZ2lmdGJpdC5jb20vMTU1L21vbnRhbmFzLThiNWRmNmUzLWNhOWUtNDFiNi1hZTliLWUxZjc4MWUxYTFjNS5wbmcifSx7ImlkIjo5OSwibmFtZSI6IktlbHNleSdzIiwiaW1hZ2VfdXJsIjoiaHR0cHM6Ly91cGxvYWRlZGltYWdlc3Rlc3RiZWQuZ2lmdGJpdC5jb20vMTUwL0tlbHNleXNsb2dvLWFhMWIyMzM3LTUzZjItNDk4ZS1hYTI1LWE0OTY2MmZiN2JjNy5wbmcifSx7ImlkIjo5NiwibmFtZSI6IkhhcnZleSdzIiwiaW1hZ2VfdXJsIjoiaHR0cHM6Ly91cGxvYWRlZGltYWdlc3Rlc3RiZWQuZ2lmdGJpdC5jb20vMTUxL0hhcnZleXNMb2dvLTMzYjk4MTJjLWQ5MjMtNDU2MC04ODJkLWY1ZjhmM2JmZWIxMC5wbmcifSx7ImlkIjoxNDAsIm5hbWUiOiJUZXN0IE1lcmNoYW50IiwiaW1hZ2VfdXJsIjoiaHR0cHM6Ly91cGxvYWRlZGltYWdlc3Rlc3RiZWQuZ2lmdGJpdC5jb20vTWVyY2gvTWVyY2hhbnRJY29uLWUwNjBmNGQxLWMyMGUtNDc0Ni1iYzc1LTQ5NjgwMDY3MDAzMS5wbmcifSx7ImlkIjo5MCwibmFtZSI6IkNpbmVwbGV4IE9kZW4iLCJpbWFnZV91cmwiOiJodHRwczovL3VwbG9hZGVkaW1hZ2VzdGVzdGJlZC5naWZ0Yml0LmNvbS8xNTYvQ2luZXBsZXgzMDBieTMwMC0yZWE4MWY2Ni0zNTBkLTQ0YWEtYjM0NC0zYzRhNjIwZWRiODMucG5nIn0seyJpZCI6MTM1LCJuYW1lIjoiVmlzYSIsImltYWdlX3VybCI6Imh0dHBzOi8vdXBsb2FkZWRpbWFnZXN0ZXN0YmVkLmdpZnRiaXQuY29tLzMxMS9WaXJ0dWFsUmV3YXJkMWY3MzA1YTViY2NmNTQ4NmFhMTJiZGM2OTllMTBkMDU5LWNiN2M1ODg1LTZjYzctNDEzZi1hZjg1LTYwNDhhNmEzNjg0Yy5wbmcifSx7ImlkIjo4NCwibmFtZSI6IlN0YXJidWNrcyIsImltYWdlX3VybCI6Imh0dHBzOi8vdXBsb2FkZWRpbWFnZXN0ZXN0YmVkLmdpZnRiaXQuY29tLzEyMS9zdGFyYnVja3MtZjIyZGI1NjQtYWMzYS00YWUxLTljODgtOThlNzlmN2U1NzAyLnBuZyJ9LHsiaWQiOjEyMSwibmFtZSI6IlNvY2lsb2dpY2EgUmV0YWlsZXIxIiwiaW1hZ2VfdXJsIjoiaHR0cHM6Ly91cGxvYWRlZGltYWdlc3Rlc3RiZWQuZ2lmdGJpdC5jb20vMTkyL3lvdXJsb2dvaGVyZTI3LWEyNDhmMTE2LWZkMzUtNDg5NS04YjllLWVlYTUzNjk2ZTI4ZC5wbmciLCJkaXNjbGFpbWVyIjoiVGhpcyBpcyBhIGRpc2NsYWltZXIgZm9yIGEgdGVzdGJlZCBnaWZ0In0seyJpZCI6NzYsIm5hbWUiOiJTcGEgV2VlayIsImltYWdlX3VybCI6Imh0dHBzOi8vdXBsb2FkZWRpbWFnZXN0ZXN0YmVkLmdpZnRiaXQuY29tLzc3L3NwYXdlZWstOTBmZjQ4ZTQtNTYwMS00ZmRlLWIwYTUtYWIzNjlhNDkzODNhLnBuZyJ9LHsiaWQiOjUwLCJuYW1lIjoiUGFwYSBHaW5vJ3MgUGl6emVyaWEiLCJpbWFnZV91cmwiOiJodHRwczovL3VwbG9hZGVkaW1hZ2VzdGVzdGJlZC5naWZ0Yml0LmNvbS81MS9wYXBhZ2lub3MtYzIyY2M3M2QtYzE1Yy00NjMwLWI3OTctYTc0NWQzNTUzOWUzLnBuZyJ9LHsiaWQiOjEwMiwibmFtZSI6Ik5pa2UiLCJpbWFnZV91cmwiOiJodHRwczovL3VwbG9hZGVkaW1hZ2VzdGVzdGJlZC5naWZ0Yml0LmNvbS8xNTgvbmlrZS0yZmZmMTQwNC0xMWVjLTQxMTEtYjgwNi0xZmM1ODEzZjQ5OTcucG5nIiwiZGlzY2xhaW1lciI6IlRoZSBTd29vc2ggZGVzaWduIGlzIGEgcmVnaXN0ZXJlZCB0cmFkZW1hcmsgb2YgTklLRS4gQWxsIHJpZ2h0cyByZXNlcnZlZC4gTklLRSBpcyBub3QgYSBwYXJ0aWNpcGFudCBpbiBvciBzcG9uc29yIG9mIHRoaXMgcHJvbW90aW9uLiJ9LHsiaWQiOjEwMCwibmFtZSI6Ik1pbGVzdG9uZXMgR3JpbGwgYW5kIEJhciIsImltYWdlX3VybCI6Imh0dHBzOi8vdXBsb2FkZWRpbWFnZXN0ZXN0YmVkLmdpZnRiaXQuY29tLzE1NC9taWxlc3RvbmVzMS00OTk4NzZkYS03NjZmLTQyZGMtYTZmZi1iZDNmYjVhNzBkZjAuanBnIn0seyJpZCI6OTcsIm5hbWUiOiJIb21lIERlcG90IiwiaW1hZ2VfdXJsIjoiaHR0cHM6Ly91cGxvYWRlZGltYWdlc3Rlc3RiZWQuZ2lmdGJpdC5jb20vMTUyL2hvbWVkZXBvdC1hOTMwZjhiNy03NGIxLTQ3N2QtODk1Ni0xNjlhOGYxMzcxOTYucG5nIn0seyJpZCI6OTUsIm5hbWUiOiJHbG9iYWwgSG90ZWwgQ2FyZCBwb3dlcmVkIGJ5IE9yYml0eiIsImltYWdlX3VybCI6Imh0dHBzOi8vdXBsb2FkZWRpbWFnZXN0ZXN0YmVkLmdpZnRiaXQuY29tLzE0Ni9naGNwb3Nob3Jpem9udGFsLTIwNzJiOWY5LTQ0YjgtNDliMi1iNGQ0LWQ0MjE4OThjMmQ4ZS5wbmcifSx7ImlkIjoxMzcsIm5hbWUiOiJNYXN0ZXJDYXJkIiwiaW1hZ2VfdXJsIjoiaHR0cHM6Ly91cGxvYWRlZGltYWdlc3Rlc3RiZWQuZ2lmdGJpdC5jb20vMzI2L21hc3RlcmNhcmRsb2dvMjk3NjRjOTU2OTRhOWNkYWI0NzA2OTBhMDE2NWE3MTExMDViZS1lYzZiY2JmMC1jODBjLTQzZDctYWU0Ny1mYzgyYjY4ZGVkNzkuanBnIiwiZGlzY2xhaW1lciI6IkRpc2NsYWltZXIsIGlmIG5lZWRlZCwgZ29lcyBoZXJlIn0seyJpZCI6MTMyLCJuYW1lIjoiRWFzdCBTaWRlIE1hcmlvJ3MiLCJpbWFnZV91cmwiOiJodHRwczovL3VwbG9hZGVkaW1hZ2VzdGVzdGJlZC5naWZ0Yml0LmNvbS8yNDYvRWFzdFNpZGVNYXJpb3Nsb2dvMjAxMy1mZjc4MThjYS1mZDRlLTQ0MWItOWEyNS00NTVhNjdiMmYxYTQucG5nIn0seyJpZCI6MTI4LCJuYW1lIjoiTWVyY2hhbnQgRGVtbyIsImltYWdlX3VybCI6Imh0dHBzOi8vdXBsb2FkZWRpbWFnZXN0ZXN0YmVkLmdpZnRiaXQuY29tL0dGQlQxMjgvTWVyY2hhbnRJY29uMngtMWM2MzBmZGItYWJmZC00YjAwLTk0OGMtYzRiZGQzYmMwZDZkLnBuZyJ9LHsiaWQiOjExMiwibmFtZSI6IlRhcmdldCIsImltYWdlX3VybCI6Imh0dHBzOi8vdXBsb2FkZWRpbWFnZXN0ZXN0YmVkLmdpZnRiaXQuY29tLzE4NC90YXJnZXQtZGMyN2ViYzAtZWFmMS00NmRiLWIzMmYtNDY1Mjg3N2M1MDczLlBORyJ9LHsiaWQiOjEwNywibmFtZSI6IlN3aXNzIENoYWxldCIsImltYWdlX3VybCI6Imh0dHBzOi8vdXBsb2FkZWRpbWFnZXN0ZXN0YmVkLmdpZnRiaXQuY29tLzE1Ny9zd2lzcy02ZjU4ZWFhZi1hMzljLTQ3N2MtODZlYS0yYTFkZGNlYTMxYjEucG5nIn1dLCJpbmZvIjp7ImNvZGUiOiJJTkZPX01BUktFVFBMQUNFX1JFVFJJRVZFRF9WRU5ET1JTIiwibmFtZSI6Ik1hcmtldHBsYWNlIFZlbmRvcnMgUmV0cmlldmVkIiwibWVzc2FnZSI6IkEgbGlzdCBvZiBtYXJrZXRwbGFjZSB2ZW5kb3JzIGhhcyBiZWVuIHJldHJpZXZlZC4ifX0=
58
+ http_version:
59
+ recorded_at: Tue, 14 Feb 2017 19:41:59 GMT
60
+ recorded_with: VCR 3.0.3
@@ -0,0 +1,28 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'giftbit/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'giftbit'
7
+ spec.version = Giftbit::VERSION
8
+ spec.authors = ['Sean Linsley']
9
+ spec.email = ['sean@modernmsg.com']
10
+ spec.summary = 'A Ruby gem for the Giftbit API'
11
+ spec.homepage = 'https://www.github.com/modernmsg/giftbit'
12
+ spec.license = 'MIT'
13
+
14
+ spec.files = `git ls-files`.split($/)
15
+ spec.test_files = spec.files.grep(/spec\//)
16
+ spec.require_paths = ['lib']
17
+
18
+ spec.required_ruby_version = '>= 2'
19
+
20
+ spec.add_dependency 'rest-client'
21
+ spec.add_dependency 'activesupport'
22
+
23
+ spec.add_development_dependency 'rake'
24
+ spec.add_development_dependency 'rspec'
25
+ spec.add_development_dependency 'pry'
26
+ spec.add_development_dependency 'vcr'
27
+ spec.add_development_dependency 'webmock'
28
+ end
@@ -0,0 +1,78 @@
1
+ require 'giftbit/version'
2
+ require 'giftbit/base'
3
+
4
+ class Giftbit
5
+ extend Base
6
+ include Base
7
+
8
+ # Class-level methods only work if you have a single API account. This lets
9
+ # you instantiate the API for a given account, if you have multiple.
10
+ def initialize(auth:)
11
+ fail 'no auths set' unless auths = self.class.auths
12
+ self.auth = auths.fetch(auth)
13
+ end
14
+
15
+ # This lets you call the same API requests on every account you have.
16
+ # This is useful e.g. to check the status of every gift in every account.
17
+ def self.each_auth
18
+ fail 'no auths set' unless auths
19
+ auths.each do |name, _|
20
+ yield new auth: name
21
+ end
22
+ end
23
+
24
+ def ==(other)
25
+ other.is_a?(Giftbit) && auth == other.auth
26
+ end
27
+
28
+ module Methods
29
+ def account
30
+ get ''
31
+ end
32
+
33
+ def funds
34
+ get 'funds'
35
+ end
36
+
37
+ def marketplace(params = {})
38
+ get 'marketplace', params: params
39
+ end
40
+
41
+ def regions(params = {})
42
+ get 'marketplace/regions', params: params
43
+ end
44
+
45
+ def vendors(params = {})
46
+ get 'marketplace/vendors', params: params
47
+ end
48
+
49
+ def campaign(params = {})
50
+ get 'campaign', params: params
51
+ end
52
+
53
+ def gifts(params = {})
54
+ get 'gifts', params: params
55
+ end
56
+
57
+ def create_gift(body = {})
58
+ body[:expiry] ||= (Date.today + 365).to_s
59
+
60
+ post 'campaign', body: body
61
+ end
62
+
63
+ def delete_gift(gift_uuid)
64
+ delete "gifts/#{gift_uuid}"
65
+ end
66
+
67
+ def resend_gift(gift_uuid)
68
+ put "gifts/#{gift_uuid}", body: {resend: true}
69
+ end
70
+
71
+ def get_links(campaign_id)
72
+ get "links/#{campaign_id}"
73
+ end
74
+ end
75
+
76
+ extend Methods
77
+ include Methods
78
+ end
@@ -0,0 +1,99 @@
1
+ require 'active_support'
2
+ require 'json'
3
+ require 'rest-client'
4
+
5
+ class Giftbit
6
+ module Base
7
+ def self.extended(klass)
8
+ klass.send :cattr_accessor, :endpoint, :auth, :auths
9
+ klass.endpoint = 'https://testbedapp.giftbit.com/papi/v1/'
10
+ end
11
+
12
+ def self.included(klass)
13
+ klass.send :attr_accessor, :auth
14
+ end
15
+
16
+ def get_auth
17
+ fail "auth and auths can't both be set" if inherited_auth && auths?
18
+
19
+ if auth = instance? ? self.auth : inherited_auth
20
+ auth
21
+ elsif auths?
22
+ fail 'you must init a new API instance with the auth you want to use'
23
+ else
24
+ fail 'you must set an auth token at application boot'
25
+ end
26
+ end
27
+
28
+ def inherited_auth
29
+ instance? ? self.class.auth : auth
30
+ end
31
+
32
+ def inherited_endpoint
33
+ instance? ? self.class.endpoint : endpoint
34
+ end
35
+
36
+ def auths?
37
+ auths = instance? ? self.class.auths : self.auths
38
+ auths && auths.any?
39
+ end
40
+
41
+ def instance?
42
+ self.class == Giftbit
43
+ end
44
+
45
+ private
46
+
47
+ def default_resource_options
48
+ {
49
+ headers: {
50
+ "Authorization" => "Bearer #{get_auth}",
51
+ "Accept" => "application/json",
52
+ "Content-Type" => "json"
53
+ }
54
+ }
55
+ end
56
+
57
+ def resource(options = {})
58
+ RestClient::Resource.new inherited_endpoint, default_resource_options.deep_merge(options)
59
+ end
60
+
61
+ def response(method, resource, options = {})
62
+ if body = options.delete(:body)
63
+ json = resource.send(method, JSON.generate(body), options)
64
+ else
65
+ json = resource.send(method, options)
66
+ end
67
+
68
+ JSON.parse json
69
+ rescue RestClient::ExceptionWithResponse => e
70
+ case e.http_code
71
+ when 400..499
72
+ JSON.parse e.response
73
+ when 500..599
74
+ {
75
+ 'status' => e.http_code,
76
+ 'error' => { 'message' => e.response }
77
+ }
78
+ else
79
+ raise
80
+ end
81
+ end
82
+
83
+ def get(path, request_options = {}, resource_options = {})
84
+ response :get, resource(resource_options)[path], request_options
85
+ end
86
+
87
+ def delete(path, request_options = {}, resource_options = {})
88
+ response :delete, resource(resource_options)[path], request_options
89
+ end
90
+
91
+ def post(path, request_options = {}, resource_options = {})
92
+ response :post, resource(resource_options)[path], request_options
93
+ end
94
+
95
+ def put(path, request_options = {}, resource_options = {})
96
+ response :put, resource(resource_options)[path], request_options
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,3 @@
1
+ class Giftbit
2
+ VERSION = '1.0.0'
3
+ end
@@ -0,0 +1,284 @@
1
+ require 'giftbit'
2
+ require 'vcr'
3
+ require 'webmock'
4
+
5
+ VCR.configure do |config|
6
+ config.cassette_library_dir = 'fixtures/vcr_cassettes'
7
+ config.hook_into :webmock
8
+ config.allow_http_connections_when_no_cassette = true
9
+ end
10
+
11
+ def retry_request(cassette)
12
+ if cassette.recording?
13
+ VCR.eject_cassette
14
+
15
+ response = yield
16
+ attempts = 1
17
+
18
+ until response || attempts > 12 do
19
+ sleep 5
20
+ response = yield
21
+ attempts += 1
22
+ end
23
+
24
+ VCR.insert_cassette(cassette.name, record: :new_episodes)
25
+ end
26
+
27
+ yield
28
+ end
29
+
30
+ describe Giftbit do
31
+ let(:auth) { 'eyJ0eXAiOiJKV1QiLCJhbGciOiJTSEEyNTYifQ==.TFdWYU5VTVhzK3JFaVhHT2p5VDRHNFRsUk1ybnk2V2E4TDNDSW5meEdXdTVERUJNeHlDTEU1K216Qk1hb3Q4QlZaTVJvWndjR2ZoS01xc3gzdnZMUHdQckN1Z0kreG9rYVF3c1JjUjNkNlNLVmROQTlJb0hvMmpHdkx2REh3NXE=.cu7N3bPxGg8fPxFsIUcjyOISwn+29YpB0l7YDHwkMDg=' }
32
+ let :data do
33
+ {
34
+ id: "GiftbitGift#{Time.now.utc.to_i}",
35
+ message: 'Thank you for being an awesome person',
36
+ subject: 'Present from Community Rewards',
37
+ contacts: [firstname: 'Sean', lastname: 'Linsley', email: 'sean@modernmsg.com'],
38
+ marketplace_gifts: [id: 1, price_in_cents: 5000]
39
+ }
40
+ end
41
+
42
+ after do
43
+ Giftbit.auth = nil
44
+ Giftbit.auths = nil
45
+ end
46
+
47
+ context 'authentication' do
48
+ it 'errors without auth' do
49
+ expect{
50
+ Giftbit.account
51
+ }.to raise_error 'you must set an auth token at application boot'
52
+ end
53
+
54
+ it 'errors without auth, but auths set' do
55
+ Giftbit.auths = {default: auth}
56
+
57
+ expect{
58
+ Giftbit.account
59
+ }.to raise_error 'you must init a new API instance with the auth you want to use'
60
+ end
61
+
62
+ it 'errors for unregistered auth' do
63
+ Giftbit.auths = {default: auth}
64
+
65
+ expect{
66
+ Giftbit.new(auth: :foo).account
67
+ }.to raise_error KeyError, 'key not found: :foo'
68
+ end
69
+
70
+ it 'errors when both auth and auths are set' do
71
+ Giftbit.auth = auth
72
+ Giftbit.auths = {default: auth}
73
+
74
+ expect{
75
+ Giftbit.account
76
+ }.to raise_error "auth and auths can't both be set"
77
+
78
+ expect{
79
+ Giftbit.new(auth: :default).account
80
+ }.to raise_error "auth and auths can't both be set"
81
+ end
82
+ end
83
+
84
+ describe '.each_auth' do
85
+ it 'returns each auth' do
86
+ Giftbit.auths = {default: auth, custom: 'foo'}
87
+
88
+ times_called = 0
89
+
90
+ Giftbit.each_auth do |api|
91
+ times_called += 1
92
+
93
+ expect(api).to be_an_instance_of Giftbit
94
+ expect([auth, 'foo']).to include api.auth
95
+ end
96
+
97
+ expect(times_called).to eq 2
98
+ end
99
+ end
100
+
101
+ [:class, :instance].each do |variant|
102
+ describe "(#{variant})" do
103
+ before do |example|
104
+ if variant == :class
105
+ Giftbit.auth = example.metadata[:invalid_auth] ? 'notavalidtoken' : auth
106
+ else
107
+ Giftbit.auths = {default: auth}
108
+ Giftbit.auths.merge! invalid: 'notavalidtoken' if example.metadata[:invalid_auth]
109
+ end
110
+ end
111
+
112
+ let :api do |example|
113
+ if variant == :class
114
+ Giftbit
115
+ else
116
+ auth = example.metadata[:invalid_auth] ? :invalid : :default
117
+ Giftbit.new auth: auth
118
+ end
119
+ end
120
+
121
+ context 'requests' do
122
+ it 'parses JSON for a successful request' do
123
+ VCR.use_cassette('request-200') do
124
+ json = api.create_gift(data)
125
+
126
+ expect(json['status']).to eql 200
127
+ end
128
+ end
129
+
130
+ it 'parses JSON for a client error' do
131
+ VCR.use_cassette('request-400') do
132
+ json = api.create_gift
133
+
134
+ expect(json['status']).to eql 422
135
+ expect(json).to have_key 'error'
136
+ end
137
+ end
138
+
139
+ it 'creates JSON for a server error' do
140
+ VCR.use_cassette('request-500') do
141
+ json = api.create_gift
142
+
143
+ expect(json['status']).to eql 503
144
+ expect(json.dig('error', 'message')).to include '<html>'
145
+ end
146
+ end
147
+ end
148
+
149
+ describe '#account' do
150
+ it 'returns welcome message with valid credentials' do
151
+ VCR.use_cassette('account-valid') do
152
+ res = api.account
153
+
154
+ expect(res['info']['name']).to eql 'Credentials are valid'
155
+ end
156
+ end
157
+
158
+ it 'returns unauthorized message with invalid credentials', invalid_auth: true do
159
+ VCR.use_cassette('account-invalid') do
160
+ res = api.account
161
+
162
+ expect(res['text']).to eql 'Unauthorized'
163
+ expect(res['status']).to eql 401
164
+ end
165
+ end
166
+ end
167
+
168
+ describe '#funds' do
169
+ it 'returns funds info' do
170
+ VCR.use_cassette('funds') do
171
+ res = api.funds
172
+ expect(res['info']['name']).to eql 'Fund information retrieved'
173
+ expect(res['fundsbycurrency']['USD']['available_in_cents']). to be >= 0
174
+ end
175
+ end
176
+ end
177
+
178
+ describe '#marketplace' do
179
+ it 'lists all gifts' do
180
+ VCR.use_cassette('marketplace-all') do
181
+ res = api.marketplace
182
+
183
+ expect(res['info']['name']).to eql 'Marketplace Gifts Retrieved'
184
+ end
185
+ end
186
+
187
+ it 'lists all gifts by vendor' do
188
+ VCR.use_cassette('marketplace-by-vendor') do
189
+ res = api.marketplace vendor: 6
190
+
191
+ expect(res['total_count']).to be >= 0
192
+ end
193
+ end
194
+ end
195
+
196
+ describe '#regions' do
197
+ it 'lists all regions' do
198
+ VCR.use_cassette('regions-all') do
199
+ res = api.regions
200
+
201
+ expect(res['regions'].count).to eql 4
202
+ end
203
+ end
204
+ end
205
+
206
+ describe '#vendors' do
207
+ it 'list all vendors' do
208
+ VCR.use_cassette('vendors-all') do
209
+ res = api.vendors
210
+
211
+ expect(res['vendors'].count).to eql 27
212
+ end
213
+ end
214
+ end
215
+
216
+ describe '#campaign' do
217
+ it 'list all campaigns created' do
218
+ VCR.use_cassette('campaign-all') do
219
+ res = api.campaign
220
+
221
+ expect(res['campaigns'].count).to be >= 5
222
+ end
223
+ end
224
+
225
+ it 'can fetch campaign with ID provided' do
226
+ VCR.use_cassette('campaign-by-id') do
227
+ gift = api.create_gift(data)
228
+
229
+ res = api.campaign(id: gift['info']['id'])
230
+
231
+ expect(res['info']['id']).to eql gift['info']['id']
232
+ end
233
+ end
234
+ end
235
+
236
+ describe '#gifts' do
237
+ it 'can fetch the gifts for a given campaign' do
238
+ VCR.use_cassette('gifts') do
239
+ gifts = api.gifts
240
+
241
+ expect(gifts['gifts'].length).to be > 0
242
+ end
243
+ end
244
+ end
245
+
246
+ describe '#create_gift' do
247
+ it 'creates a gift' do
248
+ VCR.use_cassette('create_gift') do
249
+ gift = api.create_gift(data)
250
+
251
+ expect(gift['info']['name']).to eql 'Campaign Created'
252
+ end
253
+ end
254
+ end
255
+
256
+ describe '#resend_gift' do
257
+ it 'can re-send an email for a given campaign gift' do
258
+ VCR.use_cassette('resend_gift') do |cassette|
259
+ gift = api.create_gift(data)
260
+ gift = retry_request(cassette) do
261
+ api.gifts(campaign_uuid: gift['campaign']['uuid'])['gifts'].first
262
+ end
263
+ res = api.resend_gift(gift['uuid'])
264
+
265
+ expect(res['info']['code']).to eql 'INFO_GIFTS_RESENT'
266
+ end
267
+ end
268
+ end
269
+
270
+ describe '#get_links' do
271
+ it 'returns link status' do
272
+ VCR.use_cassette('get_links') do
273
+ data[:delivery_type] = 'SHORTLINK'
274
+ gift = api.create_gift(data)
275
+
276
+ res = api.get_links(gift['campaign']['id'])
277
+
278
+ expect(res['info']['code']).to eql 'INFO_LINKS_GENERATION_IN_PROGRESS'
279
+ end
280
+ end
281
+ end
282
+ end
283
+ end
284
+ end