vihaya-events 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: bc964189032da23b22704e70018dfc84d1e062626c4dd1ce773afaba4746e30d
4
+ data.tar.gz: 9408a9f45ee799454fb04b93d4c0103c26016b478d07d830e232b7f5061c3b8e
5
+ SHA512:
6
+ metadata.gz: cc1711f1be3cd370091be2183c39dcda4c43e20d40a29d1a44f35d38237a34b95c8620aa7a5bcf98acd8fad0a6d129063a162a878c38bb59ed2c412904b2df84
7
+ data.tar.gz: e0df7f05daadcc52963abd838db56440ac685ec0326e797b00a85f3f9f20ef92a447fa66335c5a242a988d95b4a299710e9a0a597a1413e95c1d7ceda4f0939b
data/CHANGELOG.md ADDED
@@ -0,0 +1,18 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## 0.1.0 — 2026-04-08
6
+
7
+ First public release on RubyGems.
8
+
9
+ ### Added
10
+ - `Vihaya::Client` with `events` and `payments` resource namespaces.
11
+ - `events.list`, `events.get(id)`, `events.register(id, data)` methods.
12
+ - `payments.verify(payment_id:, order_id:, signature:, amount: nil)` method.
13
+ - Plain-Ruby models for `Event`, `CustomField`, `SpecialPrice`, `Contact`,
14
+ `AgendaItem`, `Speaker`, `Sponsor`, `FAQItem`, `PromoCode`, and
15
+ `RegisterData` — feature parity with the JavaScript, Flutter, and Python
16
+ SDKs.
17
+ - `Vihaya::Error` exception class with `#status` and `#data` accessors.
18
+ - Zero runtime dependencies — built on `net/http` and `json` from stdlib.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vihaya Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,152 @@
1
+ # Vihaya Events — Ruby SDK
2
+
3
+ [![Gem Version](https://img.shields.io/gem/v/vihaya-events.svg)](https://rubygems.org/gems/vihaya-events)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
5
+
6
+ The official Ruby SDK for the [Vihaya Events](https://vihaya.app) platform.
7
+ Built on the Ruby standard library (`net/http` + `json`) with **zero runtime
8
+ dependencies**, and feature parity with the JavaScript, Flutter, and Python
9
+ SDKs.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ gem install vihaya-events
15
+ ```
16
+
17
+ Or add it to your Gemfile:
18
+
19
+ ```ruby
20
+ gem "vihaya-events"
21
+ ```
22
+
23
+ Requires Ruby 3.0+.
24
+
25
+ ## Quick start
26
+
27
+ ```ruby
28
+ require "vihaya"
29
+
30
+ vh = Vihaya::Client.new("vh_live_...") # get your key from the developer dashboard
31
+
32
+ vh.events.list.each do |event|
33
+ puts "#{event.title} — #{event.location}"
34
+ end
35
+ ```
36
+
37
+ ## Fetch a full event
38
+
39
+ `events.get` returns an `Event` with every piece of metadata the organizer
40
+ has configured — speakers, agenda, sponsors, FAQs, custom fields, pricing
41
+ tiers, and sub-events for mega events.
42
+
43
+ ```ruby
44
+ event = vh.events.get("evt_8x42j9")
45
+
46
+ puts event.title
47
+ puts "Mode: #{event.event_mode} Timezone: #{event.timezone}"
48
+
49
+ event.speaker_list.each do |speaker|
50
+ puts "- #{speaker.name} (#{speaker.role})"
51
+ end
52
+
53
+ event.agenda_list.each do |item|
54
+ puts "[#{item.time}] #{item.title}"
55
+ end
56
+
57
+ event.special_prices.each do |tier|
58
+ puts " #{tier.name}: ₹#{tier.amount}"
59
+ end
60
+ ```
61
+
62
+ ### Mega events
63
+
64
+ If `event.mega_event?` is true, it contains sub-events. Each sub-event has
65
+ its own tiers, custom fields, etc.
66
+
67
+ ```ruby
68
+ if event.mega_event?
69
+ event.sub_events.each do |sub|
70
+ price = sub.free? ? "Free" : "₹#{sub.price}"
71
+ puts "- #{sub.title} (#{price})"
72
+ end
73
+ end
74
+ ```
75
+
76
+ ## Register an attendee
77
+
78
+ ```ruby
79
+ registration = Vihaya::RegisterData.new(
80
+ name: "Anjali Mehta",
81
+ email: "anjali@example.com",
82
+ phone: "+919820012345",
83
+ custom_fields: { "T-Shirt Size" => "L", "College" => "Vihaya Institute" }
84
+ )
85
+
86
+ result = vh.events.register("evt_8x42j9", registration)
87
+
88
+ if result[:isPaid]
89
+ order_id = result[:orderId]
90
+ # Launch Razorpay checkout with this order_id, then verify server-side:
91
+ vh.payments.verify(
92
+ payment_id: "pay_xxx",
93
+ order_id: order_id,
94
+ signature: "sig_xxx"
95
+ )
96
+ else
97
+ puts "Registered! ID: #{result[:registrationId]}"
98
+ end
99
+ ```
100
+
101
+ You can also pass a plain `Hash` instead of `RegisterData` if you prefer — the
102
+ SDK will send it as-is, so use camelCase keys for that path.
103
+
104
+ ## Error handling
105
+
106
+ All API failures raise `Vihaya::Error` with the HTTP status and raw body:
107
+
108
+ ```ruby
109
+ begin
110
+ vh.events.get("evt_does_not_exist")
111
+ rescue Vihaya::Error => e
112
+ puts "#{e.message} (status=#{e.status})"
113
+ puts e.data.inspect
114
+ end
115
+ ```
116
+
117
+ ## API reference
118
+
119
+ ### `Vihaya::Client.new(api_key, base_url: ..., headers: {}, timeout: 30)`
120
+
121
+ The main client. `api_key` is required; everything else is keyword.
122
+
123
+ ### `vh.events`
124
+
125
+ | Method | Returns | Description |
126
+ | --- | --- | --- |
127
+ | `list` | `Array<Vihaya::Event>` | All events on the authenticated account. |
128
+ | `get(event_id)` | `Vihaya::Event` | Full metadata for one event. |
129
+ | `register(event_id, data)` | `Hash` | Submit a registration. `data` can be `RegisterData` or `Hash`. |
130
+
131
+ ### `vh.payments`
132
+
133
+ | Method | Returns | Description |
134
+ | --- | --- | --- |
135
+ | `verify(payment_id:, order_id:, signature:, amount: nil)` | `Hash` | Server-side Razorpay signature verification. |
136
+
137
+ > **Security:** never hard-code a live secret key in client-side code. Use
138
+ > environment variables and perform payment verification from a trusted
139
+ > backend environment only.
140
+
141
+ ## Development
142
+
143
+ ```bash
144
+ git clone https://github.com/Vishnu252005/vihaya-sdk-ruby.git
145
+ cd vihaya-sdk-ruby
146
+ ruby test/test_client.rb
147
+ gem build vihaya-events.gemspec
148
+ ```
149
+
150
+ ## License
151
+
152
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Quickstart example for the Vihaya Ruby SDK.
5
+ #
6
+ # Run with:
7
+ #
8
+ # VIHAYA_API_KEY=vh_live_... ruby examples/quickstart.rb
9
+
10
+ require "vihaya"
11
+
12
+ api_key = ENV.fetch("VIHAYA_API_KEY", nil)
13
+ if api_key.nil? || api_key.empty?
14
+ warn "Set VIHAYA_API_KEY in your environment first."
15
+ exit 1
16
+ end
17
+
18
+ vh = Vihaya::Client.new(api_key)
19
+
20
+ begin
21
+ puts "Fetching events..."
22
+ events = vh.events.list
23
+ puts "Found #{events.length} event(s)."
24
+
25
+ events.first(5).each do |event|
26
+ price = event.free? ? "Free" : "₹#{event.price}"
27
+ puts " - [#{event.id}] #{event.title} #{price}"
28
+ end
29
+
30
+ exit 0 if events.empty?
31
+
32
+ first = events.first
33
+ puts "\nFetching details for: #{first.id}"
34
+ detail = vh.events.get(first.id)
35
+ puts " title: #{detail.title}"
36
+ puts " mode: #{detail.event_mode}"
37
+ puts " timezone: #{detail.timezone}"
38
+ puts " speakers: #{detail.speaker_list.length}"
39
+ puts " agenda: #{detail.agenda_list.length} items"
40
+
41
+ puts "\nRegistering a test attendee for: #{first.id}"
42
+ registration = Vihaya::RegisterData.new(
43
+ name: "Quickstart User",
44
+ email: "quickstart@vihaya.app",
45
+ phone: "+919999999999",
46
+ custom_fields: { "College" => "Vihaya Institute" }
47
+ )
48
+ response = vh.events.register(first.id, registration)
49
+
50
+ if response[:isPaid]
51
+ puts " Payment required. Order ID: #{response[:orderId]}"
52
+ else
53
+ puts " Registered. Registration ID: #{response[:registrationId]}"
54
+ end
55
+ rescue Vihaya::Error => e
56
+ warn "API error: #{e.message} (status=#{e.status})"
57
+ exit 2
58
+ end
@@ -0,0 +1,208 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "net/http"
5
+ require "uri"
6
+
7
+ require_relative "error"
8
+ require_relative "models"
9
+ require_relative "version"
10
+
11
+ module Vihaya
12
+ # The main Vihaya API client.
13
+ #
14
+ # @example
15
+ # require "vihaya"
16
+ #
17
+ # vh = Vihaya::Client.new("vh_live_...")
18
+ # vh.events.list.each do |event|
19
+ # puts "#{event.title} - #{event.date}"
20
+ # end
21
+ class Client
22
+ DEFAULT_BASE_URL = "https://events.vihaya.app"
23
+ DEFAULT_TIMEOUT = 30
24
+
25
+ attr_reader :events, :payments
26
+
27
+ # @param api_key [String] Your Vihaya API key. Get one from the developer
28
+ # dashboard at https://events.vihaya.app/profile/developer.
29
+ # @param base_url [String] Override the API base URL. Defaults to
30
+ # "https://events.vihaya.app".
31
+ # @param headers [Hash] Extra headers to send with every request.
32
+ # @param timeout [Integer, Float] Per-request timeout in seconds (default 30).
33
+ def initialize(api_key, base_url: DEFAULT_BASE_URL, headers: {}, timeout: DEFAULT_TIMEOUT)
34
+ raise ArgumentError, "api_key is required" if api_key.nil? || api_key.to_s.empty?
35
+
36
+ @api_key = api_key
37
+ @base_url = base_url.to_s.sub(%r{/\z}, "")
38
+ @extra_headers = headers || {}
39
+ @timeout = timeout
40
+
41
+ @events = EventsAPI.new(self)
42
+ @payments = PaymentsAPI.new(self)
43
+ end
44
+
45
+ # Internal: perform a JSON request. Raises {Vihaya::Error} on any
46
+ # non-2xx response or transport error.
47
+ #
48
+ # @api private
49
+ def request(method, path, body: nil, query: nil)
50
+ uri = URI.parse(@base_url + path)
51
+ uri.query = URI.encode_www_form(query) if query && !query.empty?
52
+
53
+ req = build_request(method, uri, body)
54
+
55
+ response = perform(uri, req)
56
+ parse_response(response)
57
+ rescue Vihaya::Error
58
+ raise
59
+ rescue StandardError => e
60
+ raise Vihaya::Error, "Network error: #{e.message}"
61
+ end
62
+
63
+ private
64
+
65
+ def build_request(method, uri, body)
66
+ klass = {
67
+ "GET" => Net::HTTP::Get,
68
+ "POST" => Net::HTTP::Post,
69
+ "PUT" => Net::HTTP::Put,
70
+ "PATCH" => Net::HTTP::Patch,
71
+ "DELETE" => Net::HTTP::Delete
72
+ }.fetch(method.to_s.upcase) { raise ArgumentError, "Unsupported HTTP method: #{method}" }
73
+
74
+ req = klass.new(uri.request_uri)
75
+ default_headers.each { |k, v| req[k] = v }
76
+ @extra_headers.each { |k, v| req[k.to_s] = v.to_s }
77
+ req.body = JSON.generate(body) if body
78
+ req
79
+ end
80
+
81
+ def default_headers
82
+ {
83
+ "x-api-key" => @api_key,
84
+ "Content-Type" => "application/json",
85
+ "Accept" => "application/json",
86
+ "User-Agent" => "vihaya-ruby/#{Vihaya::VERSION}"
87
+ }
88
+ end
89
+
90
+ def perform(uri, req)
91
+ http = Net::HTTP.new(uri.host, uri.port)
92
+ http.use_ssl = (uri.scheme == "https")
93
+ http.open_timeout = @timeout
94
+ http.read_timeout = @timeout
95
+ http.request(req)
96
+ end
97
+
98
+ def parse_response(response)
99
+ body = response.body.to_s
100
+ data =
101
+ if body.empty?
102
+ nil
103
+ else
104
+ begin
105
+ JSON.parse(body, symbolize_names: true)
106
+ rescue JSON::ParserError
107
+ nil
108
+ end
109
+ end
110
+
111
+ code = response.code.to_i
112
+ return data if code.between?(200, 299)
113
+
114
+ message =
115
+ (data.is_a?(Hash) && (data[:error] || data[:message])) ||
116
+ "Vihaya API error (#{code})"
117
+ raise Vihaya::Error.new(message, status: code, data: data)
118
+ end
119
+
120
+ # ------------------------------------------------------------------
121
+ # Resource namespaces
122
+ # ------------------------------------------------------------------
123
+
124
+ # Event-related API methods. Access via {Vihaya::Client#events}.
125
+ class EventsAPI
126
+ def initialize(client)
127
+ @client = client
128
+ end
129
+
130
+ # List all events on the authenticated account.
131
+ # @return [Array<Vihaya::Event>]
132
+ def list
133
+ result = @client.request("GET", "/api/v1/events")
134
+ data = Client.unwrap(result, default: [])
135
+ Event.from_list(data)
136
+ end
137
+
138
+ # Fetch comprehensive metadata for a single event by ID.
139
+ # @param event_id [String]
140
+ # @return [Vihaya::Event]
141
+ def get(event_id)
142
+ result = @client.request("GET", "/api/v1/events/#{event_id}")
143
+ Event.new(Client.unwrap(result, default: result) || {})
144
+ end
145
+
146
+ # Register an attendee for an event.
147
+ #
148
+ # For paid events the response will include an `orderId` you should
149
+ # use to launch Razorpay checkout. For free events the response
150
+ # confirms the registration directly.
151
+ #
152
+ # @param event_id [String]
153
+ # @param data [Vihaya::RegisterData, Hash] payload
154
+ # @return [Hash] raw API response (symbol keys)
155
+ def register(event_id, data)
156
+ payload =
157
+ case data
158
+ when RegisterData then data.to_payload
159
+ when Hash then data
160
+ else
161
+ raise ArgumentError, "data must be a Vihaya::RegisterData or Hash"
162
+ end
163
+
164
+ result = @client.request("POST", "/api/v1/events/#{event_id}/register", body: payload)
165
+ result.is_a?(Hash) ? result : { data: result }
166
+ end
167
+ end
168
+
169
+ # Payment-related API methods. Access via {Vihaya::Client#payments}.
170
+ class PaymentsAPI
171
+ def initialize(client)
172
+ @client = client
173
+ end
174
+
175
+ # Server-side verification of a Razorpay payment signature.
176
+ #
177
+ # Call this from a trusted environment (backend, cron job, CLI) after
178
+ # the frontend Razorpay checkout succeeds.
179
+ #
180
+ # @param payment_id [String] Razorpay payment ID (e.g. "pay_O8K2...")
181
+ # @param order_id [String] Razorpay order ID from the registration response
182
+ # @param signature [String] The signature Razorpay returned to the frontend
183
+ # @param amount [Numeric, nil] Optional expected amount
184
+ # @return [Hash] raw API response (symbol keys)
185
+ def verify(payment_id:, order_id:, signature:, amount: nil)
186
+ payload = {
187
+ paymentId: payment_id,
188
+ orderId: order_id,
189
+ signature: signature
190
+ }
191
+ payload[:amount] = amount unless amount.nil?
192
+
193
+ result = @client.request("POST", "/api/v1/payments/verify", body: payload)
194
+ result.is_a?(Hash) ? result : { data: result }
195
+ end
196
+ end
197
+
198
+ # Unwraps the `{"success": true, "data": ...}` envelope used by the Vihaya
199
+ # API. Older endpoints returned the data directly, so we fall back.
200
+ #
201
+ # @api private
202
+ def self.unwrap(result, default:)
203
+ return result[:data] if result.is_a?(Hash) && result.key?(:data)
204
+
205
+ result.nil? ? default : result
206
+ end
207
+ end
208
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vihaya
4
+ # Raised when the Vihaya API returns an error response, or when the SDK
5
+ # cannot reach the API at all.
6
+ #
7
+ # @!attribute [r] message
8
+ # @return [String] human-readable error message from the server
9
+ # @!attribute [r] status
10
+ # @return [Integer, nil] HTTP status code, or nil for transport errors
11
+ # @!attribute [r] data
12
+ # @return [Hash, nil] raw parsed JSON response body, or nil
13
+ class Error < StandardError
14
+ attr_reader :status, :data
15
+
16
+ def initialize(message, status: nil, data: nil)
17
+ super(message)
18
+ @status = status
19
+ @data = data
20
+ end
21
+
22
+ def inspect
23
+ "#<Vihaya::Error message=#{message.inspect} status=#{status.inspect}>"
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,324 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vihaya
4
+ # Lightweight base model for Vihaya API responses.
5
+ #
6
+ # Instead of pulling in an ORM or Dry::Struct, each model is a plain Ruby
7
+ # object with explicit snake_case accessors. Unknown fields are preserved
8
+ # in {#raw} so forward-compatible API additions don't break clients.
9
+ #
10
+ # Every model also responds to Hash-like access (`event[:title]`,
11
+ # `event["title"]`) and has `to_h` for serialization back out.
12
+ class Model
13
+ attr_reader :raw
14
+
15
+ # Override in subclasses: map of snake_case Ruby name to camelCase API key.
16
+ FIELDS = {}.freeze
17
+
18
+ def initialize(data = {})
19
+ @raw = symbolize(data)
20
+ self.class::FIELDS.each do |ruby_name, api_key|
21
+ instance_variable_set(:"@#{ruby_name}", @raw[api_key.to_sym])
22
+ end
23
+ end
24
+
25
+ def [](key)
26
+ @raw[key.to_sym]
27
+ end
28
+
29
+ def to_h
30
+ @raw.dup
31
+ end
32
+
33
+ def ==(other)
34
+ other.is_a?(self.class) && other.raw == @raw
35
+ end
36
+
37
+ def self.from(data)
38
+ return nil if data.nil?
39
+
40
+ new(data)
41
+ end
42
+
43
+ def self.from_list(list)
44
+ return [] if list.nil?
45
+
46
+ Array(list).map { |item| new(item) }
47
+ end
48
+
49
+ private
50
+
51
+ def symbolize(obj)
52
+ case obj
53
+ when Hash
54
+ obj.each_with_object({}) { |(k, v), memo| memo[k.to_sym] = symbolize(v) }
55
+ when Array
56
+ obj.map { |item| symbolize(item) }
57
+ else
58
+ obj
59
+ end
60
+ end
61
+ end
62
+
63
+ # A custom input field on an event registration form.
64
+ class CustomField < Model
65
+ FIELDS = {
66
+ id: :id,
67
+ name: :name,
68
+ type: :type,
69
+ required: :required,
70
+ options: :options,
71
+ replaces_default: :replacesDefault
72
+ }.freeze
73
+
74
+ attr_reader :id, :name, :type, :required, :options, :replaces_default
75
+ end
76
+
77
+ # A pricing tier (VIP, Early Bird, Student, etc.).
78
+ class SpecialPrice < Model
79
+ FIELDS = {
80
+ name: :name,
81
+ amount: :amount,
82
+ early_bird_amount: :earlyBirdAmount,
83
+ requires_valid_id: :requiresValidId,
84
+ valid_ids: :validIds,
85
+ custom_fields: :customFields
86
+ }.freeze
87
+
88
+ attr_reader :name, :amount, :early_bird_amount, :requires_valid_id, :valid_ids
89
+
90
+ def custom_fields
91
+ CustomField.from_list(@raw[:customFields])
92
+ end
93
+ end
94
+
95
+ # A contact person for an event.
96
+ class Contact < Model
97
+ FIELDS = { id: :id, name: :name, phone: :phone, email: :email }.freeze
98
+ attr_reader :id, :name, :phone, :email
99
+ end
100
+
101
+ # A session / slot in the event schedule.
102
+ class AgendaItem < Model
103
+ FIELDS = {
104
+ id: :id,
105
+ title: :title,
106
+ time: :time,
107
+ description: :description,
108
+ speaker_id: :speakerId
109
+ }.freeze
110
+
111
+ attr_reader :id, :title, :time, :description, :speaker_id
112
+ end
113
+
114
+ # A speaker appearing at an event.
115
+ class Speaker < Model
116
+ FIELDS = {
117
+ id: :id,
118
+ name: :name,
119
+ role: :role,
120
+ bio: :bio,
121
+ image_url: :imageUrl,
122
+ linkedin_url: :linkedinUrl,
123
+ twitter_url: :twitterUrl,
124
+ website_url: :websiteUrl
125
+ }.freeze
126
+
127
+ attr_reader :id, :name, :role, :bio,
128
+ :image_url, :linkedin_url, :twitter_url, :website_url
129
+ end
130
+
131
+ # An event sponsor.
132
+ class Sponsor < Model
133
+ FIELDS = {
134
+ id: :id,
135
+ name: :name,
136
+ logo_url: :logoUrl,
137
+ category: :category,
138
+ website_url: :websiteUrl
139
+ }.freeze
140
+
141
+ attr_reader :id, :name, :logo_url, :category, :website_url
142
+ end
143
+
144
+ # A frequently-asked question entry for an event.
145
+ class FAQItem < Model
146
+ FIELDS = { id: :id, question: :question, answer: :answer }.freeze
147
+ attr_reader :id, :question, :answer
148
+ end
149
+
150
+ # A promo / discount code applied at registration time.
151
+ class PromoCode < Model
152
+ FIELDS = {
153
+ code: :code,
154
+ type: :type,
155
+ value: :value,
156
+ usage_limit: :usageLimit,
157
+ used_count: :usedCount,
158
+ is_active: :isActive
159
+ }.freeze
160
+
161
+ attr_reader :code, :type, :value, :usage_limit, :used_count, :is_active
162
+ end
163
+
164
+ # A Vihaya event with full metadata.
165
+ #
166
+ # Mirrors the `VihayaEvent` shape exposed by the JavaScript, Flutter, and
167
+ # Python SDKs. Every non-identifier field may be nil because the API
168
+ # only returns what the organizer has configured for that event.
169
+ class Event < Model
170
+ FIELDS = {
171
+ id: :id,
172
+ title: :title,
173
+ event_type: :eventType,
174
+ description: :description,
175
+ date: :date,
176
+ end_date: :endDate,
177
+ location: :location,
178
+ price: :price,
179
+ is_free: :isFree,
180
+ creator_id: :creatorId,
181
+ created_at: :createdAt,
182
+ has_special_prices: :hasSpecialPrices,
183
+ has_platform_fee: :hasPlatformFee,
184
+ platform_fee: :platformFee,
185
+ platform_fee_type: :platformFeeType,
186
+ pass_platform_fee_to_user: :passPlatformFeeToUser,
187
+ collect_dietary_preferences: :collectDietaryPreferences,
188
+ collect_accessibility_needs: :collectAccessibilityNeeds,
189
+ collect_emergency_contact: :collectEmergencyContact,
190
+ collect_affiliation: :collectAffiliation,
191
+ collect_research_interests: :collectResearchInterests,
192
+ collect_t_shirt_size: :collectTShirtSize,
193
+ enable_food_scanning: :enableFoodScanning,
194
+ food_scan_limit: :foodScanLimit,
195
+ is_team_event: :isTeamEvent,
196
+ min_team_size: :minTeamSize,
197
+ max_team_size: :maxTeamSize,
198
+ venue_name: :venueName,
199
+ full_address: :fullAddress,
200
+ city: :city,
201
+ country: :country,
202
+ google_map_link: :googleMapLink,
203
+ contact_phone: :contactPhone,
204
+ contact_email: :contactEmail,
205
+ contact_person_name: :contactPersonName,
206
+ event_mode: :eventMode,
207
+ timezone: :timezone,
208
+ currency: :currency,
209
+ registration_deadline: :registrationDeadline,
210
+ requires_approval: :requiresApproval,
211
+ waitlist_available: :waitlistAvailable
212
+ }.freeze
213
+
214
+ attr_reader :id, :title, :event_type, :description, :date, :end_date,
215
+ :location, :price, :is_free, :creator_id, :created_at,
216
+ :has_special_prices, :has_platform_fee, :platform_fee,
217
+ :platform_fee_type, :pass_platform_fee_to_user,
218
+ :collect_dietary_preferences, :collect_accessibility_needs,
219
+ :collect_emergency_contact, :collect_affiliation,
220
+ :collect_research_interests, :collect_t_shirt_size,
221
+ :enable_food_scanning, :food_scan_limit,
222
+ :is_team_event, :min_team_size, :max_team_size,
223
+ :venue_name, :full_address, :city, :country, :google_map_link,
224
+ :contact_phone, :contact_email, :contact_person_name,
225
+ :event_mode, :timezone, :currency,
226
+ :registration_deadline, :requires_approval, :waitlist_available
227
+
228
+ def free?
229
+ is_free == true
230
+ end
231
+
232
+ def mega_event?
233
+ event_type == "megaEvent"
234
+ end
235
+
236
+ def agenda_list
237
+ AgendaItem.from_list(@raw[:agendaList])
238
+ end
239
+
240
+ def speaker_list
241
+ Speaker.from_list(@raw[:speakerList])
242
+ end
243
+
244
+ def sponsor_list
245
+ Sponsor.from_list(@raw[:sponsorList])
246
+ end
247
+
248
+ def faq_list
249
+ FAQItem.from_list(@raw[:faqList])
250
+ end
251
+
252
+ def contact_list
253
+ Contact.from_list(@raw[:contactList])
254
+ end
255
+
256
+ def custom_fields
257
+ CustomField.from_list(@raw[:customFields])
258
+ end
259
+
260
+ def special_prices
261
+ SpecialPrice.from_list(@raw[:specialPrices])
262
+ end
263
+
264
+ def promo_codes
265
+ PromoCode.from_list(@raw[:promoCodes])
266
+ end
267
+
268
+ def sub_events
269
+ Event.from_list(@raw[:subEvents])
270
+ end
271
+ end
272
+
273
+ # Payload for {Vihaya::Client#events}.register.
274
+ #
275
+ # Only `name`, `email`, and `phone` are required. Everything else is
276
+ # optional and mirrors the JS/Flutter/Python SDK shapes.
277
+ class RegisterData
278
+ # Map of Ruby kwarg name -> wire (camelCase) key.
279
+ FIELDS = {
280
+ name: :name,
281
+ email: :email,
282
+ phone: :phone,
283
+ payment_id: :paymentId,
284
+ order_id: :orderId,
285
+ registration_id: :registrationId,
286
+ special_price: :specialPrice,
287
+ promo_code: :promoCode,
288
+ is_early_bird_applied: :isEarlyBirdApplied,
289
+ team_name: :teamName,
290
+ team_members: :teamMembers,
291
+ accommodation: :accommodation,
292
+ dietary_preference: :dietaryPreference,
293
+ preferences: :preferences,
294
+ custom_fields: :customFields,
295
+ user_id: :userId,
296
+ source: :source
297
+ }.freeze
298
+
299
+ attr_accessor(*FIELDS.keys)
300
+
301
+ def initialize(name:, email:, phone:, **extras)
302
+ @name = name
303
+ @email = email
304
+ @phone = phone
305
+ extras.each do |key, value|
306
+ unless FIELDS.key?(key)
307
+ raise ArgumentError, "Unknown RegisterData field: #{key.inspect}"
308
+ end
309
+
310
+ public_send("#{key}=", value)
311
+ end
312
+ end
313
+
314
+ # Serializes to the wire format (camelCase keys, nils dropped).
315
+ def to_payload
316
+ FIELDS.each_with_object({}) do |(ruby_name, wire_key), memo|
317
+ value = public_send(ruby_name)
318
+ memo[wire_key] = value unless value.nil?
319
+ end
320
+ end
321
+
322
+ alias to_h to_payload
323
+ end
324
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vihaya
4
+ VERSION = "0.1.0"
5
+ end
data/lib/vihaya.rb ADDED
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Official Ruby SDK for the Vihaya Events platform.
4
+ #
5
+ # Quick start:
6
+ #
7
+ # require "vihaya"
8
+ #
9
+ # vh = Vihaya::Client.new("vh_live_...")
10
+ # vh.events.list.each do |event|
11
+ # puts "#{event.title} - #{event.date}"
12
+ # end
13
+ #
14
+ # See https://events.vihaya.app/profile/developer/docs for the full API
15
+ # reference.
16
+ module Vihaya
17
+ end
18
+
19
+ require_relative "vihaya/version"
20
+ require_relative "vihaya/error"
21
+ require_relative "vihaya/models"
22
+ require_relative "vihaya/client"
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/vihaya/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "vihaya-events"
7
+ spec.version = Vihaya::VERSION
8
+ spec.authors = ["Vihaya Team"]
9
+ spec.email = ["vihaya.app@gmail.com"]
10
+
11
+ spec.summary = "Official Ruby SDK for the Vihaya Events platform."
12
+ spec.description = "Fetch events, register attendees, and verify Razorpay " \
13
+ "payments on the Vihaya Events platform with a fully-typed " \
14
+ "Ruby client. Feature parity with the JavaScript, Flutter, " \
15
+ "and Python SDKs."
16
+ spec.homepage = "https://github.com/Vishnu252005/vihaya-sdk-ruby"
17
+ spec.license = "MIT"
18
+ spec.required_ruby_version = ">= 3.0.0"
19
+
20
+ spec.metadata["homepage_uri"] = spec.homepage
21
+ spec.metadata["source_code_uri"] = "https://github.com/Vishnu252005/vihaya-sdk-ruby"
22
+ spec.metadata["changelog_uri"] = "https://github.com/Vishnu252005/vihaya-sdk-ruby/blob/main/CHANGELOG.md"
23
+ spec.metadata["documentation_uri"] = "https://events.vihaya.app/profile/developer/docs"
24
+ spec.metadata["bug_tracker_uri"] = "https://github.com/Vishnu252005/vihaya-sdk-ruby/issues"
25
+ spec.metadata["rubygems_mfa_required"] = "true"
26
+
27
+ spec.files = Dir[
28
+ "lib/**/*.rb",
29
+ "examples/**/*.rb",
30
+ "README.md",
31
+ "CHANGELOG.md",
32
+ "LICENSE",
33
+ "vihaya-events.gemspec"
34
+ ]
35
+ spec.require_paths = ["lib"]
36
+
37
+ # Zero runtime dependencies — built on Ruby stdlib (net/http + json).
38
+ end
metadata ADDED
@@ -0,0 +1,58 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vihaya-events
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Vihaya Team
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: Fetch events, register attendees, and verify Razorpay payments on the
13
+ Vihaya Events platform with a fully-typed Ruby client. Feature parity with the JavaScript,
14
+ Flutter, and Python SDKs.
15
+ email:
16
+ - vihaya.app@gmail.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - CHANGELOG.md
22
+ - LICENSE
23
+ - README.md
24
+ - examples/quickstart.rb
25
+ - lib/vihaya.rb
26
+ - lib/vihaya/client.rb
27
+ - lib/vihaya/error.rb
28
+ - lib/vihaya/models.rb
29
+ - lib/vihaya/version.rb
30
+ - vihaya-events.gemspec
31
+ homepage: https://github.com/Vishnu252005/vihaya-sdk-ruby
32
+ licenses:
33
+ - MIT
34
+ metadata:
35
+ homepage_uri: https://github.com/Vishnu252005/vihaya-sdk-ruby
36
+ source_code_uri: https://github.com/Vishnu252005/vihaya-sdk-ruby
37
+ changelog_uri: https://github.com/Vishnu252005/vihaya-sdk-ruby/blob/main/CHANGELOG.md
38
+ documentation_uri: https://events.vihaya.app/profile/developer/docs
39
+ bug_tracker_uri: https://github.com/Vishnu252005/vihaya-sdk-ruby/issues
40
+ rubygems_mfa_required: 'true'
41
+ rdoc_options: []
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: 3.0.0
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ requirements: []
55
+ rubygems_version: 4.0.3
56
+ specification_version: 4
57
+ summary: Official Ruby SDK for the Vihaya Events platform.
58
+ test_files: []