Class: Rhino::Configuration

Inherits:
Object
  • Object
show all
Defined in:
lib/rhino/configuration.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeConfiguration

Returns a new instance of Configuration.



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/rhino/configuration.rb', line 14

def initialize
  @models = {}
  @route_groups = {}
  @multi_tenant = {
    organization_identifier_column: "id"
  }
  @invitations = {
    expires_days: 7,
    allowed_roles: nil
  }
  @nested = {
    path: "nested",
    max_operations: 50,
    allowed_models: nil
  }
  @auth = {
    enforce_group_membership: false
  }
  @test_framework = "rspec"
  @client_path = nil
  @mobile_path = nil
  @route_key = nil
end

Instance Attribute Details

#authObject

Returns the value of attribute auth.



12
13
14
# File 'lib/rhino/configuration.rb', line 12

def auth
  @auth
end

#client_pathObject

Returns the value of attribute client_path.



5
6
7
# File 'lib/rhino/configuration.rb', line 5

def client_path
  @client_path
end

#invitationsObject

Returns the value of attribute invitations.



5
6
7
# File 'lib/rhino/configuration.rb', line 5

def invitations
  @invitations
end

#mobile_pathObject

Returns the value of attribute mobile_path.



5
6
7
# File 'lib/rhino/configuration.rb', line 5

def mobile_path
  @mobile_path
end

#modelsObject

Returns the value of attribute models.



5
6
7
# File 'lib/rhino/configuration.rb', line 5

def models
  @models
end

#multi_tenantObject

Returns the value of attribute multi_tenant.



5
6
7
# File 'lib/rhino/configuration.rb', line 5

def multi_tenant
  @multi_tenant
end

#nestedObject

Returns the value of attribute nested.



5
6
7
# File 'lib/rhino/configuration.rb', line 5

def nested
  @nested
end

#route_groupsObject

Returns the value of attribute route_groups.



5
6
7
# File 'lib/rhino/configuration.rb', line 5

def route_groups
  @route_groups
end

#route_keyObject

Global default route key: the column matched against the :id URL segment on member endpoints (show/update/destroy/restore/force_delete) for every model that does not declare its own rhino_route_key. Default nil = primary key (today's behavior, fully backward compatible).



11
12
13
# File 'lib/rhino/configuration.rb', line 11

def route_key
  @route_key
end

#test_frameworkObject

Returns the value of attribute test_framework.



5
6
7
# File 'lib/rhino/configuration.rb', line 5

def test_framework
  @test_framework
end

Instance Method Details

#auth_enabled_groupsObject

Names of all groups (except :public) that opted into per-group auth.



150
151
152
153
# File 'lib/rhino/configuration.rb', line 150

def auth_enabled_groups
  @route_groups.keys.reject { |name| name.to_s == "public" }
               .select { |name| group_auth_enabled?(name) }
end

#auth_enabled_legacy_groupsObject

Names of auth-enabled groups that have an empty prefix AND no domain, i.e. groups whose auth routes would be byte-for-byte identical to the legacy unprefixed /api/auth/* set (GROUP_AUTH_DESIGN.md ยง11.1). Such a group IS the default/legacy auth: the legacy routes adopt its route_group/hooks instead of registering a colliding second set. Two or more is a conflict (raised by the route-group validator).



161
162
163
164
165
166
167
168
# File 'lib/rhino/configuration.rb', line 161

def auth_enabled_legacy_groups
  auth_enabled_groups.select do |name|
    group = @route_groups[name.to_sym]
    prefix = group[:prefix].to_s
    domain = group[:domain]
    prefix.empty? && (domain.nil? || domain.to_s.strip.empty?)
  end
end

#enforce_group_membership?Boolean

Master flag (default off). When off, behavior is byte-for-byte today's: no group-membership enforcement.

Returns:

  • (Boolean)


46
47
48
# File 'lib/rhino/configuration.rb', line 46

def enforce_group_membership?
  !!@auth[:enforce_group_membership]
end

#group_auth_enabled?(group_name) ⇒ Boolean

Whether a group has per-group auth routes enabled (auth: true). The public group is never auth-enabled.

Returns:

  • (Boolean)


142
143
144
145
146
147
# File 'lib/rhino/configuration.rb', line 142

def group_auth_enabled?(group_name)
  return false if group_name.to_s == "public"

  group = @route_groups[group_name.to_sym]
  !!(group && group[:auth])
end

#group_is_tenant?(group_name) ⇒ Boolean

Whether a group is a tenant group (organization-scoped). Only the reserved :tenant group is treated as a tenant group, matching has_tenant_group?.

Returns:

  • (Boolean)


196
197
198
# File 'lib/rhino/configuration.rb', line 196

def group_is_tenant?(group_name)
  group_name.to_s == "tenant"
end

#has_public_group?Boolean

Whether a 'public' route group is configured

Returns:

  • (Boolean)


107
108
109
# File 'lib/rhino/configuration.rb', line 107

def has_public_group?
  @route_groups.key?(:public)
end

#has_tenant_group?Boolean

Whether a 'tenant' route group is configured

Returns:

  • (Boolean)


102
103
104
# File 'lib/rhino/configuration.rb', line 102

def has_tenant_group?
  @route_groups.key?(:tenant)
end

#hooks_for_group(group_name) ⇒ Object

Resolve the configured lifecycle-hooks class for a group, instantiated. Returns nil when the group has no hooks configured. Accepts a class, a class name string, or an instance.



173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/rhino/configuration.rb', line 173

def hooks_for_group(group_name)
  return nil if group_name.nil?

  group = @route_groups[group_name.to_sym]
  return nil unless group

  hooks = group[:hooks]
  return nil if hooks.nil?

  case hooks
  when String
    klass = hooks.safe_constantize
    klass&.new
  when Class
    hooks.new
  else
    hooks
  end
end

#model(slug, klass_name) ⇒ Object

Register a model with its slug Usage: config.model :posts, 'Post'



52
53
54
# File 'lib/rhino/configuration.rb', line 52

def model(slug, klass_name)
  @models[slug.to_sym] = klass_name.to_s
end

#model_in_group?(slug, group_name) ⇒ Boolean

Check if a specific slug belongs to a specific group

Returns:

  • (Boolean)


132
133
134
# File 'lib/rhino/configuration.rb', line 132

def model_in_group?(slug, group_name)
  models_for_group(group_name).include?(slug.to_sym)
end

#models_for_group(group_name) ⇒ Object

Resolve the model slugs for a given route group



112
113
114
115
116
117
118
119
120
121
122
# File 'lib/rhino/configuration.rb', line 112

def models_for_group(group_name)
  group = @route_groups[group_name.to_sym]
  return [] unless group

  group_models = group[:models]
  if group_models == :all || group_models == "*"
    @models.keys
  else
    Array(group_models).map(&:to_sym) & @models.keys
  end
end

#public_model?(slug) ⇒ Boolean

Check if a model belongs to the 'public' route group

Returns:

  • (Boolean)


125
126
127
128
129
# File 'lib/rhino/configuration.rb', line 125

def public_model?(slug)
  return false unless has_public_group?

  models_for_group(:public).include?(slug.to_sym)
end

#resolve_model(slug) ⇒ Object

Resolve a model class from its slug



80
81
82
83
84
85
86
87
88
89
90
# File 'lib/rhino/configuration.rb', line 80

def resolve_model(slug)
  klass_name = @models[slug.to_sym]
  raise ActiveRecord::RecordNotFound, "The #{slug} model does not exist" unless klass_name

  klass = klass_name.constantize
  raise ActiveRecord::RecordNotFound, "The #{slug} model does not exist" unless klass

  klass
rescue NameError
  raise ActiveRecord::RecordNotFound, "The #{slug} model does not exist"
end

#route_group(name, prefix: "", domain: nil, middleware: [], models: :all, auth: false, hooks: nil) ⇒ Object

Register a route group with its configuration Usage: config.route_group :tenant, prefix: ':organization', middleware: [Rhino::Middleware::ResolveOrganizationFromRoute], models: :all

The optional domain: keyword constrains the group's routes to a specific host. Two groups can then share the same prefix: but live on different domains. A parameterized domain such as "organization.example.com" captures the subdomain and feeds organization resolution exactly like the path-prefix ":organization" does. Groups without a domain (nil/blank) match any host (default, fully backward compatible).



65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/rhino/configuration.rb', line 65

def route_group(name, prefix: "", domain: nil, middleware: [], models: :all, auth: false, hooks: nil)
  normalized_domain = domain.to_s.strip
  normalized_domain = nil if normalized_domain.empty?

  @route_groups[name.to_sym] = {
    prefix: prefix.to_s,
    domain: normalized_domain,
    middleware: Array(middleware),
    models: models,
    auth: !!auth,
    hooks: hooks
  }
end

#slug_for(model_class) ⇒ Object

Find the slug for a given model class



93
94
95
96
97
98
99
# File 'lib/rhino/configuration.rb', line 93

def slug_for(model_class)
  class_name = model_class.is_a?(Class) ? model_class.name : model_class.class.name
  @models.each do |slug, klass_name|
    return slug if klass_name == class_name
  end
  nil
end