acts_as_joinable 1.1.0 → 1.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/app/models/default_permission_set.rb +2 -0
- data/app/models/membership.rb +1 -0
- data/lib/acts_as_joinable/version.rb +3 -0
- data/lib/acts_as_joinable.rb +0 -3
- data/lib/joinable/acts_as_joinable.rb +66 -68
- data/lib/joinable/acts_as_joinable_component.rb +29 -33
- data/lib/joinable/acts_as_permissable.rb +19 -4
- data/lib/joinable/feedable_extensions.rb +3 -1
- data/lib/joinable/permissions_attribute_wrapper.rb +31 -31
- data/lib/tasks/acts_as_joinable_tasks.rake +4 -0
- metadata +41 -7
@@ -2,6 +2,7 @@ class DefaultPermissionSet < ActiveRecord::Base
|
|
2
2
|
include Joinable::PermissionsAttributeWrapper
|
3
3
|
|
4
4
|
belongs_to :joinable, :polymorphic => true
|
5
|
+
has_many :permission_links, lambda { where("#{PermissionLink.table_name}.joinable_type = #{table_name}.joinable_type") }, :primary_key => :joinable_id, :foreign_key => :joinable_id
|
5
6
|
|
6
7
|
after_update :raise_existing_member_permissions
|
7
8
|
|
@@ -15,6 +16,7 @@ class DefaultPermissionSet < ActiveRecord::Base
|
|
15
16
|
end
|
16
17
|
end
|
17
18
|
|
19
|
+
# Easy way to choose basic permission sets
|
18
20
|
def access_model=(model)
|
19
21
|
case model.to_s
|
20
22
|
when 'open'
|
data/app/models/membership.rb
CHANGED
@@ -3,6 +3,7 @@ class Membership < ActiveRecord::Base
|
|
3
3
|
|
4
4
|
belongs_to :joinable, :polymorphic => true
|
5
5
|
belongs_to :user
|
6
|
+
has_many :permission_links, lambda { where("#{PermissionLink.table_name}.joinable_type = #{table_name}.joinable_type") }, :primary_key => :joinable_id, :foreign_key => :joinable_id
|
6
7
|
|
7
8
|
before_save :prevent_locked_permission_changes, :normalize_owner_permissions
|
8
9
|
|
data/lib/acts_as_joinable.rb
CHANGED
@@ -8,20 +8,20 @@ module Joinable #:nodoc:
|
|
8
8
|
# These unpacked permissions are put into an array with the singular permissions (eg. find)
|
9
9
|
# and stored in a *permissions* class variable.
|
10
10
|
#
|
11
|
-
# In addition, The grouped permissions are stored in a separate *
|
11
|
+
# In addition, The grouped permissions are stored in a separate *component_permissions_hash* class variable.
|
12
12
|
#
|
13
13
|
# NOTE: The permissions are passed in-order because in the view we expect to find certain permission patterns.
|
14
14
|
# eg. the simple project permission level is determined by looking for a string of permissions that span
|
15
15
|
# several components, (labels, writeboards, files, etc...).
|
16
16
|
# TODO: Remove the aforementioned order dependency
|
17
17
|
def acts_as_joinable(options = {})
|
18
|
-
extend ClassMethods
|
19
|
-
include InstanceMethods
|
18
|
+
extend ClassMethods
|
19
|
+
include InstanceMethods
|
20
20
|
|
21
21
|
options.assert_valid_keys :component_permissions
|
22
|
-
|
22
|
+
self.component_permissions_hash = options[:component_permissions]
|
23
23
|
|
24
|
-
|
24
|
+
self.permissions = [:find, :view]
|
25
25
|
add_flattened_component_permissions(options[:component_permissions])
|
26
26
|
self.permissions += [:manage, :own]
|
27
27
|
end
|
@@ -34,12 +34,10 @@ module Joinable #:nodoc:
|
|
34
34
|
# eg. {:labels => [:view, :apply, :remove, :create, :delete]} becomes
|
35
35
|
# [:view_labels, :apply_labels, :remove_labels, :create_labels, :delete_labels]
|
36
36
|
# and is added to self.permissions
|
37
|
-
def add_flattened_component_permissions(
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
end
|
42
|
-
end
|
37
|
+
def add_flattened_component_permissions(component_permissions_hash)
|
38
|
+
component_permissions_hash.each do |component_name, component_permissions|
|
39
|
+
component_permissions.each { |component_permission| self.permissions << "#{component_permission}_#{component_name}".to_sym }
|
40
|
+
end
|
43
41
|
end
|
44
42
|
end
|
45
43
|
|
@@ -47,38 +45,28 @@ module Joinable #:nodoc:
|
|
47
45
|
include Joinable::ActsAsPermissable::ClassMethods
|
48
46
|
|
49
47
|
def self.extended(base)
|
50
|
-
base.
|
51
|
-
|
52
|
-
base.has_many :membership_invitations, :as => :joinable, :dependent => :destroy, :before_add => :add_initiator
|
53
|
-
base.has_many :membership_requests, :as => :joinable, :dependent => :destroy
|
54
|
-
base.has_many :memberships, :as => :joinable, :dependent => :destroy, :order => "id ASC", :before_remove => :add_initiator
|
55
|
-
|
56
|
-
base.has_many :invitees, :class_name => "User", :through => :membership_invitations, :source => :user
|
57
|
-
base.has_many :requestees, :class_name => "User", :through => :membership_requests, :source => :user
|
58
|
-
base.has_many :members, :class_name => "User", :through => :memberships, :source => :user
|
59
|
-
|
60
|
-
base.has_many :non_owner_memberships, :as => :joinable, :class_name => 'Membership', :conditions => "permissions NOT LIKE '%own%'"
|
61
|
-
base.has_one :owner_membership, :as => :joinable, :class_name => 'Membership', :conditions => "permissions LIKE '%own%'"
|
62
|
-
|
63
|
-
base.has_many :permission_links, :as => :joinable, :dependent => :destroy
|
48
|
+
base.class_eval do
|
49
|
+
cattr_accessor :permissions, :component_permissions_hash
|
64
50
|
|
65
|
-
|
51
|
+
has_many :membership_invitations, :as => :joinable, :dependent => :destroy, :before_add => :add_initiator
|
52
|
+
has_many :membership_requests, :as => :joinable, :dependent => :destroy
|
53
|
+
has_many :memberships, lambda { order :id }, :as => :joinable, :dependent => :destroy, :before_remove => :add_initiator
|
66
54
|
|
67
|
-
|
55
|
+
has_many :invitees, :class_name => "User", :through => :membership_invitations, :source => :user
|
56
|
+
has_many :requestees, :class_name => "User", :through => :membership_requests, :source => :user
|
57
|
+
has_many :members, :class_name => "User", :through => :memberships, :source => :user
|
68
58
|
|
69
|
-
|
70
|
-
|
71
|
-
|
59
|
+
has_many :permission_links, :as => :joinable, :dependent => :destroy
|
60
|
+
has_one :default_permission_set, :as => :joinable, :dependent => :destroy
|
61
|
+
|
62
|
+
scope :with_member, lambda {|user| joins(:memberships).where(:memberships => {:user_id => user}).order("memberships.created_at DESC") }
|
72
63
|
|
73
|
-
|
64
|
+
accepts_nested_attributes_for :default_permission_set
|
65
|
+
accepts_nested_attributes_for :membership_invitations, :allow_destroy => true
|
66
|
+
accepts_nested_attributes_for :memberships, :allow_destroy => true, :reject_if => proc { |attributes| attributes['locked'] == 'true' }
|
74
67
|
|
75
|
-
|
76
|
-
scope :with_member, lambda {|user| joins(:memberships).where(:memberships => {:user_id => (user.is_a?(User) ? user.id : user)}).order("memberships.created_at DESC NULLS LAST") }
|
68
|
+
after_create :add_owner_membership
|
77
69
|
end
|
78
|
-
|
79
|
-
base.accepts_nested_attributes_for :default_permission_set
|
80
|
-
base.accepts_nested_attributes_for :membership_invitations, :allow_destroy => true
|
81
|
-
base.accepts_nested_attributes_for :memberships, :allow_destroy => true, :reject_if => proc { |attributes| attributes['locked'] == 'true' }
|
82
70
|
end
|
83
71
|
|
84
72
|
def permissions_string
|
@@ -141,36 +129,35 @@ module Joinable #:nodoc:
|
|
141
129
|
user_id = user.id
|
142
130
|
end
|
143
131
|
|
144
|
-
|
145
|
-
joinable_id = options[:id_column] || table_name + ".id"
|
132
|
+
joinable_id = options[:id_column] || "#{table_name}.id"
|
146
133
|
|
147
134
|
if permission == :find
|
148
|
-
"#{membership_permission_exists_sql(user_id,
|
135
|
+
"#{membership_permission_exists_sql(user_id, joinable_id, 'find')} OR #{membership_invitation_permission_exists_sql(user_id, joinable_id, 'find')} OR #{default_permission_set_permission_exists_sql(joinable_id, 'find')}"
|
149
136
|
elsif permission.to_s.starts_with?('view')
|
150
|
-
"#{membership_permission_exists_sql(user_id,
|
137
|
+
"#{membership_permission_exists_sql(user_id, joinable_id, permission)} OR #{default_permission_set_permission_exists_sql(joinable_id, permission)}"
|
151
138
|
elsif permission == :join
|
152
|
-
"#{membership_invitation_permission_exists_sql(user_id,
|
139
|
+
"#{membership_invitation_permission_exists_sql(user_id, joinable_id, 'view')} OR #{default_permission_set_permission_exists_sql(joinable_id, 'view')}"
|
153
140
|
elsif permission.to_s.starts_with?('join_and_')
|
154
|
-
default_permission_set_permission_exists_sql(
|
141
|
+
default_permission_set_permission_exists_sql(joinable_id, permission.to_s.gsub('join_and_', ''))
|
155
142
|
elsif permission == :collaborate
|
156
|
-
"EXISTS (SELECT id FROM memberships WHERE memberships.joinable_type = '#{
|
143
|
+
"EXISTS (SELECT id FROM memberships WHERE memberships.joinable_type = '#{self.name}' AND memberships.joinable_id = #{joinable_id} AND memberships.user_id = #{user_id} AND memberships.permissions && '{#{(collaborator_permissions - viewer_permissions).join(",")}}')"
|
157
144
|
else
|
158
|
-
membership_permission_exists_sql(user_id,
|
145
|
+
membership_permission_exists_sql(user_id, joinable_id, permission)
|
159
146
|
end
|
160
147
|
end
|
161
148
|
|
162
149
|
private
|
163
150
|
|
164
|
-
def membership_permission_exists_sql(user_id,
|
165
|
-
"EXISTS (SELECT id FROM memberships WHERE memberships.joinable_type = '#{
|
151
|
+
def membership_permission_exists_sql(user_id, joinable_id, permission)
|
152
|
+
"EXISTS (SELECT id FROM memberships WHERE memberships.joinable_type = '#{self.name}' AND memberships.joinable_id = #{joinable_id} AND memberships.user_id = #{user_id} AND #{permission_sql_condition('memberships.permissions', permission)})"
|
166
153
|
end
|
167
154
|
|
168
|
-
def membership_invitation_permission_exists_sql(user_id,
|
169
|
-
"EXISTS (SELECT id FROM membership_invitations WHERE membership_invitations.joinable_type = '#{
|
155
|
+
def membership_invitation_permission_exists_sql(user_id, joinable_id, permission)
|
156
|
+
"EXISTS (SELECT id FROM membership_invitations WHERE membership_invitations.joinable_type = '#{self.name}' AND membership_invitations.joinable_id = #{joinable_id} AND membership_invitations.user_id = #{user_id} AND #{permission_sql_condition('membership_invitations.permissions', permission)})"
|
170
157
|
end
|
171
158
|
|
172
|
-
def default_permission_set_permission_exists_sql(
|
173
|
-
"EXISTS (SELECT id FROM default_permission_sets WHERE default_permission_sets.joinable_type = '#{
|
159
|
+
def default_permission_set_permission_exists_sql(joinable_id, permission)
|
160
|
+
"EXISTS (SELECT id FROM default_permission_sets WHERE default_permission_sets.joinable_type = '#{self.name}' AND default_permission_sets.joinable_id = #{joinable_id} AND #{permission_sql_condition('default_permission_sets.permissions', permission)})"
|
174
161
|
end
|
175
162
|
end
|
176
163
|
|
@@ -241,28 +228,35 @@ module Joinable #:nodoc:
|
|
241
228
|
# user. This method also supports caching of a membership
|
242
229
|
# request in order to facilitate eager loading.
|
243
230
|
#NOTE: See :membership_request_for documentation for an in depth example of this type of behaviour
|
244
|
-
def membership_for(
|
231
|
+
def membership_for(user_id)
|
245
232
|
if cached_membership != nil
|
246
233
|
cached_membership
|
247
234
|
else
|
248
|
-
memberships.where(:user_id =>
|
235
|
+
memberships.where(:user_id => user_id).first
|
249
236
|
end
|
250
237
|
end
|
251
238
|
|
252
239
|
# Find out whether this Joinable has a membership for a certain user and return true, else false
|
253
|
-
def membership_for?(
|
254
|
-
!membership_for(
|
240
|
+
def membership_for?(user_id)
|
241
|
+
!membership_for(user_id).nil?
|
255
242
|
end
|
256
243
|
|
257
|
-
# Returns
|
258
|
-
def
|
259
|
-
memberships.maximum(:updated_at)
|
244
|
+
# Returns a unique cache key any time the memberships were updated for this joinable
|
245
|
+
def memberships_cache_key
|
246
|
+
"#{memberships.size}_#{memberships.maximum(:updated_at).to_f}"
|
260
247
|
end
|
261
248
|
|
262
|
-
|
249
|
+
# Convenience method for reading or writing the default permission set's access_model
|
250
|
+
delegate :access_model, 'access_model=', :to => :default_permission_set
|
251
|
+
|
252
|
+
# Convenience method for reading the default permission set's access_model
|
253
|
+
def default_permissions
|
254
|
+
self.default_permission_set.permissions
|
255
|
+
end
|
263
256
|
|
264
|
-
|
265
|
-
|
257
|
+
# Convenience method for writing the default permission set's access_model
|
258
|
+
def default_permissions=(permissions)
|
259
|
+
self.default_permission_set.permissions = permissions
|
266
260
|
end
|
267
261
|
|
268
262
|
# Returns true or false depending on whether or not the user has the specified permission for this object.
|
@@ -287,8 +281,8 @@ module Joinable #:nodoc:
|
|
287
281
|
|
288
282
|
cache_path = "permissions/#{self.class.table_name}/#{self.id}/user_#{user.id}_#{key}"
|
289
283
|
|
290
|
-
if defined?(
|
291
|
-
permissions =
|
284
|
+
if defined?(Rails.cache)
|
285
|
+
permissions = Rails.cache.read(cache_path)
|
292
286
|
if permissions && (value = permissions[permission_name]) != nil
|
293
287
|
return value
|
294
288
|
end
|
@@ -297,18 +291,23 @@ module Joinable #:nodoc:
|
|
297
291
|
# The permission isn't cached yet, so cache it
|
298
292
|
value = self.class.with_permission(user, permission_name).exists?(self.id)
|
299
293
|
|
300
|
-
if defined?(
|
294
|
+
if defined?(Rails.cache)
|
301
295
|
if permissions
|
302
296
|
permissions = permissions.dup
|
303
297
|
permissions[permission_name] = value
|
304
298
|
else
|
305
299
|
permissions = {permission_name => value}
|
306
300
|
end
|
307
|
-
|
301
|
+
Rails.cache.write(cache_path, permissions)
|
308
302
|
end
|
309
303
|
return value
|
310
304
|
end
|
311
305
|
|
306
|
+
# Ensure the joinable has a set of default permissions (an empty set unless one already exists)
|
307
|
+
def default_permission_set
|
308
|
+
super || self.build_default_permission_set
|
309
|
+
end
|
310
|
+
|
312
311
|
private
|
313
312
|
|
314
313
|
# Adds an initiator to a membership or invitation to possibly use in feed generation
|
@@ -318,9 +317,8 @@ module Joinable #:nodoc:
|
|
318
317
|
|
319
318
|
# Adds an permission entry with full access to the object by the user associated with the object if one does not already exist
|
320
319
|
def add_owner_membership
|
321
|
-
Membership.
|
320
|
+
Membership.where(:joinable => self, :user => user).first_or_create!(:permissions => self.class.permissions_string)
|
322
321
|
end
|
323
322
|
end
|
324
323
|
end
|
325
|
-
end
|
326
|
-
|
324
|
+
end
|
@@ -46,10 +46,6 @@ module Joinable #:nodoc:
|
|
46
46
|
def self.extended(base)
|
47
47
|
base.has_one :permission_link, :as => :component, :dependent => :destroy
|
48
48
|
base.after_create :find_joinable_and_create_permission_link
|
49
|
-
|
50
|
-
base.class_eval do
|
51
|
-
scope :with_permission, lambda { |user, permission| select("#{table_name}.*").where(with_permission_sql(user, permission)) }
|
52
|
-
end
|
53
49
|
end
|
54
50
|
|
55
51
|
# Returns the SQL necessary to find all components for which there is no associated joinable or
|
@@ -72,49 +68,50 @@ module Joinable #:nodoc:
|
|
72
68
|
user_id = user.id
|
73
69
|
end
|
74
70
|
|
75
|
-
|
76
|
-
component_id = options[:id_column] || table_name + ".id"
|
71
|
+
component_id_column = options[:id_column] || "#{table_name}.id"
|
77
72
|
|
78
73
|
permission_without_join_and_prefix = permission.gsub('join_and_', '')
|
79
|
-
|
74
|
+
permission_or_column = permission_without_join_and_prefix == 'view' ? "permission_links.component_view_permission" : "'#{permission_without_join_and_prefix}'"
|
80
75
|
|
81
76
|
if permission.starts_with?('view')
|
82
|
-
"#{no_inherited_permissions_exist_sql(
|
77
|
+
"#{no_inherited_permissions_exist_sql(component_id_column)} OR #{membership_permission_exists_sql(user_id, component_id_column, permission_or_column)} OR #{default_permission_set_permission_exists_sql(component_id_column, permission_or_column)}"
|
83
78
|
elsif permission.starts_with?('join_and_')
|
84
|
-
default_permission_set_permission_exists_sql(
|
79
|
+
default_permission_set_permission_exists_sql(component_id_column, permission_or_column)
|
85
80
|
else
|
86
|
-
"#{no_inherited_permissions_exist_sql(
|
81
|
+
"#{no_inherited_permissions_exist_sql(component_id_column)} OR #{membership_permission_exists_sql(user_id, component_id_column, permission_or_column)}"
|
87
82
|
end
|
88
83
|
end
|
89
84
|
|
90
85
|
private
|
91
86
|
|
92
87
|
# All components that don't have a permission link to a joinable
|
93
|
-
def no_inherited_permissions_exist_sql(
|
94
|
-
|
88
|
+
def no_inherited_permissions_exist_sql(component_id_column)
|
89
|
+
permission_links_for_joinable = PermissionLink.where(:component_type => self.name).where("permission_links.component_id = #{component_id_column}")
|
90
|
+
|
91
|
+
return "NOT EXISTS (#{ permission_links_for_joinable.to_sql })"
|
95
92
|
end
|
96
93
|
|
97
94
|
# All components that have an associated membership with a specific permission
|
98
95
|
#
|
99
96
|
# The view permission requires special handling because it may be customized in the permission_link.
|
100
97
|
# For more information see the *recurse_to_inherit_custom_view_permission* method.
|
101
|
-
def membership_permission_exists_sql(user_id,
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
98
|
+
def membership_permission_exists_sql(user_id, component_id_column, permission_or_column)
|
99
|
+
memberships_allowing_permission = Membership.joins(:permission_links)
|
100
|
+
.where(:user_id => user_id)
|
101
|
+
.where("permission_links.component_type" => self.name)
|
102
|
+
.where("permission_links.component_id = #{component_id_column}")
|
103
|
+
.where(permission_sql_condition('memberships.permissions', permission_or_column, :raw => true))
|
104
|
+
|
105
|
+
return "EXISTS (#{ memberships_allowing_permission.to_sql })"
|
109
106
|
end
|
110
107
|
|
111
|
-
def default_permission_set_permission_exists_sql(
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
108
|
+
def default_permission_set_permission_exists_sql(component_id_column, permission_or_column)
|
109
|
+
sets_allowing_permission = DefaultPermissionSet.joins(:permission_links)
|
110
|
+
.where("permission_links.component_type" => self.name)
|
111
|
+
.where("permission_links.component_id = #{component_id_column}")
|
112
|
+
.where(permission_sql_condition('default_permission_sets.permissions', permission_or_column, :raw => true))
|
113
|
+
|
114
|
+
return "EXISTS (#{ sets_allowing_permission.to_sql })"
|
118
115
|
end
|
119
116
|
end
|
120
117
|
|
@@ -130,11 +127,9 @@ module Joinable #:nodoc:
|
|
130
127
|
# Useful for outputting information to the user while they
|
131
128
|
# are creating a new component.
|
132
129
|
def who_will_be_able_to_view?
|
133
|
-
User.
|
134
|
-
|
135
|
-
|
136
|
-
AND memberships.joinable_id = #{joinable.id}
|
137
|
-
AND #{self.class.permission_sql_condition('memberships.permissions', recurse_to_inherit_custom_view_permission)}")
|
130
|
+
User.joins(:memberships)
|
131
|
+
.where(:memberships => {:joinable => joinable})
|
132
|
+
.where(permission_sql_condition('memberships.permissions', recurse_to_inherit_custom_view_permission))
|
138
133
|
end
|
139
134
|
|
140
135
|
def check_permission(user, permission)
|
@@ -196,6 +191,7 @@ module Joinable #:nodoc:
|
|
196
191
|
end
|
197
192
|
attr_writer :view_permission
|
198
193
|
|
194
|
+
private
|
199
195
|
|
200
196
|
# Recurse up the tree to see if any of the intervening joinable_components have a customized view permission
|
201
197
|
# In that case, inherit that customized view permission. This allows searches of the form
|
@@ -208,7 +204,7 @@ module Joinable #:nodoc:
|
|
208
204
|
if parent.acts_like?(:joinable) || self.view_permission
|
209
205
|
return self.view_permission || :view
|
210
206
|
elsif parent.acts_like?(:joinable_component)
|
211
|
-
return parent.recurse_to_inherit_custom_view_permission
|
207
|
+
return parent.send(:recurse_to_inherit_custom_view_permission)
|
212
208
|
else
|
213
209
|
return nil
|
214
210
|
end
|
@@ -10,9 +10,22 @@ module Joinable #:nodoc:
|
|
10
10
|
return record
|
11
11
|
end
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
# Returns all records where the given user has the given permission
|
14
|
+
def with_permission(user, permission)
|
15
|
+
where(with_permission_sql(user, permission))
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns an SQL fragment for a WHERE condition that evaluates to true if the user has the given permission
|
19
|
+
# For use when asking
|
20
|
+
def with_permission_sql(user, permission, options = {})
|
21
|
+
raise NotImplementedError
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns an SQL fragment for a WHERE condition that checks the given column for the given permission
|
25
|
+
def permission_sql_condition(column, permission, options = {})
|
26
|
+
permission = "'#{permission}'" unless options[:raw]
|
27
|
+
"#{permission} = ANY(#{column})"
|
28
|
+
end
|
16
29
|
end
|
17
30
|
|
18
31
|
module InstanceMethods
|
@@ -22,8 +35,10 @@ module Joinable #:nodoc:
|
|
22
35
|
|
23
36
|
# Returns a list of users who either do or do not have the specified permission.
|
24
37
|
def who_can?(permission)
|
25
|
-
User.
|
38
|
+
User.where(with_permission_sql("#{User.table_name}.id", permission, :id_column => id))
|
26
39
|
end
|
40
|
+
|
41
|
+
delegate :with_permission_sql, :permission_sql_condition, :to => 'self.class'
|
27
42
|
end
|
28
43
|
end
|
29
44
|
end
|
@@ -2,12 +2,14 @@ module FeedableExtensions
|
|
2
2
|
def self.add
|
3
3
|
Feed.class_eval do
|
4
4
|
# Filter feeds about public joinables that you haven't joined, unless the feed is actually about you
|
5
|
-
scope :
|
5
|
+
scope :not_from_unjoined, lambda {|joinable_type, user|
|
6
6
|
where("feeds.scoping_object_type IS NULL OR
|
7
7
|
feeds.scoping_object_type != '#{joinable_type}' OR
|
8
8
|
(feeds.feedable_type = 'User' AND feeds.feedable_id = #{user.id}) OR
|
9
9
|
EXISTS (SELECT * FROM memberships WHERE memberships.joinable_type = '#{joinable_type}' AND memberships.joinable_id = feeds.scoping_object_id AND memberships.user_id = ?)", user.id)
|
10
10
|
}
|
11
|
+
# Filter feeds about public things where the given action took place
|
12
|
+
scope :not_unscoped, lambda {|action| where('NOT (feeds.scoping_object_type IS NULL AND feeds.action = ?)', action) }
|
11
13
|
|
12
14
|
acts_as_joinable_component :parent => 'permission_inheritance_target', :polymorphic => true, :view_permission => lambda {|feed| :find if feed.feedable.acts_like?(:joinable) }
|
13
15
|
|
@@ -14,13 +14,13 @@ module Joinable #:nodoc:
|
|
14
14
|
|
15
15
|
# Returns an array of the permissions as symbols
|
16
16
|
def permissions
|
17
|
-
self[:permissions].collect(&:to_sym)
|
17
|
+
Array.wrap(self[:permissions]).collect(&:to_sym)
|
18
18
|
end
|
19
19
|
|
20
20
|
def permissions=(permissions)
|
21
21
|
case permissions
|
22
|
-
when String
|
23
|
-
self[:permissions] = permissions.split(' ')
|
22
|
+
when String, Symbol
|
23
|
+
self[:permissions] = permissions.to_s.split(' ')
|
24
24
|
when Array
|
25
25
|
self[:permissions] = permissions
|
26
26
|
else
|
@@ -98,6 +98,31 @@ module Joinable #:nodoc:
|
|
98
98
|
self.permissions += permissions_to_grant
|
99
99
|
end
|
100
100
|
|
101
|
+
# Adds readers for component permission groups and single permissions
|
102
|
+
#
|
103
|
+
# Used by advanced permission forms to determine how which options to select
|
104
|
+
# in the various fields. (eg. which option of f.select :labels_permissions to choose)
|
105
|
+
def method_missing(method_name, *args, &block)
|
106
|
+
# NOTE: As of Rails 4, respond_to? must be checked inside the case statement otherwise it breaks regular AR attribute accessors
|
107
|
+
case method_name.to_s
|
108
|
+
when /.+_permissions/
|
109
|
+
return component_permissions_reader(method_name) if respond_to?(:joinable_type) && joinable_type.present?
|
110
|
+
when /.+_permission/
|
111
|
+
return single_permission_reader(method_name) if respond_to?(:joinable_type) && joinable_type.present?
|
112
|
+
end
|
113
|
+
|
114
|
+
super
|
115
|
+
end
|
116
|
+
|
117
|
+
def respond_to?(method_name, include_private = false)
|
118
|
+
case method_name.to_s
|
119
|
+
when /.+_permissions?/
|
120
|
+
return true if respond_to?(:joinable_type) && joinable_type.present?
|
121
|
+
end
|
122
|
+
|
123
|
+
super
|
124
|
+
end
|
125
|
+
|
101
126
|
private
|
102
127
|
|
103
128
|
# Verifies that all the access levels are valid for the attached permissible
|
@@ -112,37 +137,12 @@ module Joinable #:nodoc:
|
|
112
137
|
self.permissions = permissions.uniq.sort_by { |permission| allowed_permissions.index(permission) }
|
113
138
|
end
|
114
139
|
|
115
|
-
# Adds readers for component permission groups and single permissions
|
116
|
-
#
|
117
|
-
# Used by advanced permission forms to determine how which options to select
|
118
|
-
# in the various fields. (eg. which option of f.select :labels_permissions to choose)
|
119
|
-
def method_missing(method_name, *args)
|
120
|
-
# add permission_for accessors and mutators
|
121
|
-
|
122
|
-
# NOTE: Don't mess with the method_name variable (e.g. change it to a string)
|
123
|
-
# since upstream methods might assume it is a symbol.
|
124
|
-
# NOTE: Ensure we enforce some characters before the '_permission' suffix because Rails 3 creates
|
125
|
-
if respond_to?(:joinable_type) && joinable_type.present?
|
126
|
-
if method_name.to_s =~ /.+_permissions/
|
127
|
-
return component_permissions_reader(method_name)
|
128
|
-
elsif method_name.to_s =~ /.+_permission/
|
129
|
-
return single_permission_reader(method_name)
|
130
|
-
else
|
131
|
-
super
|
132
|
-
end
|
133
|
-
else
|
134
|
-
super
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
140
|
# Get a string of all of the permissions the object has for a specific joinable component
|
139
141
|
# eg. labels_permissions # returns 'view_labels apply_labels remove_labels'
|
140
142
|
def component_permissions_reader(method_name)
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
return component_permissions.collect {|permission| "#{permission}_#{component_name}"}.select {|permission| has_permission?(permission)}.join(" ")
|
145
|
-
end
|
143
|
+
joinable_type.constantize.component_permissions_hash.each do |component_name, component_permissions|
|
144
|
+
if method_name.to_s == "#{component_name}_permissions"
|
145
|
+
return component_permissions.collect {|permission| "#{permission}_#{component_name}"}.select {|permission| has_permission?(permission)}.join(" ")
|
146
146
|
end
|
147
147
|
end
|
148
148
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acts_as_joinable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1
|
4
|
+
version: 1.3.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,16 +10,32 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2013-08-14 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
|
-
name:
|
16
|
+
name: pg
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - '>='
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '0'
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: rails
|
17
33
|
requirement: !ruby/object:Gem::Requirement
|
18
34
|
none: false
|
19
35
|
requirements:
|
20
36
|
- - ~>
|
21
37
|
- !ruby/object:Gem::Version
|
22
|
-
version: 0
|
38
|
+
version: '4.0'
|
23
39
|
type: :runtime
|
24
40
|
prerelease: false
|
25
41
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -27,7 +43,23 @@ dependencies:
|
|
27
43
|
requirements:
|
28
44
|
- - ~>
|
29
45
|
- !ruby/object:Gem::Version
|
30
|
-
version: 0
|
46
|
+
version: '4.0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: sqlite3
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
31
63
|
description: Adds access control to objects by giving them members, each with configurable
|
32
64
|
permissions.
|
33
65
|
email: technical@rrnpilot.org
|
@@ -40,6 +72,7 @@ files:
|
|
40
72
|
- app/models/membership_invitation.rb
|
41
73
|
- app/models/membership_request.rb
|
42
74
|
- app/models/permission_link.rb
|
75
|
+
- lib/acts_as_joinable/version.rb
|
43
76
|
- lib/acts_as_joinable.rb
|
44
77
|
- lib/joinable/acts_as_joinable.rb
|
45
78
|
- lib/joinable/acts_as_joinable_component.rb
|
@@ -47,6 +80,7 @@ files:
|
|
47
80
|
- lib/joinable/acts_as_permissable.rb
|
48
81
|
- lib/joinable/feedable_extensions.rb
|
49
82
|
- lib/joinable/permissions_attribute_wrapper.rb
|
83
|
+
- lib/tasks/acts_as_joinable_tasks.rake
|
50
84
|
- README.rdoc
|
51
85
|
homepage: http://github.com/rrn/acts_as_joinable
|
52
86
|
licenses: []
|
@@ -57,13 +91,13 @@ require_paths:
|
|
57
91
|
required_ruby_version: !ruby/object:Gem::Requirement
|
58
92
|
none: false
|
59
93
|
requirements:
|
60
|
-
- -
|
94
|
+
- - '>='
|
61
95
|
- !ruby/object:Gem::Version
|
62
96
|
version: '0'
|
63
97
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
98
|
none: false
|
65
99
|
requirements:
|
66
|
-
- -
|
100
|
+
- - '>='
|
67
101
|
- !ruby/object:Gem::Version
|
68
102
|
version: '0'
|
69
103
|
requirements: []
|