tito_ruby 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.
Files changed (36) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +12 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +119 -0
  5. data/lib/tito/admin/client.rb +98 -0
  6. data/lib/tito/admin/collection_proxy.rb +119 -0
  7. data/lib/tito/admin/query_builder.rb +110 -0
  8. data/lib/tito/admin/resources/activity.rb +32 -0
  9. data/lib/tito/admin/resources/answer.rb +23 -0
  10. data/lib/tito/admin/resources/checkin_list.rb +34 -0
  11. data/lib/tito/admin/resources/discount_code.rb +36 -0
  12. data/lib/tito/admin/resources/event.rb +62 -0
  13. data/lib/tito/admin/resources/interested_user.rb +19 -0
  14. data/lib/tito/admin/resources/opt_in.rb +23 -0
  15. data/lib/tito/admin/resources/question.rb +30 -0
  16. data/lib/tito/admin/resources/refund.rb +20 -0
  17. data/lib/tito/admin/resources/registration.rb +49 -0
  18. data/lib/tito/admin/resources/release.rb +67 -0
  19. data/lib/tito/admin/resources/release_invitation.rb +32 -0
  20. data/lib/tito/admin/resources/rsvp_list.rb +26 -0
  21. data/lib/tito/admin/resources/ticket.rb +59 -0
  22. data/lib/tito/admin/resources/venue.rb +19 -0
  23. data/lib/tito/admin/resources/waitlisted_person.rb +35 -0
  24. data/lib/tito/admin/resources/webhook_endpoint.rb +20 -0
  25. data/lib/tito/admin/scope.rb +71 -0
  26. data/lib/tito/configuration.rb +9 -0
  27. data/lib/tito/connection.rb +42 -0
  28. data/lib/tito/errors.rb +40 -0
  29. data/lib/tito/resource.rb +172 -0
  30. data/lib/tito/types/integer_array.rb +15 -0
  31. data/lib/tito/types/json.rb +16 -0
  32. data/lib/tito/types/string_array.rb +15 -0
  33. data/lib/tito/version.rb +3 -0
  34. data/lib/tito.rb +63 -0
  35. data/lib/tito_ruby.rb +1 -0
  36. metadata +180 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 12e525061a6eb7a57d6d38ded7e37484ad4bf99cff3bc6dbb3b255667485aa98
4
+ data.tar.gz: 52be4e37d656838e821b668ee49344e6e1e9839b0106c89d294eb39dd4c7985c
5
+ SHA512:
6
+ metadata.gz: bd789d6806949407ec212d36ddf8950a9d53ec9d7ffc5ae995759d0bc905aac16df6ce2a55c0d535c469a552f903527c07a3634a50c74cdc6844c48089d78d8c
7
+ data.tar.gz: 304f031d911a74b35e411c1cea57f6abc9496697945f0026cae8ed741f013c8e807bad7c9546f4a8332cd0a715201cf281d85122108553a42f9b77a222598590
data/CHANGELOG.md ADDED
@@ -0,0 +1,12 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 (Unreleased)
4
+
5
+ **WARNING:** This is pre-release, mostly-Claude-code-generated, mostly-untested software. It mostly doesn't work at all. Only the Tickets resource is known even to successfully load data. Use at your own risk.
6
+
7
+ - Initial release
8
+ - Admin API client with token-based authentication
9
+ - Support for 18 resource types: Events, Releases, Tickets, Registrations, Activities, Questions, Answers, Discount Codes, Checkin Lists, Opt-Ins, Interested Users, RSVP Lists, Release Invitations, Waitlisted People, Webhook Endpoints, Refunds, Venues
10
+ - Chainable query builder with search, filtering, ordering, pagination, and field expansion
11
+ - ActiveModel-backed resources with dirty tracking
12
+ - Lazy-loaded, paginated collections
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026
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
13
+ all 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
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,119 @@
1
+ # Tito Ruby
2
+
3
+ A Ruby client for the [Tito](https://ti.to) Admin API v3.
4
+
5
+ **WARNING:** This is pre-release, mostly-Claude-code-generated, mostly-untested software. It mostly doesn't work at all. Only the Tickets resource is known even to successfully load data. Use at your own risk.
6
+
7
+ ## Installation
8
+
9
+ Add to your Gemfile:
10
+
11
+ ```ruby
12
+ gem "tito_ruby"
13
+ ```
14
+
15
+ Or install directly:
16
+
17
+ ```
18
+ gem install tito_ruby
19
+ ```
20
+
21
+ ## Configuration
22
+
23
+ ```ruby
24
+ Tito.configure do |config|
25
+ config.token = "your_api_token"
26
+ config.account = "your_account_slug"
27
+ end
28
+ ```
29
+
30
+ Or pass credentials directly to the client:
31
+
32
+ ```ruby
33
+ client = Tito::Admin::Client.new(token: "your_api_token", account: "your_account_slug")
34
+ ```
35
+
36
+ ## Usage
37
+
38
+ ### Events
39
+
40
+ ```ruby
41
+ client = Tito::Admin::Client.new
42
+
43
+ # List events
44
+ client.events.each { |event| puts event.title }
45
+
46
+ # Find a specific event
47
+ event = client.events.find("my-event-slug")
48
+
49
+ # Past and archived events
50
+ client.past_events.each { |e| puts e.title }
51
+ client.archived_events.each { |e| puts e.title }
52
+ ```
53
+
54
+ ### Tickets
55
+
56
+ ```ruby
57
+ client = Tito::Admin::Client.new(event: "my-event")
58
+
59
+ # List tickets
60
+ client.tickets.each { |ticket| puts ticket.reference }
61
+
62
+ # Search and filter
63
+ client.tickets.search("john").each { |t| puts t.reference }
64
+
65
+ # Pagination
66
+ client.tickets.page(2).per(50).each { |t| puts t.reference }
67
+ ```
68
+
69
+ ### Registrations
70
+
71
+ ```ruby
72
+ client.registrations.each { |reg| puts reg.name }
73
+ ```
74
+
75
+ ### Releases
76
+
77
+ ```ruby
78
+ client.releases.each { |release| puts release.title }
79
+ ```
80
+
81
+ ### Discount Codes
82
+
83
+ ```ruby
84
+ client.discount_codes.each { |code| puts code.code }
85
+ ```
86
+
87
+ ### Query Builder
88
+
89
+ All collections support a chainable query interface:
90
+
91
+ ```ruby
92
+ client.tickets
93
+ .where(state: "complete")
94
+ .order("created_at_desc")
95
+ .expand("registration", "release")
96
+ .page(1)
97
+ .per(25)
98
+ .each { |t| puts t.reference }
99
+ ```
100
+
101
+ ### Available Resources
102
+
103
+ - Events, Releases, Tickets, Registrations
104
+ - Activities, Questions, Answers
105
+ - Discount Codes, Checkin Lists
106
+ - Opt-Ins, Interested Users, RSVP Lists
107
+ - Release Invitations, Waitlisted People
108
+ - Webhook Endpoints, Refunds, Venues
109
+
110
+ ## Development
111
+
112
+ ```
113
+ bundle install
114
+ bundle exec rake test
115
+ ```
116
+
117
+ ## License
118
+
119
+ MIT License. See [LICENSE.txt](LICENSE.txt).
@@ -0,0 +1,98 @@
1
+ module Tito
2
+ module Admin
3
+ class Client
4
+ attr_reader :token, :account, :event, :connection
5
+
6
+ def initialize(token: nil, account: nil, event: nil)
7
+ @token = token || Tito.configuration.token
8
+ @account = account || Tito.configuration.account
9
+ @event = event
10
+
11
+ raise Tito::Errors::ConfigurationError, "token is required" unless @token
12
+ raise Tito::Errors::ConfigurationError, "account is required" unless @account
13
+
14
+ @connection = Tito::Connection.new(token: @token)
15
+ end
16
+
17
+ # -- Account-scoped resources --
18
+
19
+ def events
20
+ collection_for(Resources::Event)
21
+ end
22
+
23
+ def past_events
24
+ collection_for(Resources::Event, path_suffix: "/past")
25
+ end
26
+
27
+ def archived_events
28
+ collection_for(Resources::Event, path_suffix: "/archived")
29
+ end
30
+
31
+ def webhook_endpoints
32
+ collection_for(Resources::WebhookEndpoint)
33
+ end
34
+
35
+ # -- Event-scoped resources --
36
+
37
+ def tickets(event: self.event)
38
+ collection_for(Resources::Ticket, event: event)
39
+ end
40
+
41
+ def releases(event: self.event)
42
+ collection_for(Resources::Release, event: event)
43
+ end
44
+
45
+ def registrations(event: self.event)
46
+ collection_for(Resources::Registration, event: event)
47
+ end
48
+
49
+ def activities(event: self.event)
50
+ collection_for(Resources::Activity, event: event)
51
+ end
52
+
53
+ def questions(event: self.event)
54
+ collection_for(Resources::Question, event: event)
55
+ end
56
+
57
+ def discount_codes(event: self.event)
58
+ collection_for(Resources::DiscountCode, event: event)
59
+ end
60
+
61
+ def checkin_lists(event: self.event)
62
+ collection_for(Resources::CheckinList, event: event)
63
+ end
64
+
65
+ def opt_ins(event: self.event)
66
+ collection_for(Resources::OptIn, event: event)
67
+ end
68
+
69
+ def interested_users(event: self.event)
70
+ collection_for(Resources::InterestedUser, event: event)
71
+ end
72
+
73
+ def rsvp_lists(event: self.event)
74
+ collection_for(Resources::RsvpList, event: event)
75
+ end
76
+
77
+ def waitlisted_people(event: self.event)
78
+ collection_for(Resources::WaitlistedPerson, event: event)
79
+ end
80
+
81
+ def venues(event: self.event)
82
+ collection_for(Resources::Venue, event: event)
83
+ end
84
+
85
+ private
86
+
87
+ def collection_for(resource_class, event: nil, path_suffix: nil)
88
+ scope = Scope.new(
89
+ client: self,
90
+ account: @account,
91
+ event: event,
92
+ resource_class: resource_class
93
+ )
94
+ CollectionProxy.new(scope: scope, path_suffix: path_suffix)
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,119 @@
1
+ module Tito
2
+ module Admin
3
+ class CollectionProxy
4
+ include Enumerable
5
+
6
+ def initialize(scope:, path_suffix: nil)
7
+ @scope = scope
8
+ @path_suffix = path_suffix
9
+ @query = QueryBuilder.new
10
+ @loaded_pages = {}
11
+ @meta = nil
12
+ end
13
+
14
+ # -- Chainable query methods (return new proxy) --
15
+
16
+ def where(**conditions)
17
+ dup_with { |q| q.add_where(conditions) }
18
+ end
19
+
20
+ def order(**fields)
21
+ dup_with { |q| q.add_order(fields) }
22
+ end
23
+
24
+ def search(term)
25
+ dup_with { |q| q.add_search(term) }
26
+ end
27
+
28
+ def expand(*fields)
29
+ dup_with { |q| q.add_expand(fields) }
30
+ end
31
+
32
+ def page(number)
33
+ dup_with { |q| q.set_page(number) }
34
+ end
35
+
36
+ def per(size)
37
+ dup_with { |q| q.set_per_page(size) }
38
+ end
39
+
40
+ # -- Reading --
41
+
42
+ def find(id_or_slug)
43
+ params = @query.expand_params
44
+ data = @scope.request(:get, @scope.member_path(id_or_slug), params: params)
45
+ instantiate(data[@scope.resource_class.resource_name] || data)
46
+ end
47
+
48
+ def each(&block)
49
+ return enum_for(:each) unless block_given?
50
+
51
+ page_number = @query.page_number || 1
52
+ loop do
53
+ page_data = fetch_page(page_number)
54
+ records = page_data[@scope.resource_class.collection_name] || []
55
+ records.each { |attrs| block.call(instantiate(attrs)) }
56
+
57
+ meta = page_data["meta"] || {}
58
+ break if meta["next_page"].nil?
59
+ page_number = meta["next_page"]
60
+ end
61
+ end
62
+
63
+ def size
64
+ ensure_first_page_loaded
65
+ @meta&.fetch("total_count", 0) || 0
66
+ end
67
+ alias_method :count, :size
68
+ alias_method :length, :size
69
+
70
+ def total_pages
71
+ ensure_first_page_loaded
72
+ @meta&.fetch("total_pages", 0) || 0
73
+ end
74
+
75
+ def empty?
76
+ size == 0
77
+ end
78
+
79
+ # -- Mutation helpers --
80
+
81
+ def build(**attrs)
82
+ @scope.resource_class.new(_scope: @scope, **attrs)
83
+ end
84
+
85
+ def create(**attrs)
86
+ build(**attrs).tap(&:save)
87
+ end
88
+
89
+ private
90
+
91
+ def dup_with
92
+ dup.tap do |copy|
93
+ new_query = @query.dup
94
+ yield new_query
95
+ copy.instance_variable_set(:@query, new_query)
96
+ copy.instance_variable_set(:@loaded_pages, {})
97
+ copy.instance_variable_set(:@meta, nil)
98
+ end
99
+ end
100
+
101
+ def fetch_page(number)
102
+ @loaded_pages[number] ||= begin
103
+ params = @query.to_params.merge("page[number]" => number)
104
+ data = @scope.request(:get, @scope.collection_path(suffix: @path_suffix), params: params)
105
+ @meta = data["meta"] if data.is_a?(Hash)
106
+ data
107
+ end
108
+ end
109
+
110
+ def ensure_first_page_loaded
111
+ fetch_page(@query.page_number || 1) unless @meta
112
+ end
113
+
114
+ def instantiate(attrs)
115
+ @scope.resource_class.new(_scope: @scope, **attrs.transform_keys(&:to_sym))
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,110 @@
1
+ module Tito
2
+ module Admin
3
+ class QueryBuilder
4
+ attr_reader :page_number
5
+
6
+ def initialize
7
+ @wheres = {}
8
+ @orders = {}
9
+ @search_term = nil
10
+ @expands = []
11
+ @page_number = nil
12
+ @per_page = nil
13
+ end
14
+
15
+ def add_where(conditions)
16
+ conditions.each { |key, value| @wheres[key] = value }
17
+ self
18
+ end
19
+
20
+ def add_order(fields)
21
+ @orders.merge!(fields)
22
+ self
23
+ end
24
+
25
+ def add_search(term)
26
+ @search_term = term
27
+ self
28
+ end
29
+
30
+ def add_expand(fields)
31
+ @expands.concat(fields.flatten)
32
+ self
33
+ end
34
+
35
+ def set_page(number)
36
+ @page_number = number
37
+ self
38
+ end
39
+
40
+ def set_per_page(size)
41
+ @per_page = size
42
+ self
43
+ end
44
+
45
+ def expand_params
46
+ @expands.any? ? { "expand" => @expands.join(",") } : {}
47
+ end
48
+
49
+ def to_params
50
+ params = {}
51
+ params["page[size]"] = @per_page if @per_page
52
+ params["q"] = @search_term if @search_term
53
+ params.merge!(expand_params)
54
+ params.merge!(where_params)
55
+ params.merge!(order_params)
56
+ params
57
+ end
58
+
59
+ def dup
60
+ super.tap do |copy|
61
+ copy.instance_variable_set(:@wheres, @wheres.dup)
62
+ copy.instance_variable_set(:@orders, @orders.dup)
63
+ copy.instance_variable_set(:@expands, @expands.dup)
64
+ end
65
+ end
66
+
67
+ private
68
+
69
+ def where_params
70
+ params = {}
71
+ @wheres.each do |key, value|
72
+ case value
73
+ when Array
74
+ plural_key = key.to_s
75
+ plural_key = plural_key.end_with?("s") ? plural_key : "#{plural_key}s"
76
+ params["search[#{plural_key}][]"] = value.map(&:to_s)
77
+ when Range
78
+ if value.begin
79
+ params["search[#{key}][gte]"] = format_value(value.begin)
80
+ end
81
+ if value.end
82
+ op = value.exclude_end? ? "lt" : "lte"
83
+ params["search[#{key}][#{op}]"] = format_value(value.end)
84
+ end
85
+ else
86
+ params["search[#{key}]"] = format_value(value)
87
+ end
88
+ end
89
+ params
90
+ end
91
+
92
+ def order_params
93
+ return {} if @orders.empty?
94
+ parts = @orders.map { |field, dir| dir == :desc ? "-#{field}" : field.to_s }
95
+ { "sort" => parts.join(",") }
96
+ end
97
+
98
+ def format_value(val)
99
+ case val
100
+ when Time, DateTime
101
+ val.utc.iso8601.sub(/Z$/, " UTC")
102
+ when Date
103
+ val.to_s
104
+ else
105
+ val.to_s
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,32 @@
1
+ module Tito
2
+ module Admin
3
+ module Resources
4
+ class Activity < Tito::Resource
5
+ event_scoped!
6
+ path_template "%{account}/%{event}/activities"
7
+ resource_name "activity"
8
+ collection_name "activities"
9
+ supports :list, :show, :create, :update, :delete
10
+
11
+ attribute :id, :integer
12
+ attribute :name, :string
13
+ attribute :description, :string
14
+ attribute :date, :string
15
+ attribute :start_time, :string
16
+ attribute :end_time, :string
17
+ attribute :start_at, :datetime
18
+ attribute :end_at, :datetime
19
+ attribute :capacity, :integer
20
+ attribute :allocation_count, :integer
21
+ attribute :sold_out, :boolean
22
+ attribute :show_to_attendee, :boolean
23
+ attribute :created_at, :datetime
24
+ attribute :updated_at, :datetime
25
+
26
+ expandable :questions, :releases, :upgrades, :venue
27
+
28
+ action :duplicate, method: :post, path: "duplication"
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,23 @@
1
+ module Tito
2
+ module Admin
3
+ module Resources
4
+ class Answer < Tito::Resource
5
+ event_scoped!
6
+ path_template "%{account}/%{event}/questions/%{parent_id}/answers"
7
+ resource_name "answer"
8
+ collection_name "answers"
9
+ supports :list, :show
10
+
11
+ attribute :id, :integer
12
+ attribute :question_id, :integer
13
+ attribute :ticket_id, :integer
14
+ attribute :primary_response, :string
15
+ attribute :alternate_response, :string
16
+ attribute :response, :string
17
+ attribute :download_url, :string
18
+
19
+ expandable :question, :ticket
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,34 @@
1
+ module Tito
2
+ module Admin
3
+ module Resources
4
+ class CheckinList < Tito::Resource
5
+ event_scoped!
6
+ path_template "%{account}/%{event}/checkin_lists"
7
+ resource_name "checkin_list"
8
+ collection_name "checkin_lists"
9
+ supports :list, :show, :create, :update, :delete
10
+
11
+ attribute :id, :integer
12
+ attribute :slug, :string
13
+ attribute :title, :string
14
+ attribute :web_checkin_url, :string
15
+ attribute :qr_code_url, :string
16
+ attribute :expires_at, :datetime
17
+ attribute :expired, :boolean
18
+ attribute :open, :boolean
19
+ attribute :state, :string
20
+ attribute :show_email, :boolean
21
+ attribute :show_company_name, :boolean
22
+ attribute :show_phone_number, :boolean
23
+ attribute :hide_unpaid, :boolean
24
+ attribute :checked_in_count, :integer
25
+ attribute :checked_in_percent, :decimal
26
+ attribute :tickets_count, :integer
27
+ attribute :created_at, :datetime
28
+ attribute :updated_at, :datetime
29
+
30
+ expandable :activities, :questions, :releases
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,36 @@
1
+ module Tito
2
+ module Admin
3
+ module Resources
4
+ class DiscountCode < Tito::Resource
5
+ event_scoped!
6
+ path_template "%{account}/%{event}/discount_codes"
7
+ resource_name "discount_code"
8
+ collection_name "discount_codes"
9
+ supports :list, :show, :create, :update, :delete
10
+
11
+ attribute :id, :integer
12
+ attribute :code, :string
13
+ attribute :state, :string
14
+ attribute :type, :string
15
+ attribute :value, :decimal
16
+ attribute :start_at, :datetime
17
+ attribute :end_at, :datetime
18
+ attribute :quantity, :integer
19
+ attribute :quantity_used, :integer
20
+ attribute :min_quantity_per_release, :integer
21
+ attribute :max_quantity_per_release, :integer
22
+ attribute :registrations_count, :integer
23
+ attribute :tickets_count, :integer
24
+ attribute :share_url, :string
25
+ attribute :description, :string
26
+ attribute :description_for_organizer, :string
27
+ attribute :show_public_releases, :boolean
28
+ attribute :show_secret_releases, :boolean
29
+ attribute :block_registrations_if_not_applicable, :boolean
30
+ attribute :disable_for_degressive, :boolean
31
+ attribute :created_at, :datetime
32
+ attribute :updated_at, :datetime
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,62 @@
1
+ module Tito
2
+ module Admin
3
+ module Resources
4
+ class Event < Tito::Resource
5
+ account_scoped!
6
+ path_template "events"
7
+ member_path_template "%{account}/%{id_or_slug}"
8
+ resource_name "event"
9
+ collection_name "events"
10
+ supports :list, :show, :create, :update, :delete
11
+
12
+ attribute :id, :integer
13
+ attribute :slug, :string
14
+ attribute :title, :string
15
+ attribute :url, :string
16
+ attribute :account_id, :integer
17
+ attribute :account_slug, :string
18
+ attribute :currency, :string
19
+ attribute :email_address, :string
20
+ attribute :description, :string
21
+
22
+ attribute :start_date, :string
23
+ attribute :start_time, :string
24
+ attribute :end_date, :string
25
+ attribute :end_time, :string
26
+ attribute :timezone, :string
27
+
28
+ attribute :live, :boolean
29
+ attribute :private, :boolean
30
+ attribute :archived, :boolean
31
+ attribute :test_mode, :boolean
32
+ attribute :setup, :boolean
33
+
34
+ attribute :tickets_count, :integer
35
+ attribute :registrations_count, :integer
36
+ attribute :releases_count, :integer
37
+
38
+ attribute :show_banner, :boolean
39
+ attribute :show_logo, :boolean
40
+ attribute :show_title, :boolean
41
+ attribute :show_prices_ex_tax, :boolean
42
+
43
+ attribute :require_billing_address, :boolean
44
+ attribute :require_company_name, :boolean
45
+ attribute :require_vat_number, :boolean
46
+
47
+ attribute :max_tickets_per_person, :integer
48
+ attribute :min_tickets_per_person, :integer
49
+
50
+ attribute :security_token, :string
51
+ attribute :metadata, :string
52
+
53
+ attribute :created_at, :datetime
54
+ attribute :updated_at, :datetime
55
+
56
+ expandable :releases, :release_ids, :release_slugs, :paypal_payment_options, :currency_options
57
+
58
+ action :duplicate, method: :post, path: "duplication"
59
+ end
60
+ end
61
+ end
62
+ end