hydra-access-controls 0.0.1

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.
@@ -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