rapid 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +66 -0
- data/lib/rad/http_controller/acts_as/authenticated.rb +131 -0
- data/lib/rad/http_controller/acts_as/authenticated_master_domain.rb +119 -0
- data/lib/rad/http_controller/acts_as/authorized.rb +83 -0
- data/lib/rad/http_controller/acts_as/localized.rb +27 -0
- data/lib/rad/http_controller/acts_as/multitenant.rb +53 -0
- data/lib/rad/http_controller/helpers/service_mix_helper.rb +50 -0
- data/lib/rad/http_controller.rb +15 -0
- data/lib/rad/lib/text_utils.rb +334 -0
- data/lib/rad/locales/en.yml +80 -0
- data/lib/rad/locales/ru.yml +83 -0
- data/lib/rad/locales.rb +2 -0
- data/lib/rad/models/account.rb +88 -0
- data/lib/rad/models/default_permissions.yml +26 -0
- data/lib/rad/models/micelaneous.rb +1 -0
- data/lib/rad/models/role.rb +88 -0
- data/lib/rad/models/secure_token.rb +33 -0
- data/lib/rad/models/space.rb +184 -0
- data/lib/rad/models/user.rb +158 -0
- data/lib/rad/models.rb +41 -0
- data/lib/rad/mongo_mapper/acts_as/authenticated_by_open_id.rb +29 -0
- data/lib/rad/mongo_mapper/acts_as/authenticated_by_password.rb +120 -0
- data/lib/rad/mongo_mapper/acts_as/authorized.rb +197 -0
- data/lib/rad/mongo_mapper/acts_as/authorized_object.rb +171 -0
- data/lib/rad/mongo_mapper/multitenant.rb +34 -0
- data/lib/rad/mongo_mapper/rad_micelaneous.rb +43 -0
- data/lib/rad/mongo_mapper/space_keys.rb +62 -0
- data/lib/rad/mongo_mapper/text_processor.rb +47 -0
- data/lib/rad/mongo_mapper.rb +20 -0
- data/lib/rad/paperclip/callbacks.rb +40 -0
- data/lib/rad/paperclip/extensions.rb +64 -0
- data/lib/rad/paperclip/integration.rb +165 -0
- data/lib/rad/paperclip/mime.rb +5 -0
- data/lib/rad/paperclip/validations.rb +64 -0
- data/lib/rad/paperclip.rb +11 -0
- data/lib/rad/spec/controller.rb +51 -0
- data/lib/rad/spec/model/factories.rb +65 -0
- data/lib/rad/spec/model.rb +85 -0
- data/lib/rad/spec/rem_helper.rb +145 -0
- data/lib/rad/spec.rb +4 -0
- data/lib/rad/tasks/backup.rake +64 -0
- data/lib/rad/tasks/initialize.rake +35 -0
- data/lib/rad.rb +32 -0
- data/readme.md +3 -0
- data/spec/controller/authorization_spec.rb +146 -0
- data/spec/controller/helper.rb +14 -0
- data/spec/lib/helper.rb +7 -0
- data/spec/lib/text_utils_spec.rb +238 -0
- data/spec/models/authorization_spec.rb +93 -0
- data/spec/models/authorized_object_spec.rb +258 -0
- data/spec/models/file_audit_spec/100.txt +1 -0
- data/spec/models/file_audit_spec/302.txt +3 -0
- data/spec/models/file_audit_spec.rb +168 -0
- data/spec/models/helper.rb +11 -0
- data/spec/models/space_key_spec.rb +68 -0
- data/spec/models/user_spec.rb +80 -0
- data/spec/mongo_mapper/basic_spec.rb +41 -0
- data/spec/mongo_mapper/helper.rb +10 -0
- data/spec/spec.opts +4 -0
- metadata +138 -0
@@ -0,0 +1,197 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Plugins
|
3
|
+
module Authorized
|
4
|
+
ROLES = %w{admin manager member}
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def acts_as_authorized
|
8
|
+
key :global_admin, Boolean, :protected => true
|
9
|
+
key :admin_of_accounts, Array, :protected => true
|
10
|
+
# has_many :roles_containers, :class_name => 'RolesContainer', :protected => true
|
11
|
+
space_key :space_roles, Array
|
12
|
+
|
13
|
+
validate :validate_anonymous
|
14
|
+
validates_exclusion_of :name, :within => Role::PRESERVED_USER_NAMES, :if => lambda{|u| u.new_record?}
|
15
|
+
end
|
16
|
+
|
17
|
+
def anonymous
|
18
|
+
User.find_by_name 'anonymous'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module InstanceMethods
|
23
|
+
#
|
24
|
+
# Owner
|
25
|
+
#
|
26
|
+
def owner_name; anonymous? ? nil : name end
|
27
|
+
|
28
|
+
def owner? object
|
29
|
+
# object.should! :respond_to?, :owner_name
|
30
|
+
!object.blank? and !name.blank? and object.respond_to(:owner_name) == self.name
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# Roles
|
35
|
+
#
|
36
|
+
def anonymous?
|
37
|
+
name == 'anonymous'
|
38
|
+
end
|
39
|
+
|
40
|
+
def registered?
|
41
|
+
!anonymous?
|
42
|
+
end
|
43
|
+
|
44
|
+
def add_role role
|
45
|
+
role = role.to_s
|
46
|
+
Rad.multitenant_mode?.must_be.true
|
47
|
+
|
48
|
+
if role == 'admin'
|
49
|
+
account_id = Account.current.id
|
50
|
+
admin_of_accounts << account_id unless admin_of_accounts.include? account_id
|
51
|
+
else
|
52
|
+
roles = Role.denormalize_to_lower_roles [role]
|
53
|
+
self.space_roles = space_roles + [role] unless space_roles.include?(role)
|
54
|
+
end
|
55
|
+
clear_cache
|
56
|
+
roles
|
57
|
+
end
|
58
|
+
|
59
|
+
def remove_role role
|
60
|
+
role = role.to_s
|
61
|
+
Rad.multitenant_mode?.must_be.true
|
62
|
+
|
63
|
+
if role == 'admin'
|
64
|
+
admin_of_accounts.delete Account.current.id
|
65
|
+
else
|
66
|
+
roles = Role.denormalize_to_higher_roles [role]
|
67
|
+
self.space_roles = space_roles - roles
|
68
|
+
end
|
69
|
+
clear_cache
|
70
|
+
roles
|
71
|
+
end
|
72
|
+
|
73
|
+
def roles
|
74
|
+
unless roles = cache[:roles]
|
75
|
+
if Rad.multitenant_mode?
|
76
|
+
roles = space_roles.clone
|
77
|
+
roles << 'admin' if admin_of_accounts.include? Account.current.id
|
78
|
+
else
|
79
|
+
roles = []
|
80
|
+
end
|
81
|
+
|
82
|
+
roles << 'user'
|
83
|
+
|
84
|
+
if anonymous?
|
85
|
+
roles << 'anonymous'
|
86
|
+
else
|
87
|
+
roles << 'registered'
|
88
|
+
end
|
89
|
+
|
90
|
+
roles << "user:#{name}" unless name.blank?
|
91
|
+
|
92
|
+
roles << 'admin' if global_admin and !roles.include?('admin')
|
93
|
+
|
94
|
+
roles << 'manager' if roles.include?('admin') and !roles.include?('manager')
|
95
|
+
|
96
|
+
roles = Role.denormalize_to_lower_roles(roles)
|
97
|
+
|
98
|
+
roles = HandyRoles.new roles
|
99
|
+
|
100
|
+
cache[:roles] = roles
|
101
|
+
end
|
102
|
+
roles
|
103
|
+
end
|
104
|
+
|
105
|
+
def major_roles
|
106
|
+
cache[:major_roles] ||= Role.major_roles roles
|
107
|
+
end
|
108
|
+
|
109
|
+
def has_role? role
|
110
|
+
roles.include? role
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
#
|
115
|
+
# can?
|
116
|
+
#
|
117
|
+
def can? operation, object = nil
|
118
|
+
operation = operation.to_s
|
119
|
+
|
120
|
+
return true if has_role?(:admin)
|
121
|
+
|
122
|
+
custom_method = "able_#{operation}?"
|
123
|
+
return object.send custom_method, self if object.respond_to? custom_method
|
124
|
+
|
125
|
+
effective_space_permissions[operation] or (
|
126
|
+
owner?(object) and effective_space_permissions_as_owner[operation]
|
127
|
+
)
|
128
|
+
end
|
129
|
+
|
130
|
+
def can_view? object
|
131
|
+
can? :view, object
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
#
|
136
|
+
# Effective Permissions
|
137
|
+
#
|
138
|
+
def effective_space_permissions
|
139
|
+
unless effective_space_permissions = cache[:effective_space_permissions]
|
140
|
+
effective_space_permissions = calculate_effective_roles_for roles
|
141
|
+
cache[:effective_space_permissions] = effective_space_permissions
|
142
|
+
end
|
143
|
+
effective_space_permissions
|
144
|
+
end
|
145
|
+
|
146
|
+
def effective_space_permissions_as_owner
|
147
|
+
unless effective_space_permissions_as_owner = cache[:effective_space_permissions_as_owner]
|
148
|
+
effective_space_permissions_as_owner = calculate_effective_roles_for ['owner']
|
149
|
+
cache[:effective_space_permissions_as_owner] = effective_space_permissions_as_owner
|
150
|
+
end
|
151
|
+
effective_space_permissions_as_owner
|
152
|
+
end
|
153
|
+
|
154
|
+
protected
|
155
|
+
# def effective_space_roles
|
156
|
+
# ::Rails.should_be! :multitenant_mode
|
157
|
+
# unless roles = cache[:effective_space_roles]
|
158
|
+
# roles = space_roles.clone
|
159
|
+
# roles << 'admin' if admin_of_accounts.include? Account.current.id
|
160
|
+
# cache[:effective_space_roles] = roles
|
161
|
+
# end
|
162
|
+
# roles
|
163
|
+
# end
|
164
|
+
|
165
|
+
def validate_anonymous
|
166
|
+
if anonymous? and (global_admin or !space_roles.blank?)
|
167
|
+
errors.add :base, "Anonymous can't be member or manager!"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
class HandyRoles < Array
|
172
|
+
def include? role
|
173
|
+
super role.to_s
|
174
|
+
end
|
175
|
+
alias_method :has?, :include?
|
176
|
+
|
177
|
+
def method_missing m, *args, &block
|
178
|
+
m = m.to_s
|
179
|
+
super unless m.last == '?'
|
180
|
+
|
181
|
+
self.include? m[0..-2]
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def calculate_effective_roles_for roles
|
186
|
+
permissions = Rad.multitenant_mode? ? Space.current.permissions : Space.permissions
|
187
|
+
effective_space_permissions = {}
|
188
|
+
permissions.each do |operation, allowed_roles|
|
189
|
+
effective_space_permissions[operation] = roles.any?{|role| allowed_roles.include? role}
|
190
|
+
end
|
191
|
+
effective_space_permissions
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Plugins
|
3
|
+
module AuthorizedObject
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
def acts_as_authorized_object
|
7
|
+
key :owner_name, String, :default => lambda{User.current? ? User.current.name : nil}, :protected => true
|
8
|
+
key :collaborators, Array, :protected => true
|
9
|
+
# Contains the role and all upper roles. So complex becouse we need it in indexes.
|
10
|
+
key :viewers, Array, :default => lambda{User.current? ? ["user:#{User.current.name}", 'manager'].sort : ['manager']}, :protected => true
|
11
|
+
|
12
|
+
validates_presence_of :owner_name
|
13
|
+
validate :validate_viewers
|
14
|
+
validate :validate_collaborators
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module InstanceMethods
|
19
|
+
#
|
20
|
+
# Owner
|
21
|
+
#
|
22
|
+
def owner
|
23
|
+
return nil if owner_name.blank?
|
24
|
+
cache[:owner] ||= User.find_by_name! owner_name
|
25
|
+
end
|
26
|
+
|
27
|
+
def owner= user
|
28
|
+
user.must_be.an User
|
29
|
+
cache[:owner] = user
|
30
|
+
self.owner_name = user.name
|
31
|
+
user
|
32
|
+
end
|
33
|
+
|
34
|
+
# TODO2 update it later, MM uses public API to unmarshal object
|
35
|
+
# http://groups.google.com/group/mongomapper/browse_thread/thread/ab34457e0ba9c472#
|
36
|
+
def owner_name= name
|
37
|
+
owner_role = "user:#{name}"
|
38
|
+
old_owner_role = "user:#{owner_name}"
|
39
|
+
|
40
|
+
unless viewers.include? owner_role
|
41
|
+
viewers.delete old_owner_role
|
42
|
+
viewers << owner_role
|
43
|
+
viewers.sort!
|
44
|
+
end
|
45
|
+
|
46
|
+
# write_attribute :owner_name, name
|
47
|
+
super name
|
48
|
+
clear_cache
|
49
|
+
owner_name
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Viewers and Collaborators
|
54
|
+
#
|
55
|
+
def add_viewer role
|
56
|
+
role = role.to_s
|
57
|
+
should_be_valid_user_input_role role
|
58
|
+
|
59
|
+
return if viewers.include? role
|
60
|
+
|
61
|
+
roles = viewers
|
62
|
+
roles << role
|
63
|
+
roles = Role.denormalize_to_higher_roles roles
|
64
|
+
roles << 'manager' unless roles.include? 'manager'
|
65
|
+
self.viewers = roles.sort
|
66
|
+
viewers
|
67
|
+
end
|
68
|
+
|
69
|
+
def remove_viewer role
|
70
|
+
role = role.to_s
|
71
|
+
should_be_valid_user_input_role role
|
72
|
+
|
73
|
+
return unless viewers.include? role
|
74
|
+
|
75
|
+
roles = viewers
|
76
|
+
Role.denormalize_to_higher_roles([role]).each do |r|
|
77
|
+
roles.delete r
|
78
|
+
end
|
79
|
+
roles << 'manager' unless roles.include? 'manager'
|
80
|
+
self.viewers = roles.sort
|
81
|
+
|
82
|
+
remove_collaborator role
|
83
|
+
|
84
|
+
viewers
|
85
|
+
end
|
86
|
+
|
87
|
+
def minor_viewers
|
88
|
+
unless minor_viewers = cache[:minor_viewers]
|
89
|
+
viewers = self.viewers.clone
|
90
|
+
viewers.delete 'manager'
|
91
|
+
minor_viewers = Role.minor_roles viewers
|
92
|
+
cache[:minor_viewers] = minor_viewers
|
93
|
+
end
|
94
|
+
minor_viewers
|
95
|
+
end
|
96
|
+
|
97
|
+
def add_collaborator role
|
98
|
+
role = role.to_s
|
99
|
+
should_be_valid_user_input_role role
|
100
|
+
return if collaborators.include? role
|
101
|
+
collaborators = self.collaborators.clone
|
102
|
+
collaborators << role
|
103
|
+
self.collaborators = collaborators
|
104
|
+
|
105
|
+
add_viewer role
|
106
|
+
|
107
|
+
collaborators
|
108
|
+
end
|
109
|
+
|
110
|
+
def remove_collaborator role
|
111
|
+
role = role.to_s
|
112
|
+
should_be_valid_user_input_role role
|
113
|
+
collaborators.delete role
|
114
|
+
collaborators
|
115
|
+
end
|
116
|
+
|
117
|
+
def normalized_collaborators
|
118
|
+
unless normalized_collaborators = cache[:normalized_collaborators]
|
119
|
+
normalized_collaborators = Role.denormalize_to_higher_roles collaborators
|
120
|
+
normalized_collaborators << "user:#{owner_name}"
|
121
|
+
normalized_collaborators.sort!
|
122
|
+
cache[:normalized_collaborators] = normalized_collaborators
|
123
|
+
end
|
124
|
+
normalized_collaborators
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
#
|
129
|
+
# Special Permissions
|
130
|
+
#
|
131
|
+
def able_view? user
|
132
|
+
user.roles.any?{|role| viewers.include? role}
|
133
|
+
end
|
134
|
+
|
135
|
+
def able_update? user
|
136
|
+
user.roles.any?{|role| normalized_collaborators.include? role}
|
137
|
+
end
|
138
|
+
|
139
|
+
protected
|
140
|
+
def should_be_valid_user_input_role role
|
141
|
+
# ::Rails.should_be! :multitenant_mode
|
142
|
+
# (Role::ORDERED_ROLES + Space.current.custom_roles).should! :include, role.to_s
|
143
|
+
role.must_not == 'manager'
|
144
|
+
role.must_not == "user:#{owner_name}"
|
145
|
+
end
|
146
|
+
|
147
|
+
def validate_viewers
|
148
|
+
viewers.must == viewers.uniq
|
149
|
+
|
150
|
+
viewers.must.include 'manager' # always
|
151
|
+
viewers.must.include "user:#{owner_name}"
|
152
|
+
end
|
153
|
+
|
154
|
+
def validate_collaborators
|
155
|
+
collaborators.must_not.include "user:#{owner_name}"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# module ClassMethods
|
160
|
+
# def can? operation, user
|
161
|
+
# method = "can_#{operation}?"
|
162
|
+
# if respond_to? method
|
163
|
+
# send method, user
|
164
|
+
# else
|
165
|
+
# user.effective_space_permissions[operation]
|
166
|
+
# end
|
167
|
+
# end
|
168
|
+
# end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Plugins
|
3
|
+
module Multitenant
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
def connect_to_global_database
|
7
|
+
use_database :global
|
8
|
+
end
|
9
|
+
|
10
|
+
def belongs_to_space!
|
11
|
+
keys.symbolize_keys.must_not.include :account_id
|
12
|
+
|
13
|
+
key :account_id, ObjectId, :default => lambda{Account.current? ? Account.current.id : nil}, :protected => true
|
14
|
+
belongs_to :account
|
15
|
+
|
16
|
+
key :space_id, ObjectId, :default => lambda{Space.current? ? Space.current.id : nil}, :protected => true
|
17
|
+
belongs_to :space
|
18
|
+
|
19
|
+
validates_presence_of :account_id, :space_id
|
20
|
+
|
21
|
+
default_scope do
|
22
|
+
Space.current? ? {:space_id => Space.current.id} : {}
|
23
|
+
end
|
24
|
+
|
25
|
+
# defer do
|
26
|
+
ensure_index :account_id
|
27
|
+
ensure_index :space_id
|
28
|
+
# end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Plugins
|
3
|
+
module RadMicelaneous
|
4
|
+
module InstanceMethods
|
5
|
+
delegate :config, :to => Crystal
|
6
|
+
delegate :t, :to => I18n
|
7
|
+
|
8
|
+
def to_rson options = {}
|
9
|
+
with_errors = if options.include?('errors')
|
10
|
+
options.delete 'errors'
|
11
|
+
elsif options.include?(:errors)
|
12
|
+
options.delete :errors
|
13
|
+
else
|
14
|
+
true
|
15
|
+
end
|
16
|
+
|
17
|
+
# standard MM as_json conversion
|
18
|
+
hash = as_json(options)
|
19
|
+
|
20
|
+
# MM fix
|
21
|
+
hash['id'] = hash.delete :id if hash.include? :id
|
22
|
+
|
23
|
+
# adding errors
|
24
|
+
if with_errors
|
25
|
+
errors = {}
|
26
|
+
errors.each do |name, list|
|
27
|
+
errors[name.to_s] = list
|
28
|
+
end
|
29
|
+
hash['errors'] = errors unless errors.empty?
|
30
|
+
end
|
31
|
+
|
32
|
+
hash
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module ClassMethods
|
37
|
+
delegate :config, :to => Crystal
|
38
|
+
delegate :t, :to => I18n
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Plugins
|
3
|
+
module SpaceKeys
|
4
|
+
|
5
|
+
class SpaceKeysContainer
|
6
|
+
include MongoMapper::EmbeddedDocument
|
7
|
+
key :space_id, ObjectId
|
8
|
+
|
9
|
+
SKIP_KEYS = %w{_id space_id}
|
10
|
+
|
11
|
+
def blank?
|
12
|
+
self.class.keys.keys.select{|k| !SKIP_KEYS.include?(k.to_s)}.all?{|k| value = send(k); value.blank? or value == 0}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module InstanceMethods
|
17
|
+
def get_create_or_delete_space_keys_container modifying_operation, &block
|
18
|
+
Rad.multitenant_mode?.must_be.true
|
19
|
+
|
20
|
+
unless modifying_operation
|
21
|
+
container = space_keys_containers.select{|c| c.space_id == Space.current.id}.first || \
|
22
|
+
SpaceKeysContainer.new(:space_id => Space.current.id)
|
23
|
+
block.call container
|
24
|
+
else
|
25
|
+
container = space_keys_containers.select{|c| c.space_id == Space.current.id}.first || \
|
26
|
+
space_keys_containers.build(:space_id => Space.current.id)
|
27
|
+
block.call container
|
28
|
+
space_keys_containers.delete container if container.blank?
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module ClassMethods
|
34
|
+
def space_key key, type, options = {}
|
35
|
+
define_space_keys_containers
|
36
|
+
|
37
|
+
SpaceKeysContainer.send :key, key, type, options
|
38
|
+
|
39
|
+
define_method key do
|
40
|
+
get_create_or_delete_space_keys_container false do |container|
|
41
|
+
container.send key
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
define_method "#{key}=" do |value|
|
46
|
+
get_create_or_delete_space_keys_container true do |container|
|
47
|
+
container.send "#{key}=", value
|
48
|
+
value
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def define_space_keys_containers
|
54
|
+
unless associations.keys.include? 'space_keys_containers'
|
55
|
+
has_many :space_keys_containers, :class_name => 'MongoMapper::Plugins::SpaceKeys::SpaceKeysContainer', :protected => true
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Plugins
|
3
|
+
module TextProcessor
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
def markup_key attr_name, opt = {}
|
7
|
+
attr_name = attr_name.to_s
|
8
|
+
opt = opt.to_openobject
|
9
|
+
original_attr_name = "original_#{attr_name}"
|
10
|
+
|
11
|
+
key original_attr_name, String
|
12
|
+
key attr_name, String, :protected => true unless keys.keys.include? attr_name
|
13
|
+
|
14
|
+
validates_presence_of attr_name, original_attr_name if opt.required?
|
15
|
+
|
16
|
+
alias_method "#{attr_name}_without_markup=", "#{attr_name}="
|
17
|
+
alias_method "#{original_attr_name}_without_markup=", "#{original_attr_name}="
|
18
|
+
|
19
|
+
define_method "#{attr_name}=" do |value|
|
20
|
+
send "#{original_attr_name}_without_markup=", value
|
21
|
+
send "#{attr_name}_without_markup=", value
|
22
|
+
end
|
23
|
+
|
24
|
+
define_method "#{original_attr_name}=" do |value|
|
25
|
+
send "#{original_attr_name}_without_markup=", value
|
26
|
+
send "#{attr_name}_without_markup=", TextUtils.markup(value)
|
27
|
+
end
|
28
|
+
|
29
|
+
define_method "#{attr_name}_as_text" do
|
30
|
+
value = send(attr_name)
|
31
|
+
return "" if value.blank?
|
32
|
+
Nokogiri::XML(value).content
|
33
|
+
end
|
34
|
+
|
35
|
+
ce_method_name = "copy_errors_for_#{attr_name}"
|
36
|
+
define_method ce_method_name do
|
37
|
+
if !errors.on(original_attr_name) and (err = errors.on(attr_name))
|
38
|
+
errors.add original_attr_name, err
|
39
|
+
end
|
40
|
+
end
|
41
|
+
after_validation ce_method_name
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'mongo_mapper_ext'
|
2
|
+
|
3
|
+
%w(
|
4
|
+
multitenant
|
5
|
+
space_keys
|
6
|
+
text_processor
|
7
|
+
rad_micelaneous
|
8
|
+
acts_as/authenticated_by_open_id
|
9
|
+
acts_as/authenticated_by_password
|
10
|
+
acts_as/authorized
|
11
|
+
acts_as/authorized_object
|
12
|
+
).each{|n| require "rad/mongo_mapper/#{n}"}
|
13
|
+
|
14
|
+
module RadPluginsAddition
|
15
|
+
def self.included(model)
|
16
|
+
model.plugin MongoMapper::Plugins::Multitenant
|
17
|
+
model.plugin MongoMapper::Plugins::RadMicelaneous
|
18
|
+
end
|
19
|
+
end
|
20
|
+
MongoMapper::Document.append_inclusions(RadPluginsAddition)
|
@@ -0,0 +1,40 @@
|
|
1
|
+
Paperclip::ClassMethods.class_eval do
|
2
|
+
def trace_file attachment
|
3
|
+
upd_method_name = "update_file_size_for_#{attachment}"
|
4
|
+
define_method upd_method_name do
|
5
|
+
return if disable_file_audit?
|
6
|
+
|
7
|
+
size = file_size_for(attachment)
|
8
|
+
old_size = old_file_size_for(attachment)
|
9
|
+
|
10
|
+
if (difference = size - old_size) != 0
|
11
|
+
self.class.increase_user_and_account_files_size difference
|
12
|
+
set_old_file_size_for(attachment, size)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
protected upd_method_name
|
16
|
+
before_save upd_method_name
|
17
|
+
|
18
|
+
clear_method_name = "clear_file_size_for_#{attachment}"
|
19
|
+
define_method clear_method_name do
|
20
|
+
return if disable_file_audit?
|
21
|
+
|
22
|
+
difference = - old_file_size_for(attachment)
|
23
|
+
self.class.increase_user_and_account_files_size difference
|
24
|
+
end
|
25
|
+
protected clear_method_name
|
26
|
+
after_destroy clear_method_name
|
27
|
+
end
|
28
|
+
|
29
|
+
def increase_user_and_account_files_size difference
|
30
|
+
# Upsert can't be used becouse user.files_size is not just an attribute
|
31
|
+
# User.current.files_size += difference
|
32
|
+
# User.upsert :$inc => {:files_size => difference}
|
33
|
+
u = User.current
|
34
|
+
u.files_size += difference
|
35
|
+
u.save!
|
36
|
+
|
37
|
+
Account.current.files_size += difference
|
38
|
+
Account.current.upsert :$inc => {:files_size => difference}
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# interpolation = "/system/:class/:attachment/:id_partition/:style_:filename"
|
2
|
+
interpolation = "/system/:account/:space/:class/:slug/:attachment/:filename_with_style"
|
3
|
+
|
4
|
+
# Paperclip::Attachment.class_eval do
|
5
|
+
# default_options.merge!({
|
6
|
+
# :url => "#{ActionController::Base.relative_url_root}#{interpolation}",
|
7
|
+
# :path => ":rails_root/public" + interpolation,
|
8
|
+
# # :default_url => "/:attachment/:style/missing.png",
|
9
|
+
# })
|
10
|
+
# end
|
11
|
+
|
12
|
+
crystal.after :config do |config|
|
13
|
+
Paperclip::Attachment.class_eval do
|
14
|
+
default_options.merge!({
|
15
|
+
:url => "#{config.root('')}#{interpolation}",
|
16
|
+
:path => ":crystal_root/public" + interpolation,
|
17
|
+
# :default_url => "/:attachment/:style/missing.png",
|
18
|
+
})
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module Paperclip
|
23
|
+
class << self
|
24
|
+
inject :logger => :logger
|
25
|
+
end
|
26
|
+
|
27
|
+
module Interpolations
|
28
|
+
def filename_with_style attachment, style
|
29
|
+
val = filename(attachment, style).clone
|
30
|
+
if style.to_s != 'original'
|
31
|
+
basename_index = val.rindex('.') || (val.size - 1)
|
32
|
+
val.insert basename_index, ".#{style}"
|
33
|
+
end
|
34
|
+
val
|
35
|
+
end
|
36
|
+
|
37
|
+
# Handle string ids (mongo)
|
38
|
+
# def id_partition attachment, style
|
39
|
+
# if (id = attachment.instance.id).is_a?(Integer)
|
40
|
+
# ("%09d" % id).scan(/\d{3}/).join("/")
|
41
|
+
# else
|
42
|
+
# id.to_s.scan(/.{3}/).first(3).join("/")
|
43
|
+
# end
|
44
|
+
# end
|
45
|
+
|
46
|
+
%w{name slug}.each do |name|
|
47
|
+
define_method name do |attachment, style|
|
48
|
+
attachment.instance.send name
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def account attachment, style
|
53
|
+
Account.current.name
|
54
|
+
end
|
55
|
+
|
56
|
+
def space attachment, style
|
57
|
+
Space.current.name
|
58
|
+
end
|
59
|
+
|
60
|
+
def crystal_root attachment, style
|
61
|
+
crystal.config.root('')
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|