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