Class: Osm::Model

Inherits:
Object
  • Object
show all
Includes:
ActiveAttr::Model, ActiveModel::MassAssignmentSecurity
Defined in:
lib/osm/model.rb

Overview

This class is expected to be inherited from. It provides the caching and permission handling for model objects.

Constant Summary collapse

SORT_BY =
[:id]
@@cache =

Class to use for caching

nil
@@cache_prepend =

Prepended to the key

'OSMAPI'
@@cache_ttl =

10 minutes

600

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.api_has_permission?(api, to, on, section, options = {}) ⇒ Boolean

Check if the user has granted the relevant permission to the API

Parameters:

  • api (Osm::Api)

    The api to use to make the request

  • to (Symbol)

    What action is required to be done (e.g. :read or :write)

  • on (Symbol)

    What the OSM permission is required on (e.g. :member or :programme)

  • section (Osm::Section, Fixnum, #to_i)

    The Section (or its ID) the permission is required on

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :no_cache (Boolean) — default: optional

    if true then the data will be retreived from OSM not the cache

Returns:

  • (Boolean)


183
184
185
186
187
# File 'lib/osm/model.rb', line 183

def self.api_has_permission?(api, to, on, section, options={})
  access = Osm::ApiAccess.get_ours(api, section, options)
  return false if access.nil?
  (access.permissions[on] || []).include?(to)
end

.cache_delete(api, key) ⇒ Object



112
113
114
115
# File 'lib/osm/model.rb', line 112

def self.cache_delete(api, key)
  return true if @@cache.nil?
  @@cache.delete(cache_key(api, key))
end

.cache_exist?(api, key) ⇒ Boolean

Returns:

  • (Boolean)


108
109
110
111
# File 'lib/osm/model.rb', line 108

def self.cache_exist?(api, key)
  return false if @@cache.nil?
  @@cache.exist?(cache_key(api, key))
end

.cache_key(api, key) ⇒ Object



116
117
118
119
# File 'lib/osm/model.rb', line 116

def self.cache_key(api, key)
  key = key.join('-') if key.is_a?(Array)
  "#{@@cache_prepend.empty? ? '' : "#{@@cache_prepend}-"}#{Osm::VERSION}-#{api.site}-#{key}"
end

.cache_read(api, key) ⇒ Object

Wrap cache calls



99
100
101
102
# File 'lib/osm/model.rb', line 99

def self.cache_read(api, key)
  return nil if @@cache.nil?
  @@cache.read(cache_key(api, key))
end

.cache_write(api, key, data, options = {}) ⇒ Object



103
104
105
106
107
# File 'lib/osm/model.rb', line 103

def self.cache_write(api, key, data, options={})
  return false if @@cache.nil?
  options.reverse_merge!(expires_in: @@cache_ttl)
  @@cache.write(cache_key(api, key), data, options)
end

.can_access_section?(api, section, options = {}) ⇒ Boolean

Check if the user has access to a section

Parameters:

  • api (Osm::Api)

    The api to use to make the request

  • section (Osm::Section, Fixnum, #to_i)

    The Section (or its ID) the permission is required on

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :no_cache (Boolean) — default: optional

    if true then the data will be retreived from OSM not the cache

Returns:

  • (Boolean)


146
147
148
# File 'lib/osm/model.rb', line 146

def self.can_access_section?(api, section, options={})
  api.get_user_permissions(options).keys.include?(section.to_i)
end

.configure(options) ⇒ Object

Configure the options used by all models

Parameters:

  • options (Hash)

Options Hash (options):

  • :cache (Class, nil)

    An instance of a cache class, must provide the methods (exist?, delete, write, read), for details see Rails.cache. Set to nil to disable caching.

  • :ttl (Fixnum) — default: optional, default = 1800 (30 minutes)

    The default TTL value for the cache, note that some items are cached for twice this time and others are cached for half this time (in seconds)

  • :prepend_to_key (String) — default: optional, default = 'OSMAPI'

    Text to prepend to the key used to store data in the cache

Returns:

  • nil

Raises:

  • (ArgumentError)


27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/osm/model.rb', line 27

def self.configure(options)
  raise ArgumentError, ":ttl must be a FixNum greater than 0" if options[:ttl] && !(options[:ttl].is_a?(Fixnum) && options[:ttl] > 0)
  raise ArgumentError, ":prepend_to_key must be a String" if options[:prepend_to_key] && !options[:prepend_to_key].is_a?(String)
  if options[:cache]
    [:exist?, :delete, :write, :read].each do |method|
      raise ArgumentError, ":cache must have a #{method} method" unless options[:cache].methods.include?(method)
    end
  end

  @@cache = options[:cache]
  @@cache_prepend = options[:prepend_to_key] || 'OSMAPI'
  @@cache_ttl = options[:ttl] || 600
  nil
end

.get_from_ids(api, ids, key, arguments = [], options, get_all_method) ⇒ Array

Get a list of items given a list of item IDs

Parameters:

  • api (Osm::Api)

    The api to use to make the request

  • ids (Array<Fixnum>)

    The ids of the items to get

  • key (String)

    The key for getting an item from the cache (the key [key, id] is generated)

  • argumentss (Array)

    The arguments to pass to get_all

  • options (Hash)
  • get_all_method (Symbol)

    The method to get all items (either :get_all or :get_for_section)

Options Hash (options):

  • :no_cache (Boolean) — default: optional

    if true then the data will be retreived from OSM not the cache

Returns:

  • (Array)

    An array of the items

Raises:

  • (ArgumentError)


246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/osm/model.rb', line 246

def self.get_from_ids(api, ids, key, arguments=[], options, get_all_method)
  raise ArgumentError, "get_all_method is invalid" unless [:get_all, :get_for_section].include?(get_all_method)
  items = Array.new
  ids.each do |id|
    if cache_exist?(api, [key, id])
      items.push cache_read(api, [*key, id])
    else
      # At least this one item is not in the cache - we might as well refresh the lot
      return self.send(get_all_method, api, *arguments, options.merge(:no_cache => true))
    end
  end
  return items
end

.has_access_to_section?(api, section, options = {}) ⇒ Boolean

Check if the user has access to a section

Parameters:

  • api (Osm::Api)

    The api to use to make the request

  • section (Osm::Section, Fixnum, #to_i)

    The Section (or its ID) the $

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :no_cache (Boolean) — default: optional

    if true then the data will be retreived from OSM not the cache

Returns:

  • (Boolean)

    If the Api user has access the section



127
128
129
# File 'lib/osm/model.rb', line 127

def self.has_access_to_section?(api, section, options={})
  api.get_user_permissions(options).keys.include?(section.to_i)
end

.has_permission?(api, to, on, section, options = {}) ⇒ Boolean

Check if the user has the relevant permission

Parameters:

  • api (Osm::Api)

    The api to use to make the request

  • to (Symbol)

    What action is required to be done (e.g. :read or :write)

  • on (Symbol)

    What the OSM permission is required on (e.g. :member or :programme)

  • section (Osm::Section, Fixnum, #to_i)

    The Section (or its ID) the permission is required on

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :no_cache (Boolean) — default: optional

    if true then the data will be retreived from OSM not the cache

Returns:

  • (Boolean)


156
157
158
# File 'lib/osm/model.rb', line 156

def self.has_permission?(api, to, on, section, options={})
  user_has_permission?(api, to, on, section, options) && api_has_permission?(api, to, on, section, options)
end

.require_ability_to(api, to, on, section, options = {}) ⇒ Object

Raise an exception if the user does not have the relevant permission

Parameters:

  • api (Osm::Api)

    The api to use to make the request

  • to (Symbol)

    What action is required to be done (e.g. :read or :write)

  • on (Symbol)

    What the OSM permission is required on (e.g. :member or :programme)

  • section (Osm::Section, Fixnum, #to_i)

    The Section (or its ID) the permission is required on

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :no_cache (Boolean) — default: optional

    if true then the data will be retreived from OSM not the cache



226
227
228
229
230
231
232
233
234
235
# File 'lib/osm/model.rb', line 226

def self.require_ability_to(api, to, on, section, options={})
  section = Osm::Section.get(api, section, options) unless section.is_a?(Osm::Section)
  require_permission(api, to, on, section, options)
  if section.youth_section? && [:register, :contact, :events, :flexi].include?(on)
    require_subscription(api, :silver, section, options)
  end
  if section.youth_section? && [:finance].include?(on)
    require_subscription(api, :gold, section, options)
  end
end

.require_access_to_section(api, section, options = {}) ⇒ Object

Raise an exception if the user does not have access to a section

Parameters:

  • api (Osm::Api)

    The api to use to make the request

  • section (Osm::Section, Fixnum, #to_i)

    The Section (or its ID) the permission is required on

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :no_cache (Boolean) — default: optional

    if true then the data will be retreived from OSM not the cache

Raises:



136
137
138
139
140
# File 'lib/osm/model.rb', line 136

def self.require_access_to_section(api, section, options={})
  unless has_access_to_section?(api, section, options)
    raise Osm::Forbidden, "You do not have access to that section"
  end
end

.require_permission(api, to, on, section, options = {}) ⇒ Object

Raise an exception if the user does not have the relevant permission

Parameters:

  • api (Osm::Api)

    The api to use to make the request

  • to (Symbol)

    What action is required to be done (e.g. :read or :write)

  • on (Symbol)

    What the OSM permission is required on (e.g. :member or :programme)

  • section (Osm::Section, Fixnum, #to_i)

    The Section (or its ID) the permission is required on

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :no_cache (Boolean) — default: optional

    if true then the data will be retreived from OSM not the cache

Raises:

  • (Osm::Forbidden)

    If the Api user does not have the required permission



196
197
198
199
200
201
202
203
204
205
# File 'lib/osm/model.rb', line 196

def self.require_permission(api, to, on, section, options={})
  section = Osm::Section.get(api, section.to_i, options) unless section.is_a?(Osm::Section)
  section_name = section.try(:name)
  unless user_has_permission?(api, to, on, section, options)
    raise Osm::Forbidden, "Your OSM user does not have permission to #{to} on #{on} for #{section_name}."
  end
  unless api_has_permission?(api, to, on, section, options)
    raise Osm::Forbidden, "You have not granted the #{to} permissions on #{on} to the #{api.api_name} API for #{section_name}."
  end
end

.require_subscription(api, level, section, options = {}) ⇒ Object

Raise an exception if the user does not have the relevant permission

Parameters:

  • api (Osm::Api)

    The api to use to make the request

  • level (Symbol, Fixnum)

    The OSM subscription level required (:bronze, :silver, :gold, :gold_plus)

  • section (Osm::Section, Fixnum, #to_i)

    The Section (or its ID) the subscription is required on

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :no_cache (Boolean) — default: optional

    if true then the data will be retreived from OSM not the cache

Raises:

  • (Osm::Forbidden)

    If the Section does not have the required OSM Subscription (or higher)



213
214
215
216
217
218
# File 'lib/osm/model.rb', line 213

def self.require_subscription(api, level, section, options={})
  section = Osm::Section.get(api, section, options) unless section.is_a?(Osm::Section)
  if section.nil? || !section.subscription_at_least?(level)
    raise Osm::Forbidden, "Insufficent OSM subscription level (#{Osm::SUBSCRIPTION_LEVEL_NAMES[level]} required for #{section.name})."
  end
end

.user_has_permission?(api, to, on, section, options = {}) ⇒ Boolean

Check if the user has the relevant permission within OSM

Parameters:

  • api (Osm::Api)

    The api to use to make the request

  • to (Symbol)

    What action is required to be done (e.g. :read or :write)

  • on (Symbol)

    What the OSM permission is required on (e.g. :member or :programme)

  • section (Osm::Section, Fixnum, #to_i)

    The Section (or its ID) the permission is required on

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :no_cache (Boolean) — default: optional

    if true then the data will be retreived from OSM not the cache

Returns:

  • (Boolean)


166
167
168
169
170
171
172
173
174
175
# File 'lib/osm/model.rb', line 166

def self.user_has_permission?(api, to, on, section, options={})
  section_id = section.to_i
  permissions = api.get_user_permissions(options)
  permissions = permissions[section_id] || {}
  permissions = permissions[on] || []
  unless permissions.include?(to)
    return false
  end
  return true
end

Instance Method Details

#<(another) ⇒ Object



55
56
57
# File 'lib/osm/model.rb', line 55

def <(another)
  send('<=>', another) < 0
end

#<=(another) ⇒ Object



58
59
60
# File 'lib/osm/model.rb', line 58

def <=(another)
  send('<=>', another) <= 0
end

#<=>(another) ⇒ Object

Compare functions



49
50
51
52
53
# File 'lib/osm/model.rb', line 49

def <=>(another)
  us_values = self.class::SORT_BY.map{ |i| self.try(i) }
  them_values = self.class::SORT_BY.map{ |i| another.try(i) }
  us_values <=> them_values
end

#>(another) ⇒ Object



61
62
63
# File 'lib/osm/model.rb', line 61

def >(another)
  send('<=>', another) > 0
end

#>=(another) ⇒ Object



64
65
66
# File 'lib/osm/model.rb', line 64

def >=(another)
  send('<=>', another) >= 0
end

#between?(min, max) ⇒ Boolean

Returns:

  • (Boolean)


67
68
69
# File 'lib/osm/model.rb', line 67

def between?(min, max)
  (send('<=>', min) > 0) && (send('<=>', max) < 0)
end

#changed_attributesObject

Get a list of attributes which have changed



74
75
76
# File 'lib/osm/model.rb', line 74

def changed_attributes
  attributes.keys.select{ |k| attributes[k] != @original_attributes[k] }
end

#reset_changed_attributesObject

Reset the list of attributes which have changed



79
80
81
82
83
84
85
# File 'lib/osm/model.rb', line 79

def reset_changed_attributes
  classes_to_clone = [Array, Hash]
  attributes_now = attributes.map do |k,v|
    [k, (classes_to_clone.include?(v.class) ? v.clone : v)]
  end # Deep(ish) clone
  @original_attributes = Hash[attributes_now]
end

#to_iObject

Default to_i conversion is of id



44
45
46
# File 'lib/osm/model.rb', line 44

def to_i
  id.to_i
end