osm 0.0.26 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/CHANGELOG.md +57 -0
  2. data/README.md +13 -7
  3. data/lib/osm.rb +47 -22
  4. data/lib/osm/activity.rb +52 -57
  5. data/lib/osm/api.rb +115 -1031
  6. data/lib/osm/api_access.rb +73 -36
  7. data/lib/osm/due_badges.rb +27 -12
  8. data/lib/osm/evening.rb +118 -55
  9. data/lib/osm/event.rb +275 -17
  10. data/lib/osm/flexi_record.rb +131 -0
  11. data/lib/osm/grouping.rb +37 -15
  12. data/lib/osm/member.rb +100 -41
  13. data/lib/osm/model.rb +95 -0
  14. data/lib/osm/register.rb +177 -0
  15. data/lib/osm/section.rb +163 -71
  16. data/lib/osm/term.rb +135 -21
  17. data/spec/osm/activity_spec.rb +7 -4
  18. data/spec/osm/api_access_spec.rb +44 -36
  19. data/spec/osm/api_spec.rb +32 -1147
  20. data/spec/osm/due_badges_spec.rb +8 -1
  21. data/spec/osm/evening_spec.rb +119 -54
  22. data/spec/osm/event_spec.rb +363 -13
  23. data/spec/osm/flexi_record_spec.rb +128 -0
  24. data/spec/osm/grouping_spec.rb +9 -5
  25. data/spec/osm/member_spec.rb +111 -36
  26. data/spec/osm/model_spec.rb +140 -0
  27. data/spec/osm/osm_spec.rb +7 -31
  28. data/spec/osm/register_spec.rb +103 -0
  29. data/spec/osm/section_spec.rb +208 -92
  30. data/spec/osm/term_spec.rb +164 -28
  31. data/spec/spec_helper.rb +22 -0
  32. data/version.rb +1 -1
  33. metadata +22 -29
  34. data/lib/osm/event_attendance.rb +0 -55
  35. data/lib/osm/flexi_record_data.rb +0 -51
  36. data/lib/osm/flexi_record_field.rb +0 -42
  37. data/lib/osm/register_data.rb +0 -64
  38. data/lib/osm/register_field.rb +0 -42
  39. data/lib/osm/role.rb +0 -133
  40. data/spec/osm/api_strangeness_spec.rb +0 -83
  41. data/spec/osm/event_attendance_spec.rb +0 -34
  42. data/spec/osm/flexi_record_data_spec.rb +0 -40
  43. data/spec/osm/flexi_record_field_spec.rb +0 -23
  44. data/spec/osm/register_data_spec.rb +0 -35
  45. data/spec/osm/register_field_spec.rb +0 -24
  46. data/spec/osm/role_spec.rb +0 -118
@@ -0,0 +1,131 @@
1
+ module Osm
2
+
3
+ class FlexiRecord
4
+
5
+ # Get structure for a flexi record
6
+ # @param [Osm::Api] api The api to use to make the request
7
+ # @param [Osm::Section, Fixnum] section the section (or its ID) to get the structure for
8
+ # @param [Fixnum] the id of the Flexi Record
9
+ # @!macro options_get
10
+ # @return [Array<Osm::FlexiRecordField>] representing the fields of the flexi record
11
+ def self.get_fields(api, section, id, options={})
12
+ section_id = section.to_i
13
+ cache_key = ['flexi_record_fields', id]
14
+
15
+ if !options[:no_cache] && Osm::Model.cache_exist?(api, cache_key) && Osm::Model.get_user_permissions(api, section_id)[:flexi].include?(:read)
16
+ return Osm::Model.cache_read(api, cache_key)
17
+ end
18
+
19
+ data = api.perform_query("extras.php?action=getExtra&sectionid=#{section_id}&extraid=#{id}")
20
+
21
+ structure = []
22
+ data['structure'].each do |item|
23
+ item['rows'].each do |row|
24
+ structure.push Osm::FlexiRecord::Field.new(
25
+ :id => row['field'],
26
+ :name => row['name'],
27
+ :editable => row['editable'] || false,
28
+ )
29
+ end
30
+ end
31
+ Osm::Model.cache_write(api, cache_key, structure)
32
+
33
+ return structure
34
+ end
35
+
36
+ # Get data for flexi record
37
+ # @param [Osm::Api] api The api to use to make the request
38
+ # @param [Osm::Section, Fixnum] section the section (or its ID) to get the register for
39
+ # @param [Fixnum] the id of the Flexi Record
40
+ # @param [Osm::Term, Fixnum, nil] section the term (or its ID) to get the register for, passing nil causes the current term to be used
41
+ # @!macro options_get
42
+ # @return [Array<FlexiRecordData>]
43
+ def self.get_data(api, section, id, term=nil, options={})
44
+ section = Osm::Section.get(api, section) if section.is_a?(Fixnum)
45
+ term_id = term.nil? ? Osm::Term.get_current_term_for_section(api, section).id : term.to_i
46
+ cache_key = ['flexi_record_data', id, term_id]
47
+
48
+ if !options[:no_cache] && Osm::Model.cache_exist?(api, cache_key) && Osm::Model.get_user_permissions(api, section.id)[:flexi].include?(:read)
49
+ return Osm::Model.cache_read(api, cache_key)
50
+ end
51
+
52
+ data = api.perform_query("extras.php?action=getExtraRecords&sectionid=#{section.id}&extraid=#{id}&termid=#{term_id}&section=#{section.type}")
53
+
54
+ to_return = []
55
+ data['items'].each do |item|
56
+ fields = item.select { |key, value|
57
+ ['firstname', 'lastname', 'dob', 'total', 'completed', 'age'].include?(key) || key.to_s.match(/\Af_\d+\Z/)
58
+ }
59
+ fields.merge!(
60
+ 'dob' => item['dob'].empty? ? nil : item['dob'],
61
+ 'total' => item['total'].empty? ? nil : item['total'],
62
+ 'completed' => item['completed'].empty? ? nil : item['completed'],
63
+ 'age' => item['age'].empty? ? nil : item['age'],
64
+ )
65
+
66
+ to_return.push Osm::FlexiRecord::Data.new(
67
+ :member_id => Osm::to_i_or_nil(item['scoutid']),
68
+ :grouping_id => Osm::to_i_or_nil(item['patrolid'].eql?('') ? nil : item['patrolid']),
69
+ :fields => fields
70
+ )
71
+ end
72
+
73
+ Osm::Model.cache_write(api, cache_key, to_return)
74
+ return to_return
75
+ end
76
+
77
+
78
+
79
+
80
+ class Field < Osm::Model
81
+ # @!attribute [rw] id
82
+ # @return [String] OSM identifier for the field. Special ones are 'dob', 'total', 'completed', 'age', 'firstname' and 'lastname', user ones are of the format 'f\_NUMBER'
83
+ # @!attribute [rw] name
84
+ # @return [String] Human readable name for the field
85
+ # @!attribute [rw] editable
86
+ # @return [Boolean] Wether the field can be edited
87
+
88
+ attribute :id, :type => String
89
+ attribute :name, :type => String
90
+ attribute :editable, :type => Boolean, :default => false
91
+
92
+ attr_accessible :id, :name, :editable
93
+
94
+ validates_presence_of :id
95
+ validates_presence_of :name
96
+ validates_inclusion_of :editable, :in => [true, false]
97
+
98
+ # @!method initialize
99
+ # Initialize a new FlexiRecordField
100
+ # @param [Hash] attributes the hash of attributes (see attributes for descriptions, use Symbol of attribute name as the key)
101
+
102
+ end # Class FlexiRecord::Data
103
+
104
+
105
+ class Data < Osm::Model
106
+ # @!attribute [rw] member_id
107
+ # @return [Fixnum] OSM id for the member
108
+ # @!attribute [rw] grouping__id
109
+ # @return [Fixnum] OSM id for the grouping the member is in
110
+ # @!attribute [rw] fields
111
+ # @return [Hash] Keys are the field's id, values are the field values
112
+
113
+ attribute :member_id, :type => Integer
114
+ attribute :grouping_id, :type => Integer
115
+ attribute :fields, :default => {}
116
+
117
+ attr_accessible :member_id, :grouping_id, :fields
118
+
119
+ validates_numericality_of :member_id, :only_integer=>true, :greater_than=>0
120
+ validates_numericality_of :grouping_id, :only_integer=>true, :greater_than_or_equal_to=>-2
121
+ validates :fields, :hash => {:key_type => String}
122
+
123
+ # @!method initialize
124
+ # Initialize a new FlexiRecordData
125
+ # @param [Hash] attributes the hash of attributes (see attributes for descriptions, use Symbol of attribute name as the key)
126
+
127
+ end # Class FlexiRecord::Data
128
+
129
+ end # Class FlexiRecord
130
+
131
+ end # Module
@@ -1,11 +1,11 @@
1
1
  module Osm
2
2
 
3
- class Grouping
4
- include ::ActiveAttr::MassAssignmentSecurity
5
- include ::ActiveAttr::Model
3
+ class Grouping < Osm::Model
6
4
 
7
5
  # @!attribute [rw] id
8
6
  # @return [Fixnum] the id for grouping
7
+ # @!attribute [rw] section_id
8
+ # @return [Fixnum] the id for the section this grouping belongs to
9
9
  # @!attribute [rw] name
10
10
  # @return [String] the name of the grouping
11
11
  # @!attribute [rw] active
@@ -14,34 +14,56 @@ module Osm
14
14
  # @return [Fixnum] the points awarded to the grouping
15
15
 
16
16
  attribute :id, :type => Integer
17
+ attribute :section_id, :type => Integer
17
18
  attribute :name, :type => String
18
19
  attribute :active, :type => Boolean
19
20
  attribute :points, :type => Integer
20
21
 
21
- attr_accessible :id, :name, :active, :points
22
+ attr_accessible :id, :section_id, :name, :active, :points
22
23
 
23
24
  validates_numericality_of :id, :only_integer=>true, :greater_than_or_equal_to=>-2
25
+ validates_numericality_of :section_id, :only_integer=>true, :greater_than=>0
24
26
  validates_presence_of :name
25
27
  validates_numericality_of :points, :only_integer=>true
26
28
  validates_presence_of :active
27
29
 
28
30
 
29
- # @!method initialize
30
- # Initialize a new Term
31
- # @param [Hash] attributes the hash of attributes (see attributes for descriptions, use Symbol of attribute name as the key)
31
+ # Get the groupings that a section has
32
+ # @param [Osm::Api] api The api to use to make the request
33
+ # @param [Fixnum] section the section (or its ID) of the section to get groupings for
34
+ # @!macro options_get
35
+ # @return [Array<Osm::Grouping>, nil] An array of groupings or nil if the user can not access that section
36
+ def self.get_for_section(api, section, options={})
37
+ section_id = section.to_i
38
+ cache_key = ['groupings', section_id]
32
39
 
40
+ if !options[:no_cache] && cache_exist?(api, cache_key)
41
+ return cache_read(api, cache_key)
42
+ end
33
43
 
34
- # Initialize a new Grouping from api data
35
- # @param [Hash] data the hash of data provided by the API
36
- def self.from_api(data)
37
- new({
38
- :id => Osm::to_i_or_nil(data['patrolid']),
39
- :name => data['name'],
40
- :active => (data['active'] == 1),
41
- :points => Osm::to_i_or_nil(data['points']),
44
+ data = api.perform_query("users.php?action=getPatrols&sectionid=#{section_id}")
45
+
46
+ result = Array.new
47
+ data['patrols'].each do |item|
48
+ result.push Osm::Grouping.new({
49
+ :id => Osm::to_i_or_nil(item['patrolid']),
50
+ :section_id => section_id,
51
+ :name => item['name'],
52
+ :active => (item['active'] == 1),
53
+ :points => Osm::to_i_or_nil(item['points']),
42
54
  })
55
+ end
56
+ cache_write(api, cache_key, result)
57
+
58
+ return result
43
59
  end
44
60
 
61
+
62
+ # @!method initialize
63
+ # Initialize a new Term
64
+ # @param [Hash] attributes the hash of attributes (see attributes for descriptions, use Symbol of attribute name as the key)
65
+
66
+
45
67
  end # Class Grouping
46
68
 
47
69
  end # Module
@@ -1,8 +1,6 @@
1
1
  module Osm
2
2
 
3
- class Member
4
- include ::ActiveAttr::MassAssignmentSecurity
5
- include ::ActiveAttr::Model
3
+ class Member < Osm::Model
6
4
 
7
5
  # @!attribute [rw] id
8
6
  # @return [Fixnum] the id for the member
@@ -54,6 +52,24 @@ module Osm
54
52
  # @return [String] the member's ethnicity
55
53
  # @!attribute [rw] subs
56
54
  # @return [String] details about the member's subs
55
+ # @!attribute [rw] custom1
56
+ # @return [String] the custom1 data for the member
57
+ # @!attribute [rw] custom2
58
+ # @return [String] the custom2 data for the member
59
+ # @!attribute [rw] custom3
60
+ # @return [String] the custom3 data for the member
61
+ # @!attribute [rw] custom4
62
+ # @return [String] the custom4 data for the member
63
+ # @!attribute [rw] custom5
64
+ # @return [String] the custom5 data for the member
65
+ # @!attribute [rw] custom6
66
+ # @return [String] the custom6 data for the member
67
+ # @!attribute [rw] custom7
68
+ # @return [String] the custom7 data for the member
69
+ # @!attribute [rw] custom8
70
+ # @return [String] the custom8 data for the member
71
+ # @!attribute [rw] custom9
72
+ # @return [String] the custom9 data for the member
57
73
  # @!attribute [rw] grouping_id
58
74
  # @return [Fixnum] the grouping within the section that the member belongs to
59
75
  # @!attribute [rw] grouping_leader
@@ -90,13 +106,26 @@ module Osm
90
106
  attribute :school, :type => String, :default => ''
91
107
  attribute :ethnicity, :type => String, :default => ''
92
108
  attribute :subs, :type => String, :default => ''
109
+ attribute :custom1, :type => String, :default => ''
110
+ attribute :custom2, :type => String, :default => ''
111
+ attribute :custom3, :type => String, :default => ''
112
+ attribute :custom4, :type => String, :default => ''
113
+ attribute :custom5, :type => String, :default => ''
114
+ attribute :custom6, :type => String, :default => ''
115
+ attribute :custom7, :type => String, :default => ''
116
+ attribute :custom8, :type => String, :default => ''
117
+ attribute :custom9, :type => String, :default => ''
93
118
  attribute :grouping_id, :type => Integer
94
119
  attribute :grouping_leader, :type => Integer
95
120
  attribute :joined, :type => Date
96
121
  attribute :age, :type => String
97
122
  attribute :joined_years, :type => Integer
98
123
 
99
- attr_accessible :id, :section_id, :type, :first_name, :last_name, :email1, :email2, :email3, :email4, :phone1, :phone2, :phone3, :phone4, :address, :address2, :date_of_birth, :started, :joining_in_years, :parents, :notes, :medical, :religion, :school, :ethnicity, :subs, :grouping_id, :grouping_leader, :joined, :age, :joined_years
124
+ attr_accessible :id, :section_id, :type, :first_name, :last_name, :email1, :email2, :email3, :email4,
125
+ :phone1, :phone2, :phone3, :phone4, :address, :address2, :date_of_birth, :started,
126
+ :joining_in_years, :parents, :notes, :medical, :religion, :school, :ethnicity, :subs,
127
+ :custom1, :custom2, :custom3, :custom4, :custom5, :custom6, :custom7, :custom8, :custom9,
128
+ :grouping_id, :grouping_leader, :joined, :age, :joined_years
100
129
 
101
130
  validates_numericality_of :id, :only_integer=>true, :greater_than=>0
102
131
  validates_numericality_of :section_id, :only_integer=>true, :greater_than=>0
@@ -112,48 +141,78 @@ module Osm
112
141
  validates_format_of :age, :with => /\A[0-9]{2}\/(0[0-9]|1[012])\Z/, :message => 'age is not in the correct format (yy/mm)', :allow_blank => true
113
142
 
114
143
 
144
+ # Get members for a section
145
+ # @param [Osm::Api] api The api to use to make the request
146
+ # @param [Osm::Section, Fixnum] section the section (or its ID) to get the members for
147
+ # @param [Osm::Term, Fixnum, nil] term the term (or its ID) to get the members for, passing nil causes the current term to be used
148
+ # @!macro options_get
149
+ # @return [Array<Osm::Member>]
150
+ def self.get_for_section(api, section, term=nil, options={})
151
+ term_id = term.nil? ? Osm::Term.get_current_term_for_section(api, section).id : term.to_i
152
+ section_id = section.to_i
153
+ cache_key = ['members', section_id, term_id]
154
+
155
+ if !options[:no_cache] && cache_exist?(api, cache_key) && get_user_permissions(api, section_id)[:member].include?(:read)
156
+ return cache_read(api, cache_key)
157
+ end
158
+
159
+ data = api.perform_query("users.php?action=getUserDetails&sectionid=#{section_id}&termid=#{term_id}")
160
+
161
+ result = Array.new
162
+ data['items'].each do |item|
163
+ result.push Osm::Member.new(
164
+ :section_id => section_id,
165
+ :id => Osm::to_i_or_nil(item['scoutid']),
166
+ :type => item['type'],
167
+ :first_name => item['firstname'],
168
+ :last_name => item['lastname'],
169
+ :email1 => item['email1'],
170
+ :email2 => item['email2'],
171
+ :email3 => item['email3'],
172
+ :email4 => item['email4'],
173
+ :phone1 => item['phone1'],
174
+ :phone2 => item['phone2'],
175
+ :phone3 => item['phone3'],
176
+ :phone4 => item['phone4'],
177
+ :address => item['address'],
178
+ :address2 => item['address2'],
179
+ :date_of_birth => Osm::parse_date(item['dob'], :ignore_epoch => true),
180
+ :started => Osm::parse_date(item['started']),
181
+ :joining_in_years => item['joining_in_yrs'].to_i,
182
+ :parents => item['parents'],
183
+ :notes => item['notes'],
184
+ :medical => item['medical'],
185
+ :religion => item['religion'],
186
+ :school => item['school'],
187
+ :ethnicity => item['ethnicity'],
188
+ :subs => item['subs'],
189
+ :custom1 => item['custom1'],
190
+ :custom2 => item['custom2'],
191
+ :custom3 => item['custom3'],
192
+ :custom4 => item['custom4'],
193
+ :custom5 => item['custom5'],
194
+ :custom6 => item['custom6'],
195
+ :custom7 => item['custom7'],
196
+ :custom8 => item['custom8'],
197
+ :custom9 => item['custom9'],
198
+ :grouping_id => Osm::to_i_or_nil(item['patrolid']),
199
+ :grouping_leader => Osm::to_i_or_nil(item['patrolleader']),
200
+ :joined => Osm::parse_date(item['joined']),
201
+ :age => item['age'],
202
+ :joined_years => item['yrs'].to_i,
203
+ )
204
+ end
205
+
206
+ cache_write(api, cache_key, result)
207
+ return result
208
+ end
209
+
210
+
115
211
  # @!method initialize
116
212
  # Initialize a new Term
117
213
  # @param [Hash] attributes the hash of attributes (see attributes for descriptions, use Symbol of attribute name as the key)
118
214
 
119
215
 
120
- # Initialize a new Member from api data
121
- # @param [Hash] data the hash of data provided by the API
122
- def self.from_api(data, section_id)
123
- new({
124
- :section_id => section_id,
125
- :id => Osm::to_i_or_nil(data['scoutid']),
126
- :type => data['type'],
127
- :first_name => data['firstname'],
128
- :last_name => data['lastname'],
129
- :email1 => data['email1'],
130
- :email2 => data['email2'],
131
- :email3 => data['email3'],
132
- :email4 => data['email4'],
133
- :phone1 => data['phone1'],
134
- :phone2 => data['phone2'],
135
- :phone3 => data['phone3'],
136
- :phone4 => data['phone4'],
137
- :address => data['address'],
138
- :address2 => data['address2'],
139
- :date_of_birth => Osm::parse_date(data['dob'], :ignore_epoch => true),
140
- :started => Osm::parse_date(data['started']),
141
- :joining_in_years => data['joining_in_yrs'].to_i,
142
- :parents => data['parents'],
143
- :notes => data['notes'],
144
- :medical => data['medical'],
145
- :religion => data['religion'],
146
- :school => data['school'],
147
- :ethnicity => data['ethnicity'],
148
- :subs => data['subs'],
149
- :grouping_id => Osm::to_i_or_nil(data['patrolid']),
150
- :grouping_leader => Osm::to_i_or_nil(data['patrolleader']),
151
- :joined => Osm::parse_date(data['joined']),
152
- :age => data['age'],
153
- :joined_years => data['yrs'].to_i,
154
- })
155
- end
156
-
157
216
  # Get the years element of this scout's age
158
217
  # @return [Fixnum] the number of years this scout has been alive
159
218
  def age_years
@@ -0,0 +1,95 @@
1
+ # @!macro [new] options_get
2
+ # @param [Hash] options
3
+ # @option options [Boolean] :no_cache (optional) if true then the data will be retreived from OSM not the cache
4
+
5
+
6
+ module Osm
7
+
8
+ # This class is expected to be inherited from.
9
+ # It provides the caching and permission handling for model objects.
10
+ class Model
11
+ include ::ActiveAttr::MassAssignmentSecurity
12
+ include ::ActiveAttr::Model
13
+
14
+ @@cache = nil # Class to use for caching
15
+ @@cache_prepend = 'OSMAPI' # Prepended to the key
16
+ @@cache_ttl = 600 # 10 minutes
17
+
18
+
19
+ # Configure the options used by all models
20
+ # @param [Hash] options
21
+ # @option options [Class, nil] :cache 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.
22
+ # @option options [Fixnum] :ttl (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)
23
+ # @option options [String] :prepend_to_key (optional, default = 'OSMAPI') Text to prepend to the key used to store data in the cache
24
+ # @return nil
25
+ def self.configure(options)
26
+ raise ArgumentError, ":ttl must be a FixNum greater than 0" if options[:ttl] && !(options[:ttl].is_a?(Fixnum) && options[:ttl] > 0)
27
+ raise ArgumentError, ":prepend_to_key must be a String" if options[:prepend_to_key] && !options[:prepend_to_key].is_a?(String)
28
+ if options[:cache]
29
+ [:exist?, :delete, :write, :read].each do |method|
30
+ raise ArgumentError, ":cache must have a #{method} method" unless options[:cache].methods.include?(method)
31
+ end
32
+ end
33
+
34
+ @@cache = options[:cache]
35
+ @@cache_prepend = options[:prepend_to_key] || 'OSMAPI'
36
+ @@cache_ttl = options[:ttl] || 1800
37
+ nil
38
+ end
39
+
40
+
41
+ def to_i
42
+ id
43
+ end
44
+
45
+ private
46
+ # Wrap cache calls
47
+ def self.cache_read(api, key)
48
+ return nil if @@cache.nil?
49
+ @@cache.read(cache_key(api, key))
50
+ end
51
+ def self.cache_write(api, key, data, options={})
52
+ return false if @@cache.nil?
53
+ options.merge!(:expires_in => @@cache_ttl)
54
+ @@cache.write(cache_key(api, key), data, options)
55
+ end
56
+ def self.cache_exist?(api, key)
57
+ return false if @@cache.nil?
58
+ @@cache.exist?(cache_key(api, key))
59
+ end
60
+ def self.cache_delete(api, key)
61
+ return true if @@cache.nil?
62
+ @@cache.delete(cache_key(api, key))
63
+ end
64
+ def self.cache_key(api, key)
65
+ key = key.join('-') if key.is_a?(Array)
66
+ "#{@@cache_prepend.empty? ? '' : "#{@@cache_prepend}-"}#{api.site}-#{key}"
67
+ end
68
+
69
+
70
+ # Get access permission for an API user
71
+ # @param [Osm::Api] The api to use to make the request
72
+ # @param [Fixnum, nil] section_id to get permissions for, if nil a Hash of all section's permissions is returned
73
+ # @return [Hash] the permissions Hash
74
+ def self.get_user_permissions(api, section_id=nil)
75
+ key = ['permissions', api.user_id]
76
+ permissions = cache_exist?(api, key) ? cache_read(api, key) : Osm::Section.fetch_user_permissions(api)
77
+ return section_id.nil? ? permissions : (permissions[section_id] || {})
78
+ end
79
+
80
+ # Set access permission for an API user
81
+ # @param [Osm::Api] The api to use to make the request
82
+ # @param [Fixnum, nil] section_id to set permissions for, if nil the Hash of all section's permissions is set
83
+ # @param [Hash] permissions the permissions Hash
84
+ def self.set_user_permissions(api, section_id=nil, permissions)
85
+ key = ['permissions', api.user_id]
86
+ if section_id
87
+ permissions = get_user_permissions(api).merge(section_id => permissions)
88
+ end
89
+ cache_write(api, key, permissions)
90
+ end
91
+
92
+
93
+ end # Class Model
94
+
95
+ end # Module