hydra-access-controls 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,38 @@
1
+ # will move to lib/hydra/access_control folder/namespace in release 5.x
2
+ # Provides methods for determining permissions
3
+ # If you include this into a Controller, it will also make a number of these methods available as view helpers.
4
+ module Hydra::AccessControlsEvaluation
5
+
6
+ def self.included(klass)
7
+ if klass.respond_to?(:helper_method)
8
+ klass.helper_method(:editor?)
9
+ klass.helper_method(:reader?)
10
+ klass.helper_method(:test_permission?)
11
+ end
12
+ end
13
+
14
+ # Test the current user's permissions. This method is used by the editor? and reader? methods
15
+ # @param [Symbol] permission_type valid options: :edit, :read
16
+ # This is available as a view helper method as well as within your controllers.
17
+ # @example
18
+ # test_permission(:edit)
19
+ def test_permission(permission_type)
20
+ ActiveSupport::Deprecation.warn("test_permission has been deprecated. Use can? instead")
21
+ can? permission_type, @permissions_solr_document
22
+ end
23
+
24
+ # Test whether the the current user has edit permissions.
25
+ # This is available as a view helper method as well as within your controllers.
26
+ def editor?
27
+ logger.warn("editor? has been deprecated. Use can? instead")
28
+ can? :edit, @permissions_solr_document
29
+ end
30
+
31
+ # Test whether the the current user has read permissions.
32
+ # This is available as a view helper method as well as within your controllers.
33
+ def reader?
34
+ logger.warn("reader? has been deprecated. Use can? instead")
35
+ can? :read, @permissions_solr_document
36
+ end
37
+
38
+ end
@@ -0,0 +1,6 @@
1
+ module Hydra
2
+ module Datastream
3
+ extend ActiveSupport::Autoload
4
+ autoload :RightsMetadata
5
+ end
6
+ end
@@ -0,0 +1,192 @@
1
+ require 'active_support/core_ext/string'
2
+ module Hydra
3
+ module Datastream
4
+ # Implements Hydra RightsMetadata XML terminology for asserting access permissions
5
+ class RightsMetadata < ActiveFedora::NokogiriDatastream
6
+
7
+ set_terminology do |t|
8
+ t.root(:path=>"rightsMetadata", :xmlns=>"http://hydra-collab.stanford.edu/schemas/rightsMetadata/v1", :schema=>"http://github.com/projecthydra/schemas/tree/v1/rightsMetadata.xsd")
9
+ t.copyright {
10
+ t.machine {
11
+ t.uvalicense
12
+ t.cclicense
13
+ t.license
14
+ }
15
+ t.human_readable(:path=>"human")
16
+ t.license(:proxy=>[:machine, :license ])
17
+ t.cclicense(:proxy=>[:machine, :cclicense ])
18
+ }
19
+ t.access {
20
+ t.human_readable(:path=>"human")
21
+ t.machine {
22
+ t.group
23
+ t.person
24
+ }
25
+ t.person(:proxy=>[:machine, :person])
26
+ t.group(:proxy=>[:machine, :group])
27
+ # accessor :access_person, :term=>[:access, :machine, :person]
28
+ }
29
+ t.discover_access(:ref=>[:access], :attributes=>{:type=>"discover"})
30
+ t.read_access(:ref=>[:access], :attributes=>{:type=>"read"})
31
+ t.edit_access(:ref=>[:access], :attributes=>{:type=>"edit"})
32
+ # A bug in OM prevnts us from declaring proxy terms at the root of a Terminology
33
+ # t.access_person(:proxy=>[:access,:machine,:person])
34
+ # t.access_group(:proxy=>[:access,:machine,:group])
35
+
36
+ t.embargo {
37
+ t.human_readable(:path=>"human")
38
+ t.machine{
39
+ t.date(:type =>"release")
40
+ }
41
+ t.embargo_release_date(:proxy => [:machine, :date])
42
+ }
43
+ end
44
+
45
+ # Generates an empty Mods Article (used when you call ModsArticle.new without passing in existing xml)
46
+ def self.xml_template
47
+ builder = Nokogiri::XML::Builder.new do |xml|
48
+ xml.rightsMetadata(:version=>"0.1", "xmlns"=>"http://hydra-collab.stanford.edu/schemas/rightsMetadata/v1") {
49
+ xml.copyright {
50
+ xml.human
51
+ xml.machine {
52
+ xml.uvalicense "no"
53
+ }
54
+ }
55
+ xml.access(:type=>"discover") {
56
+ xml.human
57
+ xml.machine
58
+ }
59
+ xml.access(:type=>"read") {
60
+ xml.human
61
+ xml.machine
62
+ }
63
+ xml.access(:type=>"edit") {
64
+ xml.human
65
+ xml.machine
66
+ }
67
+ xml.embargo{
68
+ xml.human
69
+ xml.machine
70
+ }
71
+ }
72
+ end
73
+ return builder.doc
74
+ end
75
+
76
+ # Returns the permissions for the selected person/group
77
+ # If new_access_level is provided, updates the selected person/group access_level to the one specified
78
+ # A new_access_level of "none" will remove all access_levels for the selected person/group
79
+ # @param [Hash] selector hash in format {type => identifier}
80
+ # @param new_access_level (default nil)
81
+ # @return Hash in format {type => access_level}.
82
+ #
83
+ # ie.
84
+ # permissions({:person=>"person123"})
85
+ # => {"person123"=>"edit"}
86
+ # permissions({:person=>"person123"}, "read")
87
+ # => {"person123"=>"read"}
88
+ # permissions({:person=>"person123"})
89
+ # => {"person123"=>"read"}
90
+ def permissions(selector, new_access_level=nil)
91
+ type = selector.keys.first.to_sym
92
+ actor = selector.values.first
93
+ if new_access_level.nil?
94
+ xpath = self.class.terminology.xpath_for(:access, type, actor)
95
+ nodeset = self.find_by_terms(xpath)
96
+ if nodeset.empty?
97
+ return "none"
98
+ else
99
+ return nodeset.first.ancestors("access").first.attributes["type"].text
100
+ end
101
+ else
102
+ remove_all_permissions(selector)
103
+ unless new_access_level == "none"
104
+ access_type_symbol = "#{new_access_level}_access".to_sym
105
+ result = self.update_values([access_type_symbol, type] => {"-1"=>actor})
106
+ end
107
+ self.dirty = true
108
+ return new_access_level
109
+ end
110
+
111
+ end
112
+
113
+ # Reports on which groups have which permissions
114
+ # @return Hash in format {group_name => group_permissions, group_name => group_permissions}
115
+ def groups
116
+ return quick_search_by_type(:group)
117
+ end
118
+
119
+ # Reports on which groups have which permissions
120
+ # @return Hash in format {person_name => person_permissions, person_name => person_permissions}
121
+ def individuals
122
+ return quick_search_by_type(:person)
123
+ end
124
+
125
+ # Updates permissions for all of the persons and groups in a hash
126
+ # @param params ex. {"group"=>{"group1"=>"discover","group2"=>"edit"}, "person"=>{"person1"=>"read","person2"=>"discover"}}
127
+ # Currently restricts actor type to group or person. Any others will be ignored
128
+ def update_permissions(params)
129
+ params.fetch("group", {}).each_pair {|group_id, access_level| self.permissions({"group"=>group_id}, access_level)}
130
+ params.fetch("person", {}).each_pair {|group_id, access_level| self.permissions({"person"=>group_id}, access_level)}
131
+ end
132
+
133
+ # @param [Symbol] type (either :group or :person)
134
+ # @return
135
+ # This method limits the response to known access levels. Probably runs a bit faster than .permissions().
136
+ def quick_search_by_type(type)
137
+ result = {}
138
+ [{:discover_access=>"discover"},{:read_access=>"read"},{:edit_access=>"edit"}].each do |access_levels_hash|
139
+ access_level = access_levels_hash.keys.first
140
+ access_level_name = access_levels_hash.values.first
141
+ self.find_by_terms(*[access_level, type]).each do |entry|
142
+ result[entry.text] = access_level_name
143
+ end
144
+ end
145
+ return result
146
+ end
147
+
148
+ attr_reader :embargo_release_date
149
+ def embargo_release_date=(release_date)
150
+ release_date = release_date.to_s if release_date.is_a? Date
151
+ begin
152
+ Date.parse(release_date)
153
+ rescue
154
+ return "INVALID DATE"
155
+ end
156
+ self.update_values({[:embargo,:machine,:date]=>release_date})
157
+ end
158
+ def embargo_release_date(opts={})
159
+ embargo_release_date = self.find_by_terms(*[:embargo,:machine,:date]).first ? self.find_by_terms(*[:embargo,:machine,:date]).first.text : nil
160
+ if embargo_release_date.present? && opts[:format] && opts[:format] == :solr_date
161
+ embargo_release_date << "T23:59:59Z"
162
+ end
163
+ embargo_release_date
164
+ end
165
+ def under_embargo?
166
+ (embargo_release_date && Date.today < embargo_release_date.to_date) ? true : false
167
+ end
168
+
169
+ def to_solr(solr_doc=Hash.new)
170
+ super(solr_doc)
171
+ ::Solrizer::Extractor.insert_solr_field_value(solr_doc, "embargo_release_date_dt", embargo_release_date(:format=>:solr_date)) if embargo_release_date
172
+ solr_doc
173
+ end
174
+
175
+
176
+
177
+
178
+
179
+ private
180
+ # Purge all access given group/person
181
+ def remove_all_permissions(selector)
182
+ return unless ng_xml
183
+ type = selector.keys.first.to_sym
184
+ actor = selector.values.first
185
+ xpath = self.class.terminology.xpath_for(:access, type, actor)
186
+ nodes_to_purge = self.find_by_terms(xpath)
187
+ nodes_to_purge.each {|node| node.remove}
188
+ end
189
+
190
+ end
191
+ end
192
+ end
@@ -0,0 +1,7 @@
1
+ module Hydra
2
+ module ModelMixins
3
+ extend ActiveSupport::Autoload
4
+ autoload :RightsMetadata
5
+ end
6
+ end
7
+
@@ -0,0 +1,357 @@
1
+ module Hydra
2
+ module ModelMixins
3
+ module RightsMetadata
4
+
5
+
6
+ ## Updates those permissions that are provided to it. Does not replace any permissions unless they are provided
7
+ # @example
8
+ # obj.permissions= [{:name=>"group1", :access=>"discover", :type=>'group'},
9
+ # {:name=>"group2", :access=>"discover", :type=>'group'}]
10
+ def permissions=(params)
11
+ perm_hash = {'person' => rightsMetadata.individuals, 'group'=> rightsMetadata.groups}
12
+
13
+ params.each do |row|
14
+ if row[:type] == 'user'
15
+ perm_hash['person'][row[:name]] = row[:access]
16
+ else
17
+ perm_hash['group'][row[:name]] = row[:access]
18
+ end
19
+ end
20
+
21
+ rightsMetadata.update_permissions(perm_hash)
22
+ end
23
+
24
+
25
+ ## Returns a list with all the permissions on the object.
26
+ # @example
27
+ # [{:name=>"group1", :access=>"discover", :type=>'group'},
28
+ # {:name=>"group2", :access=>"discover", :type=>'group'},
29
+ # {:name=>"user2", :access=>"read", :type=>'user'},
30
+ # {:name=>"user1", :access=>"edit", :type=>'user'},
31
+ # {:name=>"user3", :access=>"read", :type=>'user'}]
32
+ def permissions
33
+ (rightsMetadata.groups.map {|x| {:type=>'group', :access=>x[1], :name=>x[0] }} +
34
+ rightsMetadata.individuals.map {|x| {:type=>'user', :access=>x[1], :name=>x[0]}})
35
+
36
+ end
37
+
38
+ # Return a list of groups that have discover permission
39
+ def discover_groups
40
+ rightsMetadata.groups.map {|k, v| k if v == 'discover'}.compact
41
+ end
42
+
43
+ # Grant discover permissions to the groups specified. Revokes discover permission for all other groups.
44
+ # @param[Array] groups a list of group names
45
+ # @example
46
+ # r.discover_groups= ['one', 'two', 'three']
47
+ # r.discover_groups
48
+ # => ['one', 'two', 'three']
49
+ #
50
+ def discover_groups=(groups)
51
+ set_discover_groups(groups, discover_groups)
52
+ end
53
+
54
+ # Grant discover permissions to the groups specified. Revokes discover permission for all other groups.
55
+ # @param[String] groups a list of group names
56
+ # @example
57
+ # r.discover_groups_string= 'one, two, three'
58
+ # r.discover_groups
59
+ # => ['one', 'two', 'three']
60
+ #
61
+ def discover_groups_string=(groups)
62
+ self.discover_groups=groups.split(/[\s,]+/)
63
+ end
64
+
65
+ # Display the groups a comma delimeted string
66
+ def discover_groups_string
67
+ self.discover_groups.join(', ')
68
+ end
69
+
70
+ # Grant discover permissions to the groups specified. Revokes discover permission for
71
+ # any of the eligible_groups that are not in groups.
72
+ # This may be used when different users are responsible for setting different
73
+ # groups. Supply the groups the current user is responsible for as the
74
+ # 'eligible_groups'
75
+ # @param[Array] groups a list of groups
76
+ # @param[Array] eligible_groups the groups that are eligible to have their discover permssion revoked.
77
+ # @example
78
+ # r.discover_groups = ['one', 'two', 'three']
79
+ # r.discover_groups
80
+ # => ['one', 'two', 'three']
81
+ # r.set_discover_groups(['one'], ['three'])
82
+ # r.discover_groups
83
+ # => ['one', 'two'] ## 'two' was not eligible to be removed
84
+ #
85
+ def set_discover_groups(groups, eligible_groups)
86
+ set_entities(:discover, :group, groups, eligible_groups)
87
+ end
88
+
89
+ def discover_users
90
+ rightsMetadata.individuals.map {|k, v| k if v == 'discover'}.compact
91
+ end
92
+
93
+ # Grant discover permissions to the users specified. Revokes discover permission for all other users.
94
+ # @param[Array] users a list of usernames
95
+ # @example
96
+ # r.discover_users= ['one', 'two', 'three']
97
+ # r.discover_users
98
+ # => ['one', 'two', 'three']
99
+ #
100
+ def discover_users=(users)
101
+ set_discover_users(users, discover_users)
102
+ end
103
+
104
+ # Grant discover permissions to the groups specified. Revokes discover permission for all other users.
105
+ # @param[String] users a list of usernames
106
+ # @example
107
+ # r.discover_users_string= 'one, two, three'
108
+ # r.discover_users
109
+ # => ['one', 'two', 'three']
110
+ #
111
+ def discover_users_string=(users)
112
+ self.discover_users=users.split(/[\s,]+/)
113
+ end
114
+
115
+ # Display the users as a comma delimeted string
116
+ def discover_users_string
117
+ self.discover_users.join(', ')
118
+ end
119
+
120
+ # Grant discover permissions to the users specified. Revokes discover permission for
121
+ # any of the eligible_users that are not in users.
122
+ # This may be used when different users are responsible for setting different
123
+ # users. Supply the users the current user is responsible for as the
124
+ # 'eligible_users'
125
+ # @param[Array] users a list of users
126
+ # @param[Array] eligible_users the users that are eligible to have their discover permssion revoked.
127
+ # @example
128
+ # r.discover_users = ['one', 'two', 'three']
129
+ # r.discover_users
130
+ # => ['one', 'two', 'three']
131
+ # r.set_discover_users(['one'], ['three'])
132
+ # r.discover_users
133
+ # => ['one', 'two'] ## 'two' was not eligible to be removed
134
+ #
135
+ def set_discover_users(users, eligible_users)
136
+ set_entities(:discover, :person, users, eligible_users)
137
+ end
138
+
139
+ # Return a list of groups that have discover permission
140
+ def read_groups
141
+ rightsMetadata.groups.map {|k, v| k if v == 'read'}.compact
142
+ end
143
+
144
+ # Grant read permissions to the groups specified. Revokes read permission for all other groups.
145
+ # @param[Array] groups a list of group names
146
+ # @example
147
+ # r.read_groups= ['one', 'two', 'three']
148
+ # r.read_groups
149
+ # => ['one', 'two', 'three']
150
+ #
151
+ def read_groups=(groups)
152
+ set_read_groups(groups, read_groups)
153
+ end
154
+
155
+ # Grant read permissions to the groups specified. Revokes read permission for all other groups.
156
+ # @param[String] groups a list of group names
157
+ # @example
158
+ # r.read_groups_string= 'one, two, three'
159
+ # r.read_groups
160
+ # => ['one', 'two', 'three']
161
+ #
162
+ def read_groups_string=(groups)
163
+ self.read_groups=groups.split(/[\s,]+/)
164
+ end
165
+
166
+ # Display the groups a comma delimeted string
167
+ def read_groups_string
168
+ self.read_groups.join(', ')
169
+ end
170
+
171
+ # Grant read permissions to the groups specified. Revokes read permission for
172
+ # any of the eligible_groups that are not in groups.
173
+ # This may be used when different users are responsible for setting different
174
+ # groups. Supply the groups the current user is responsible for as the
175
+ # 'eligible_groups'
176
+ # @param[Array] groups a list of groups
177
+ # @param[Array] eligible_groups the groups that are eligible to have their read permssion revoked.
178
+ # @example
179
+ # r.read_groups = ['one', 'two', 'three']
180
+ # r.read_groups
181
+ # => ['one', 'two', 'three']
182
+ # r.set_read_groups(['one'], ['three'])
183
+ # r.read_groups
184
+ # => ['one', 'two'] ## 'two' was not eligible to be removed
185
+ #
186
+ def set_read_groups(groups, eligible_groups)
187
+ set_entities(:read, :group, groups, eligible_groups)
188
+ end
189
+
190
+ def read_users
191
+ rightsMetadata.individuals.map {|k, v| k if v == 'read'}.compact
192
+ end
193
+
194
+ # Grant read permissions to the users specified. Revokes read permission for all other users.
195
+ # @param[Array] users a list of usernames
196
+ # @example
197
+ # r.read_users= ['one', 'two', 'three']
198
+ # r.read_users
199
+ # => ['one', 'two', 'three']
200
+ #
201
+ def read_users=(users)
202
+ set_read_users(users, read_users)
203
+ end
204
+
205
+ # Grant read permissions to the groups specified. Revokes read permission for all other users.
206
+ # @param[String] users a list of usernames
207
+ # @example
208
+ # r.read_users_string= 'one, two, three'
209
+ # r.read_users
210
+ # => ['one', 'two', 'three']
211
+ #
212
+ def read_users_string=(users)
213
+ self.read_users=users.split(/[\s,]+/)
214
+ end
215
+
216
+ # Display the users as a comma delimeted string
217
+ def read_users_string
218
+ self.read_users.join(', ')
219
+ end
220
+
221
+ # Grant read permissions to the users specified. Revokes read permission for
222
+ # any of the eligible_users that are not in users.
223
+ # This may be used when different users are responsible for setting different
224
+ # users. Supply the users the current user is responsible for as the
225
+ # 'eligible_users'
226
+ # @param[Array] users a list of users
227
+ # @param[Array] eligible_users the users that are eligible to have their read permssion revoked.
228
+ # @example
229
+ # r.read_users = ['one', 'two', 'three']
230
+ # r.read_users
231
+ # => ['one', 'two', 'three']
232
+ # r.set_read_users(['one'], ['three'])
233
+ # r.read_users
234
+ # => ['one', 'two'] ## 'two' was not eligible to be removed
235
+ #
236
+ def set_read_users(users, eligible_users)
237
+ set_entities(:read, :person, users, eligible_users)
238
+ end
239
+
240
+
241
+ # Return a list of groups that have edit permission
242
+ def edit_groups
243
+ rightsMetadata.groups.map {|k, v| k if v == 'edit'}.compact
244
+ end
245
+
246
+ # Grant edit permissions to the groups specified. Revokes edit permission for all other groups.
247
+ # @param[Array] groups a list of group names
248
+ # @example
249
+ # r.edit_groups= ['one', 'two', 'three']
250
+ # r.edit_groups
251
+ # => ['one', 'two', 'three']
252
+ #
253
+ def edit_groups=(groups)
254
+ set_edit_groups(groups, edit_groups)
255
+ end
256
+
257
+ # Grant edit permissions to the groups specified. Revokes edit permission for all other groups.
258
+ # @param[String] groups a list of group names
259
+ # @example
260
+ # r.edit_groups_string= 'one, two, three'
261
+ # r.edit_groups
262
+ # => ['one', 'two', 'three']
263
+ #
264
+ def edit_groups_string=(groups)
265
+ self.edit_groups=groups.split(/[\s,]+/)
266
+ end
267
+
268
+ # Display the groups a comma delimeted string
269
+ def edit_groups_string
270
+ self.edit_groups.join(', ')
271
+ end
272
+
273
+ # Grant edit permissions to the groups specified. Revokes edit permission for
274
+ # any of the eligible_groups that are not in groups.
275
+ # This may be used when different users are responsible for setting different
276
+ # groups. Supply the groups the current user is responsible for as the
277
+ # 'eligible_groups'
278
+ # @param[Array] groups a list of groups
279
+ # @param[Array] eligible_groups the groups that are eligible to have their edit permssion revoked.
280
+ # @example
281
+ # r.edit_groups = ['one', 'two', 'three']
282
+ # r.edit_groups
283
+ # => ['one', 'two', 'three']
284
+ # r.set_edit_groups(['one'], ['three'])
285
+ # r.edit_groups
286
+ # => ['one', 'two'] ## 'two' was not eligible to be removed
287
+ #
288
+ def set_edit_groups(groups, eligible_groups)
289
+ set_entities(:edit, :group, groups, eligible_groups)
290
+ end
291
+
292
+ def edit_users
293
+ rightsMetadata.individuals.map {|k, v| k if v == 'edit'}.compact
294
+ end
295
+
296
+ # Grant edit permissions to the groups specified. Revokes edit permission for all other groups.
297
+ # @param[Array] users a list of usernames
298
+ # @example
299
+ # r.edit_users= ['one', 'two', 'three']
300
+ # r.edit_users
301
+ # => ['one', 'two', 'three']
302
+ #
303
+ def edit_users=(users)
304
+ set_edit_users(users, edit_users)
305
+ end
306
+
307
+ # Grant edit permissions to the users specified. Revokes edit permission for
308
+ # any of the eligible_users that are not in users.
309
+ # This may be used when different users are responsible for setting different
310
+ # users. Supply the users the current user is responsible for as the
311
+ # 'eligible_users'
312
+ # @param[Array] users a list of users
313
+ # @param[Array] eligible_users the users that are eligible to have their edit permssion revoked.
314
+ # @example
315
+ # r.edit_users = ['one', 'two', 'three']
316
+ # r.edit_users
317
+ # => ['one', 'two', 'three']
318
+ # r.set_edit_users(['one'], ['three'])
319
+ # r.edit_users
320
+ # => ['one', 'two'] ## 'two' was not eligible to be removed
321
+ #
322
+ def set_edit_users(users, eligible_users)
323
+ set_entities(:edit, :person, users, eligible_users)
324
+ end
325
+
326
+
327
+ private
328
+
329
+ # @param permission either :discover, :read or :edit
330
+ # @param type either :person or :group
331
+ # @param values Values to set
332
+ # @param changeable Values we are allowed to change
333
+ def set_entities(permission, type, values, changeable)
334
+ g = preserved(type, permission)
335
+ (changeable - values).each do |entity|
336
+ #Strip permissions from users not provided
337
+ g[entity] = 'none'
338
+ end
339
+ values.each { |name| g[name] = permission.to_s}
340
+ rightsMetadata.update_permissions(type.to_s=>g)
341
+ end
342
+
343
+ ## Get those permissions we don't want to change
344
+ def preserved(type, permission)
345
+ case permission
346
+ when :edit
347
+ g = {}
348
+ when :read
349
+ Hash[rightsMetadata.quick_search_by_type(type).select {|k, v| v == 'edit'}]
350
+ when :discover
351
+ Hash[rightsMetadata.quick_search_by_type(type).select {|k, v| v == 'discover'}]
352
+ end
353
+ end
354
+
355
+ end
356
+ end
357
+ end