repository-manager 0.0.13 → 0.0.22
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.
- checksums.yaml +5 -13
- data/.rspec +1 -1
- data/README.md +424 -419
- data/app/models/repo_file.rb +29 -29
- data/app/models/repo_folder.rb +134 -114
- data/app/models/repo_item.rb +65 -64
- data/app/models/sharing.rb +58 -58
- data/app/models/sharings_member.rb +5 -5
- data/config/locales/en/repository_manager.en.yml +19 -0
- data/config/locales/fr/repository_manager.fr.yml +19 -0
- data/db/migrate/20131018214212_create_repository_manager.rb +32 -31
- data/lib/generators/repository_manager/install_generator.rb +32 -32
- data/lib/generators/repository_manager/templates/initializer.rb +11 -11
- data/lib/repository_manager/exceptions.rb +9 -9
- data/lib/repository_manager/has_repository.rb +506 -452
- data/lib/repository_manager/version.rb +1 -1
- data/repository-manager.gemspec +30 -30
- data/spec/dummy/db/migrate/20131016193722_create_users.rb +10 -10
- data/spec/dummy/db/migrate/20131016193834_create_groups.rb +9 -9
- data/spec/dummy/db/migrate/20131016194207_create_groups_users.rb +4 -4
- data/spec/dummy/db/migrate/20131018214212_create_repository_manager.rb +31 -31
- data/spec/dummy/db/schema.rb +66 -66
- data/spec/factories/group.rb +7 -7
- data/spec/factories/repo_file.rb +12 -12
- data/spec/factories/repo_folder.rb +7 -7
- data/spec/factories/user.rb +13 -13
- data/spec/has_repository_spec.rb +280 -281
- data/spec/models/associations_spec.rb +88 -88
- data/spec/models/repository_spec.rb +176 -144
- data/spec/models/share_spec.rb +67 -67
- metadata +34 -37
@@ -1,6 +1,6 @@
|
|
1
|
-
class SharingsMember < ActiveRecord::Base
|
2
|
-
attr_accessible :can_add, :can_remove if RepositoryManager.protected_attributes?
|
3
|
-
|
4
|
-
belongs_to :member, polymorphic: true
|
5
|
-
belongs_to :sharing
|
1
|
+
class SharingsMember < ActiveRecord::Base
|
2
|
+
attr_accessible :can_add, :can_remove if RepositoryManager.protected_attributes?
|
3
|
+
|
4
|
+
belongs_to :member, polymorphic: true
|
5
|
+
belongs_to :sharing
|
6
6
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
en:
|
2
|
+
repository_manager:
|
3
|
+
models:
|
4
|
+
repo_folder:
|
5
|
+
name: Nouveau dossier
|
6
|
+
success:
|
7
|
+
repo_folder:
|
8
|
+
created: Le dossier a été créé avec succès !
|
9
|
+
repo_file:
|
10
|
+
created: Le fichier a été créé avec succès !
|
11
|
+
errors:
|
12
|
+
repo_folder:
|
13
|
+
not_created: Erreur, le dossier n'a pas été créé !
|
14
|
+
repo_file:
|
15
|
+
not_created: Erreur, le fichier n'a pas été envoyé !
|
16
|
+
form:
|
17
|
+
new:
|
18
|
+
repo_folder: Créer un dossier
|
19
|
+
repo_file: Envoyer un fichier
|
@@ -0,0 +1,19 @@
|
|
1
|
+
fr:
|
2
|
+
repository_manager:
|
3
|
+
models:
|
4
|
+
repo_folder:
|
5
|
+
name: Nouveau dossier
|
6
|
+
success:
|
7
|
+
repo_folder:
|
8
|
+
created: Le dossier a été créé avec succès !
|
9
|
+
repo_file:
|
10
|
+
created: Le fichier a été créé avec succès !
|
11
|
+
errors:
|
12
|
+
repo_folder:
|
13
|
+
not_created: Erreur, le dossier n'a pas été créé !
|
14
|
+
repo_file:
|
15
|
+
not_created: Erreur, le fichier n'a pas été envoyé !
|
16
|
+
form:
|
17
|
+
new:
|
18
|
+
repo_folder: Créer un dossier
|
19
|
+
repo_file: Envoyer un fichier
|
@@ -1,32 +1,33 @@
|
|
1
|
-
class CreateRepositoryManager < ActiveRecord::Migration
|
2
|
-
|
3
|
-
def change
|
4
|
-
|
5
|
-
create_table :sharings do |t|
|
6
|
-
t.references :owner, polymorphic: true
|
7
|
-
t.references :repo_item
|
8
|
-
t.boolean :can_create, :default => false
|
9
|
-
t.boolean :can_read, :default => false
|
10
|
-
t.boolean :can_update, :default => false
|
11
|
-
t.boolean :can_delete, :default => false
|
12
|
-
t.boolean :can_share, :default => false
|
13
|
-
end
|
14
|
-
|
15
|
-
create_table :sharings_members do |t|
|
16
|
-
t.references :sharing
|
17
|
-
t.references :member, polymorphic: true
|
18
|
-
t.boolean :can_add, :default => false
|
19
|
-
t.boolean :can_remove, :default => false
|
20
|
-
end
|
21
|
-
|
22
|
-
create_table :repo_items do |t|
|
23
|
-
t.references :owner, polymorphic: true
|
24
|
-
t.string :ancestry
|
25
|
-
t.
|
26
|
-
t.
|
27
|
-
t.
|
28
|
-
t.string :
|
29
|
-
t.string :
|
30
|
-
|
31
|
-
|
1
|
+
class CreateRepositoryManager < ActiveRecord::Migration
|
2
|
+
|
3
|
+
def change
|
4
|
+
|
5
|
+
create_table :sharings do |t|
|
6
|
+
t.references :owner, polymorphic: true
|
7
|
+
t.references :repo_item
|
8
|
+
t.boolean :can_create, :default => false
|
9
|
+
t.boolean :can_read, :default => false
|
10
|
+
t.boolean :can_update, :default => false
|
11
|
+
t.boolean :can_delete, :default => false
|
12
|
+
t.boolean :can_share, :default => false
|
13
|
+
end
|
14
|
+
|
15
|
+
create_table :sharings_members do |t|
|
16
|
+
t.references :sharing
|
17
|
+
t.references :member, polymorphic: true
|
18
|
+
t.boolean :can_add, :default => false
|
19
|
+
t.boolean :can_remove, :default => false
|
20
|
+
end
|
21
|
+
|
22
|
+
create_table :repo_items do |t|
|
23
|
+
t.references :owner, polymorphic: true
|
24
|
+
t.string :ancestry
|
25
|
+
t.integer :ancestry_depth, :default => 0
|
26
|
+
t.string :name
|
27
|
+
t.float :file_size
|
28
|
+
t.string :content_type
|
29
|
+
t.string :file
|
30
|
+
t.string :type
|
31
|
+
end
|
32
|
+
end
|
32
33
|
end
|
@@ -1,33 +1,33 @@
|
|
1
|
-
module RepositoryManager #:nodoc:
|
2
|
-
class InstallGenerator < Rails::Generators::Base
|
3
|
-
include Rails::Generators::Migration
|
4
|
-
source_root File.expand_path("../templates", __FILE__)
|
5
|
-
require 'rails/generators/migration'
|
6
|
-
|
7
|
-
def self.next_migration_number path
|
8
|
-
unless @prev_migration_nr
|
9
|
-
@prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
|
10
|
-
else
|
11
|
-
@prev_migration_nr += 1
|
12
|
-
end
|
13
|
-
@prev_migration_nr.to_s
|
14
|
-
end
|
15
|
-
|
16
|
-
def create_initializer_file
|
17
|
-
template 'initializer.rb', 'config/initializers/repository_manager.rb'
|
18
|
-
end
|
19
|
-
|
20
|
-
# all public methods in here will be run in order
|
21
|
-
#def copy_initializer_file
|
22
|
-
# copy_file "initializer.rb", "config/initializers/repository_manager_initializer.rb"
|
23
|
-
#end
|
24
|
-
|
25
|
-
def copy_migrations
|
26
|
-
migrations = [["20131018214212_create_repository_manager.rb","create_repository_manager.rb"]
|
27
|
-
]
|
28
|
-
migrations.each do |migration|
|
29
|
-
migration_template "../../../../db/migrate/" + migration[0], "db/migrate/" + migration[1]
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
1
|
+
module RepositoryManager #:nodoc:
|
2
|
+
class InstallGenerator < Rails::Generators::Base
|
3
|
+
include Rails::Generators::Migration
|
4
|
+
source_root File.expand_path("../templates", __FILE__)
|
5
|
+
require 'rails/generators/migration'
|
6
|
+
|
7
|
+
def self.next_migration_number path
|
8
|
+
unless @prev_migration_nr
|
9
|
+
@prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
|
10
|
+
else
|
11
|
+
@prev_migration_nr += 1
|
12
|
+
end
|
13
|
+
@prev_migration_nr.to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_initializer_file
|
17
|
+
template 'initializer.rb', 'config/initializers/repository_manager.rb'
|
18
|
+
end
|
19
|
+
|
20
|
+
# all public methods in here will be run in order
|
21
|
+
#def copy_initializer_file
|
22
|
+
# copy_file "initializer.rb", "config/initializers/repository_manager_initializer.rb"
|
23
|
+
#end
|
24
|
+
|
25
|
+
def copy_migrations
|
26
|
+
migrations = [["20131018214212_create_repository_manager.rb","create_repository_manager.rb"]
|
27
|
+
]
|
28
|
+
migrations.each do |migration|
|
29
|
+
migration_template "../../../../db/migrate/" + migration[0], "db/migrate/" + migration[1]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
33
|
end
|
@@ -1,12 +1,12 @@
|
|
1
|
-
RepositoryManager.setup do |config|
|
2
|
-
|
3
|
-
# Default repo_item permissions that an object has on the repo_item after a sharing.
|
4
|
-
config.default_repo_item_permissions = { can_read: true, can_create: false, can_update:false, can_delete:false, can_share: false }
|
5
|
-
|
6
|
-
# Default sharing permissions that an object has when he is added in a sharing.
|
7
|
-
config.default_sharing_permissions = { can_add: false, can_remove: false }
|
8
|
-
|
9
|
-
# Default path for generating the zip file when a user want to download a folder
|
10
|
-
# Default is : "download/#{member.class.to_s.underscore}/#{member.id}/#{self.class.to_s.underscore}/#{self.id}/"
|
11
|
-
#config.default_zip_path = true
|
1
|
+
RepositoryManager.setup do |config|
|
2
|
+
|
3
|
+
# Default repo_item permissions that an object has on the repo_item after a sharing.
|
4
|
+
config.default_repo_item_permissions = { can_read: true, can_create: false, can_update:false, can_delete:false, can_share: false }
|
5
|
+
|
6
|
+
# Default sharing permissions that an object has when he is added in a sharing.
|
7
|
+
config.default_sharing_permissions = { can_add: false, can_remove: false }
|
8
|
+
|
9
|
+
# Default path for generating the zip file when a user want to download a folder
|
10
|
+
# Default is : "download/#{member.class.to_s.underscore}/#{member.id}/#{self.class.to_s.underscore}/#{self.id}/"
|
11
|
+
#config.default_zip_path = true
|
12
12
|
end
|
@@ -1,10 +1,10 @@
|
|
1
|
-
module RepositoryManager
|
2
|
-
class RepositoryManagerException < RuntimeError
|
3
|
-
end
|
4
|
-
|
5
|
-
class AuthorisationException < RepositoryManagerException
|
6
|
-
end
|
7
|
-
|
8
|
-
class NestedSharingException < RepositoryManagerException
|
9
|
-
end
|
1
|
+
module RepositoryManager
|
2
|
+
class RepositoryManagerException < RuntimeError
|
3
|
+
end
|
4
|
+
|
5
|
+
class AuthorisationException < RepositoryManagerException
|
6
|
+
end
|
7
|
+
|
8
|
+
class NestedSharingException < RepositoryManagerException
|
9
|
+
end
|
10
10
|
end
|
@@ -1,453 +1,507 @@
|
|
1
|
-
module RepositoryManager
|
2
|
-
module HasRepository
|
3
|
-
extend ActiveSupport::Concern
|
4
|
-
|
5
|
-
module ClassMethods
|
6
|
-
def has_repository(options = {})
|
7
|
-
|
8
|
-
has_many :sharings, through: :sharings_members
|
9
|
-
has_many :sharings_members, as: :member, dependent: :destroy
|
10
|
-
has_many :sharings_owners, as: :owner, class_name: 'Sharing'
|
11
|
-
|
12
|
-
# The own repo_items
|
13
|
-
has_many :repo_items, as: :owner #, dependent: :destroy
|
14
|
-
# The sharing repo_items
|
15
|
-
has_many :shared_repo_items, through: :sharings, source: :repo_item, class_name: 'RepoItem'
|
16
|
-
|
17
|
-
#scope :all_repo_items, -> { self.repo_items.shared_repo_items }
|
18
|
-
|
19
|
-
#All repo_items (own and sharings)
|
20
|
-
#has_many :all_repo_items
|
21
|
-
|
22
|
-
include RepositoryManager::HasRepository::LocalInstanceMethods
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
module LocalInstanceMethods
|
27
|
-
|
28
|
-
# Sharing the repo_item with the members, with the options
|
29
|
-
# options[:repo_item_permissions] contains :
|
30
|
-
# <tt>:can_read</tt> - Member can download the repo_item
|
31
|
-
# <tt>:can_create</tt> - Member can create a new repo_item on it
|
32
|
-
# <tt>:can_edit</tt> - Member can edit the repo_item
|
33
|
-
# <tt>:can_delete</tt> - Member can delete the repo_item
|
34
|
-
# <tt>:can_share</tt> - Member can share the repo_item
|
35
|
-
# options[:sharing_permissions] contains :
|
36
|
-
# <tt>:can_add</tt> - Specify if the member can add objects to the sharing
|
37
|
-
# <tt>:can_remove</tt> - Specify if the member can remove object to the sharing
|
38
|
-
def share!(repo_item, members, options = {})
|
39
|
-
|
40
|
-
# Nested sharing are not accepted
|
41
|
-
if !RepositoryManager.accept_nested_sharing
|
42
|
-
# Check if no other sharing exist in the path
|
43
|
-
if repo_item.has_nested_sharing?
|
44
|
-
raise RepositoryManager::NestedSharingException.new("sharing failed. Another sharing already exist on the subtree or an ancestor '#{repo_item.name}'")
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
authorisations = get_authorisations(repo_item)
|
49
|
-
|
50
|
-
# Here we look if the instance has the authorisation for making a sharing
|
51
|
-
if can_share?(nil, authorisations)
|
52
|
-
|
53
|
-
# We put the default options
|
54
|
-
repo_item_permissions = RepositoryManager.default_repo_item_permissions
|
55
|
-
sharing_permissions = RepositoryManager.default_sharing_permissions
|
56
|
-
|
57
|
-
# If there is options, we have to take it
|
58
|
-
repo_item_permissions = options[:repo_item_permissions] if options[:repo_item_permissions]
|
59
|
-
sharing_permissions = options[:sharing_permissions] if options[:sharing_permissions]
|
60
|
-
|
61
|
-
# Correct the item permission with accepted permissions
|
62
|
-
repo_item_permissions = make_repo_item_permissions(repo_item_permissions, authorisations)
|
63
|
-
|
64
|
-
sharing = Sharing.new(repo_item_permissions)
|
65
|
-
sharing.owner = self
|
66
|
-
|
67
|
-
sharing.add_members(members, sharing_permissions)
|
68
|
-
|
69
|
-
repo_item.sharings << sharing
|
70
|
-
repo_item.save
|
71
|
-
sharing
|
72
|
-
else
|
73
|
-
# No permission => No sharing
|
74
|
-
raise RepositoryManager::AuthorisationException.new("sharing failed. You don't have the permission to share the repo_item '#{repo_item.name}'")
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def share(repo_item, members, options = {})
|
79
|
-
begin
|
80
|
-
share!(repo_item, members, options)
|
81
|
-
rescue RepositoryManager::AuthorisationException, RepositoryManager::NestedSharingException
|
82
|
-
false
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
# Create a folder with the name (name) in the directory (source_folder)
|
87
|
-
# Returns the object of the folder created if it is ok
|
88
|
-
# Returns an Exception if the folder is not created
|
89
|
-
# RepositoryManagerException if the name already exist
|
90
|
-
# AuthorisationException if the object don't have the permission
|
91
|
-
def create_folder!(name = '
|
92
|
-
# If he want to create a folder in a directory, we have to check if he have the authorisation
|
93
|
-
if can_create?(source_folder)
|
94
|
-
|
95
|
-
folder = RepoFolder.new
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
#
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
repo_file
|
149
|
-
|
150
|
-
repo_file
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
create_file
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
#
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
end
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
repo_item
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
end
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
#
|
292
|
-
#
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
#
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
#
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
#
|
315
|
-
#
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
end
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
#
|
360
|
-
def
|
361
|
-
if
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
#
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
1
|
+
module RepositoryManager
|
2
|
+
module HasRepository
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
def has_repository(options = {})
|
7
|
+
|
8
|
+
has_many :sharings, through: :sharings_members
|
9
|
+
has_many :sharings_members, as: :member, dependent: :destroy
|
10
|
+
has_many :sharings_owners, as: :owner, class_name: 'Sharing'
|
11
|
+
|
12
|
+
# The own repo_items
|
13
|
+
has_many :repo_items, as: :owner #, dependent: :destroy
|
14
|
+
# The sharing repo_items
|
15
|
+
has_many :shared_repo_items, through: :sharings, source: :repo_item, class_name: 'RepoItem'
|
16
|
+
|
17
|
+
#scope :all_repo_items, -> { self.repo_items.shared_repo_items }
|
18
|
+
|
19
|
+
#All repo_items (own and sharings)
|
20
|
+
#has_many :all_repo_items
|
21
|
+
|
22
|
+
include RepositoryManager::HasRepository::LocalInstanceMethods
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module LocalInstanceMethods
|
27
|
+
|
28
|
+
# Sharing the repo_item with the members, with the options
|
29
|
+
# options[:repo_item_permissions] contains :
|
30
|
+
# <tt>:can_read</tt> - Member can download the repo_item
|
31
|
+
# <tt>:can_create</tt> - Member can create a new repo_item on it
|
32
|
+
# <tt>:can_edit</tt> - Member can edit the repo_item
|
33
|
+
# <tt>:can_delete</tt> - Member can delete the repo_item
|
34
|
+
# <tt>:can_share</tt> - Member can share the repo_item
|
35
|
+
# options[:sharing_permissions] contains :
|
36
|
+
# <tt>:can_add</tt> - Specify if the member can add objects to the sharing
|
37
|
+
# <tt>:can_remove</tt> - Specify if the member can remove object to the sharing
|
38
|
+
def share!(repo_item, members, options = {})
|
39
|
+
|
40
|
+
# Nested sharing are not accepted
|
41
|
+
if !RepositoryManager.accept_nested_sharing
|
42
|
+
# Check if no other sharing exist in the path
|
43
|
+
if repo_item.has_nested_sharing?
|
44
|
+
raise RepositoryManager::NestedSharingException.new("sharing failed. Another sharing already exist on the subtree or an ancestor '#{repo_item.name}'")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
authorisations = get_authorisations(repo_item)
|
49
|
+
|
50
|
+
# Here we look if the instance has the authorisation for making a sharing
|
51
|
+
if can_share?(nil, authorisations)
|
52
|
+
|
53
|
+
# We put the default options
|
54
|
+
repo_item_permissions = RepositoryManager.default_repo_item_permissions
|
55
|
+
sharing_permissions = RepositoryManager.default_sharing_permissions
|
56
|
+
|
57
|
+
# If there is options, we have to take it
|
58
|
+
repo_item_permissions = options[:repo_item_permissions] if options[:repo_item_permissions]
|
59
|
+
sharing_permissions = options[:sharing_permissions] if options[:sharing_permissions]
|
60
|
+
|
61
|
+
# Correct the item permission with accepted permissions
|
62
|
+
repo_item_permissions = make_repo_item_permissions(repo_item_permissions, authorisations)
|
63
|
+
|
64
|
+
sharing = Sharing.new(repo_item_permissions)
|
65
|
+
sharing.owner = self
|
66
|
+
|
67
|
+
sharing.add_members(members, sharing_permissions)
|
68
|
+
|
69
|
+
repo_item.sharings << sharing
|
70
|
+
repo_item.save
|
71
|
+
sharing
|
72
|
+
else
|
73
|
+
# No permission => No sharing
|
74
|
+
raise RepositoryManager::AuthorisationException.new("sharing failed. You don't have the permission to share the repo_item '#{repo_item.name}'")
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def share(repo_item, members, options = {})
|
79
|
+
begin
|
80
|
+
share!(repo_item, members, options)
|
81
|
+
rescue RepositoryManager::AuthorisationException, RepositoryManager::NestedSharingException
|
82
|
+
false
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Create a folder with the name (name) in the directory (source_folder)
|
87
|
+
# Returns the object of the folder created if it is ok
|
88
|
+
# Returns an Exception if the folder is not created
|
89
|
+
# RepositoryManagerException if the name already exist
|
90
|
+
# AuthorisationException if the object don't have the permission
|
91
|
+
def create_folder!(name = '', source_folder = nil)
|
92
|
+
# If he want to create a folder in a directory, we have to check if he have the authorisation
|
93
|
+
if can_create?(source_folder)
|
94
|
+
|
95
|
+
folder = RepoFolder.new
|
96
|
+
if name == ''
|
97
|
+
folder.name = default_folder_name(source_folder)
|
98
|
+
else
|
99
|
+
folder.name = name
|
100
|
+
end
|
101
|
+
folder.owner = self
|
102
|
+
|
103
|
+
# Soit il a une source_folder, donc on l'ajoute et on le sauve et ça fonctionne pas => ERREUR
|
104
|
+
# Soit il n'a pas de source_folder et le save ne va pas => ERREUR
|
105
|
+
unless (folder.save && source_folder && source_folder.add(folder)) || (!source_folder && folder.save)
|
106
|
+
folder.destroy
|
107
|
+
raise RepositoryManager::RepositoryManagerException.new("create_folder failed. Can\'t save the folder '#{name}'.")
|
108
|
+
end
|
109
|
+
else
|
110
|
+
raise RepositoryManager::AuthorisationException.new("create_folder failed. You don't have the permission to create a folder in '#{source_folder.name}'")
|
111
|
+
end
|
112
|
+
folder
|
113
|
+
end
|
114
|
+
|
115
|
+
def create_folder(name = '', source_folder = nil)
|
116
|
+
begin
|
117
|
+
create_folder!(name, source_folder)
|
118
|
+
rescue RepositoryManager::AuthorisationException, RepositoryManager::RepositoryManagerException
|
119
|
+
false
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Delete the repo_item
|
124
|
+
def delete_repo_item!(repo_item)
|
125
|
+
if can_delete?(repo_item)
|
126
|
+
repo_item.destroy
|
127
|
+
else
|
128
|
+
raise RepositoryManager::AuthorisationException.new("delete_repo_item failed. You don't have the permission to delete the repo_item '#{repo_item.name}'")
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def delete_repo_item(repo_item)
|
133
|
+
begin
|
134
|
+
delete_repo_item!(repo_item)
|
135
|
+
rescue RepositoryManager::AuthorisationException
|
136
|
+
false
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Create the file (file) in the directory (source_folder)
|
141
|
+
# Param file can be a File, or a instance of RepoFile
|
142
|
+
# Return the object of the file created if it is ok
|
143
|
+
# Return false if the file is not created (no authorisation)
|
144
|
+
def create_file!(file, source_folder = nil)
|
145
|
+
# If he want to create a file in a directory, we have to check if he have the authorisation
|
146
|
+
if can_create?(source_folder)
|
147
|
+
if file.class.name == 'RepoFile'
|
148
|
+
repo_file = file
|
149
|
+
repo_file.owner = self
|
150
|
+
unless repo_file.save
|
151
|
+
raise RepositoryManager::RepositoryManagerException.new("create_file failed. The file '#{name}' can't be save")
|
152
|
+
end
|
153
|
+
else
|
154
|
+
repo_file = RepoFile.new
|
155
|
+
repo_file.file = file
|
156
|
+
repo_file.owner = self
|
157
|
+
unless repo_file.save
|
158
|
+
raise RepositoryManager::RepositoryManagerException.new("create_file failed. The file '#{name}' can't be save")
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# We have to look if it is ok to add the file here
|
163
|
+
if source_folder == nil || source_folder.add(file)
|
164
|
+
return repo_file
|
165
|
+
else
|
166
|
+
# The add didn't works, we delete the file
|
167
|
+
file.destroy
|
168
|
+
raise RepositoryManager::RepositoryManagerException.new("create_file failed. The file '#{name}' already exist in folder '#{source_folder.name}'")
|
169
|
+
end
|
170
|
+
else
|
171
|
+
#raise "create_file failed. You don't have the permission to create a file in the folder '#{source_folder.name}'"
|
172
|
+
raise RepositoryManager::AuthorisationException.new("create_file failed. The file '#{name}' already exist in folder '#{source_folder.name}'")
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def create_file(file, source_folder = nil)
|
177
|
+
begin
|
178
|
+
create_file!(file, source_folder)
|
179
|
+
rescue RepositoryManager::AuthorisationException, RepositoryManager::RepositoryManagerException
|
180
|
+
false
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
# Gets the repo authorisations
|
185
|
+
# Return false if the entity has not the authorisation to share this rep
|
186
|
+
# Return true if the entity can share this rep with all the authorisations
|
187
|
+
# Return an Array if the entity can share but with restriction
|
188
|
+
# Return true if the repo_item is nil (he as all authorisations on his own rep)
|
189
|
+
def get_authorisations(repo_item = nil)
|
190
|
+
# If repo_item is nil, he can do what he want
|
191
|
+
return true if repo_item == nil
|
192
|
+
|
193
|
+
# If the member is the owner, he can do what he want !
|
194
|
+
if repo_item.owner == self
|
195
|
+
# You can do what ever you want :)
|
196
|
+
return true
|
197
|
+
# Find if a sharing of this rep exist for the self instance or it ancestors
|
198
|
+
else
|
199
|
+
path_ids = repo_item.path_ids
|
200
|
+
# Check the nearest sharing if it exist
|
201
|
+
if s = self.sharings.where(repo_item_id: path_ids).last
|
202
|
+
return {can_share: s.can_share, can_read: s.can_read, can_create: s.can_create, can_update: s.can_update, can_delete: s.can_delete}
|
203
|
+
end
|
204
|
+
end
|
205
|
+
# Else, false
|
206
|
+
return false
|
207
|
+
end
|
208
|
+
|
209
|
+
# Download a repo_item if the object can_read it
|
210
|
+
# If it is a file, he download the file
|
211
|
+
# If it is a folder, we check witch repo_item is in it, and witch he can_read
|
212
|
+
# We zip all the content that the object has access.
|
213
|
+
# options
|
214
|
+
# :path => 'path/to/zip'
|
215
|
+
def download!(repo_item, options = {})
|
216
|
+
if can_download?(repo_item)
|
217
|
+
path = options[:path] if options[:path]
|
218
|
+
|
219
|
+
repo_item.download({object: self, path: path})
|
220
|
+
else
|
221
|
+
raise RepositoryManager::AuthorisationException.new("download failed. You don't have the permission to download the repo_item '#{repo_item.name}'")
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def download(repo_item, options = {})
|
226
|
+
begin
|
227
|
+
download!(repo_item, options)
|
228
|
+
rescue RepositoryManager::AuthorisationException
|
229
|
+
false
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# Rename the repo_item with the new_name
|
234
|
+
def rename_repo_item!(repo_item, new_name)
|
235
|
+
unless can_update?(repo_item)
|
236
|
+
raise RepositoryManager::AuthorisationException.new("rename repo_item failed. You don't have the permission to update the repo_item '#{repo_item.name}'")
|
237
|
+
end
|
238
|
+
repo_item.rename(new_name)
|
239
|
+
end
|
240
|
+
|
241
|
+
# Rename the repo_item with the new_name
|
242
|
+
def rename_repo_item(repo_item, new_name)
|
243
|
+
begin
|
244
|
+
rename_repo_item!(repo_item, new_name)
|
245
|
+
rescue RepositoryManager::AuthorisationException
|
246
|
+
false
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
# Move the repo_item in the target_folder
|
251
|
+
def move_repo_item!(repo_item, target_folder)
|
252
|
+
unless can_delete?(repo_item)
|
253
|
+
raise RepositoryManager::AuthorisationException.new("move repo_item failed. You don't have the permission to delete the repo_item '#{repo_item.name}'")
|
254
|
+
end
|
255
|
+
unless can_create?(target_folder)
|
256
|
+
raise RepositoryManager::AuthorisationException.new("move repo_item failed. You don't have the permission to create in the target_folder '#{target_folder.name}'")
|
257
|
+
end
|
258
|
+
# If it has the permission, we move the repo_item in the target_folder
|
259
|
+
repo_item.move(target_folder)
|
260
|
+
end
|
261
|
+
|
262
|
+
def move_repo_item(repo_item, target_folder)
|
263
|
+
begin
|
264
|
+
move_repo_item!(repo_item, target_folder)
|
265
|
+
rescue RepositoryManager::AuthorisationException
|
266
|
+
false
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
# Delete the download folder of the user
|
271
|
+
def delete_download_path
|
272
|
+
FileUtils.rm_rf(self.get_default_download_path())
|
273
|
+
end
|
274
|
+
|
275
|
+
#Return the authorisations of the sharing (can_add, can_remove)
|
276
|
+
def get_sharing_authorisations(sharing)
|
277
|
+
sharing.get_authorisations(self)
|
278
|
+
end
|
279
|
+
|
280
|
+
# Return true if you can share the repo, else false
|
281
|
+
# You can give the authorisations or the repo_item as params
|
282
|
+
def can_share?(repo_item, authorisations = nil)
|
283
|
+
can_do?('share', repo_item, authorisations)
|
284
|
+
end
|
285
|
+
|
286
|
+
# Return true if you can read the repo, else false
|
287
|
+
def can_read?(repo_item, authorisations = nil)
|
288
|
+
can_do?('read', repo_item, authorisations)
|
289
|
+
end
|
290
|
+
|
291
|
+
# Return true if you can download the repo, else false
|
292
|
+
# Read = Download for the moment
|
293
|
+
def can_download?(repo_item, authorisations = nil)
|
294
|
+
can_do?('read', repo_item, authorisations)
|
295
|
+
end
|
296
|
+
|
297
|
+
# Return true if you can create in the repo, false else
|
298
|
+
def can_create?(repo_item, authorisations = nil)
|
299
|
+
can_do?('create', repo_item, authorisations)
|
300
|
+
end
|
301
|
+
|
302
|
+
# Returns true if you can edit the repo, false else
|
303
|
+
def can_update?(repo_item, authorisations = nil)
|
304
|
+
can_do?('update', repo_item, authorisations)
|
305
|
+
end
|
306
|
+
|
307
|
+
# Returns true if you can delete the repo, false else
|
308
|
+
def can_delete?(repo_item, authorisations = nil)
|
309
|
+
can_do?('delete', repo_item, authorisations)
|
310
|
+
end
|
311
|
+
|
312
|
+
## Returns true if it exist a sharing in the ancestors of descendant_ids of the repo_item (without itself)
|
313
|
+
#def has_sharing?(repo_item)
|
314
|
+
# # An array with the ids of all ancestors and descendants
|
315
|
+
# ancestor_and_descendant_ids = []
|
316
|
+
# ancestor_and_descendant_ids << repo_item.descendant_ids if !repo_item.descendant_ids.empty?
|
317
|
+
# ancestor_and_descendant_ids << repo_item.ancestor_ids if !repo_item.ancestor_ids.empty?
|
318
|
+
#
|
319
|
+
# # If it is a sharing, it returns true
|
320
|
+
# if self.sharings.where(repo_item_id: ancestor_and_descendant_ids).count > 0
|
321
|
+
# true
|
322
|
+
# else
|
323
|
+
# false
|
324
|
+
# end
|
325
|
+
#
|
326
|
+
#end
|
327
|
+
|
328
|
+
# Return true if you can add a member in this sharing, false else
|
329
|
+
def can_add_to?(sharing)
|
330
|
+
can_do_to?('add', sharing)
|
331
|
+
end
|
332
|
+
|
333
|
+
# Return true if you can remove a member in this sharing, false else
|
334
|
+
def can_remove_from?(sharing)
|
335
|
+
can_do_to?('remove', sharing)
|
336
|
+
end
|
337
|
+
|
338
|
+
# You can here add new members in the sharing
|
339
|
+
# Param member could be an object or an array of object
|
340
|
+
def add_members_to!(sharing, members, options = RepositoryManager.default_sharing_permissions)
|
341
|
+
authorisations = get_sharing_authorisations(sharing)
|
342
|
+
if can_add_to?(sharing)
|
343
|
+
sharing_permissions = make_sharing_permissions(options, authorisations)
|
344
|
+
sharing.add_members(members, sharing_permissions)
|
345
|
+
else
|
346
|
+
raise RepositoryManager::AuthorisationException.new("add members failed. You don't have the permission to add a member in this sharing")
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
def add_members_to(sharing, members, options = RepositoryManager.default_sharing_permissions)
|
351
|
+
begin
|
352
|
+
add_members_to!(sharing, members, options = RepositoryManager.default_sharing_permissions)
|
353
|
+
rescue RepositoryManager::AuthorisationException
|
354
|
+
false
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
# You can here add new members in the sharing
|
359
|
+
# Param member could be an object or an array of object
|
360
|
+
def remove_members_from!(sharing, members)
|
361
|
+
if can_remove_from?(sharing)
|
362
|
+
sharing.remove_members(members)
|
363
|
+
else
|
364
|
+
raise RepositoryManager::AuthorisationException.new("remove members failed. You don't have the permission to remove a member on this sharing")
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
def remove_members_from(sharing, members)
|
369
|
+
begin
|
370
|
+
remove_members_from!(sharing, members)
|
371
|
+
rescue RepositoryManager::AuthorisationException
|
372
|
+
false
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
# Get the download path of the member
|
377
|
+
def get_default_download_path(prefix = 'download/')
|
378
|
+
"#{prefix}#{self.class.to_s.underscore}/#{self.id}/"
|
379
|
+
end
|
380
|
+
|
381
|
+
private
|
382
|
+
|
383
|
+
# Return if you can do or not this action in the sharing
|
384
|
+
def can_do_to?(what, sharing, authorisations = nil)
|
385
|
+
if authorisations == nil
|
386
|
+
authorisations = sharing.get_authorisations(self)
|
387
|
+
end
|
388
|
+
case what
|
389
|
+
when 'add'
|
390
|
+
authorisations == true || (authorisations.kind_of?(Hash) && authorisations[:can_add] == true)
|
391
|
+
when 'remove'
|
392
|
+
authorisations == true || (authorisations.kind_of?(Hash) && authorisations[:can_remove] == true)
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
# Return if you can do or not this action (what)
|
397
|
+
def can_do?(what, repo_item, authorisations = nil)
|
398
|
+
# If we pass no authorisations we have to get it
|
399
|
+
if authorisations == nil
|
400
|
+
authorisations = get_authorisations(repo_item)
|
401
|
+
end
|
402
|
+
|
403
|
+
case what
|
404
|
+
when 'read'
|
405
|
+
authorisations == true || (authorisations.kind_of?(Hash) && authorisations[:can_read] == true)
|
406
|
+
when 'delete'
|
407
|
+
if RepositoryManager.accept_nested_sharing
|
408
|
+
# TODO implement to look if he can delete all the folder
|
409
|
+
else
|
410
|
+
authorisations == true || (authorisations.kind_of?(Hash) && authorisations[:can_delete] == true)
|
411
|
+
end
|
412
|
+
when 'update'
|
413
|
+
authorisations == true || (authorisations.kind_of?(Hash) && authorisations[:can_update] == true)
|
414
|
+
when 'share'
|
415
|
+
if RepositoryManager.accept_nested_sharing
|
416
|
+
# TODO implement to look if he can delete all the folder
|
417
|
+
else
|
418
|
+
authorisations == true || (authorisations.kind_of?(Hash) && authorisations[:can_share] == true)
|
419
|
+
end
|
420
|
+
when 'create'
|
421
|
+
if RepositoryManager.accept_nested_sharing
|
422
|
+
# TODO implement to look if he can delete all the folder
|
423
|
+
else
|
424
|
+
authorisations == true || (authorisations.kind_of?(Hash) && authorisations[:can_create] == true)
|
425
|
+
end
|
426
|
+
else
|
427
|
+
false
|
428
|
+
end
|
429
|
+
|
430
|
+
end
|
431
|
+
|
432
|
+
# Correct the repo_item_permissions with the authorisations
|
433
|
+
def make_repo_item_permissions(wanted_permissions, authorisations)
|
434
|
+
# If it is an array, we have restriction in the permissions
|
435
|
+
if authorisations.kind_of?(Hash) && wanted_permissions
|
436
|
+
# Built the sharing with the accepted permissions
|
437
|
+
# We remove the permission if we can't sharing it
|
438
|
+
if wanted_permissions[:can_read] == true && authorisations[:can_read] == false
|
439
|
+
wanted_permissions[:can_read] = false
|
440
|
+
end
|
441
|
+
if wanted_permissions[:can_create] == true && authorisations[:can_create] == false
|
442
|
+
wanted_permissions[:can_create] = false
|
443
|
+
end
|
444
|
+
if wanted_permissions[:can_update] == true && authorisations[:can_update] == false
|
445
|
+
wanted_permissions[:can_update] = false
|
446
|
+
end
|
447
|
+
if wanted_permissions[:can_delete] == true && authorisations[:can_delete] == false
|
448
|
+
wanted_permissions[:can_delete] = false
|
449
|
+
end
|
450
|
+
if wanted_permissions[:can_share] == true && authorisations[:can_share] == false
|
451
|
+
wanted_permissions[:can_share] = false
|
452
|
+
end
|
453
|
+
end
|
454
|
+
return wanted_permissions
|
455
|
+
end
|
456
|
+
|
457
|
+
# Correct the sharing_permissions with the authorisations
|
458
|
+
def make_sharing_permissions(wanted_permissions, authorisations)
|
459
|
+
# If it is an array, we have restriction in the permissions
|
460
|
+
if authorisations.kind_of?(Hash) && wanted_permissions
|
461
|
+
# Built the sharing with the accepted permissions
|
462
|
+
# We remove the permission if we can't share it
|
463
|
+
if wanted_permissions[:can_add] == true && authorisations[:can_add] == false
|
464
|
+
wanted_permissions[:can_add] = false
|
465
|
+
end
|
466
|
+
if wanted_permissions[:can_remove] == true && authorisations[:can_remove] == false
|
467
|
+
wanted_permissions[:can_remove] = false
|
468
|
+
end
|
469
|
+
end
|
470
|
+
return wanted_permissions
|
471
|
+
end
|
472
|
+
|
473
|
+
# Put a default name if none is given
|
474
|
+
def default_folder_name(source_folder)
|
475
|
+
i = ''
|
476
|
+
name = "#{I18n.t 'repository_manager.models.repo_folder.name'}#{i}"
|
477
|
+
# We check if another item has the same name
|
478
|
+
|
479
|
+
if source_folder
|
480
|
+
# We check if another item has the same name
|
481
|
+
until !RepoItem.where(name: name).where(id: source_folder.child_ids).first do
|
482
|
+
if i == ''
|
483
|
+
i = 1
|
484
|
+
end
|
485
|
+
i += 1
|
486
|
+
name = "#{I18n.t 'repository_manager.models.repo_folder.name'}#{i}"
|
487
|
+
end
|
488
|
+
|
489
|
+
else
|
490
|
+
# Si il n'a pas de parent, racine
|
491
|
+
until !RepoItem.where(name: name).where(owner: self).where(ancestry: nil).first do
|
492
|
+
if i == ''
|
493
|
+
i = 1
|
494
|
+
end
|
495
|
+
i += 1
|
496
|
+
name = "#{I18n.t 'repository_manager.models.repo_folder.name'}#{i}"
|
497
|
+
end
|
498
|
+
|
499
|
+
end
|
500
|
+
name
|
501
|
+
end
|
502
|
+
|
503
|
+
end
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
453
507
|
ActiveRecord::Base.send :include, RepositoryManager::HasRepository
|