acts_as_joinable 1.1.0 → 1.3.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.
- 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: []
|