erp_tech_svcs 3.0.0
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/GPL-3-LICENSE +674 -0
- data/README.rdoc +2 -0
- data/Rakefile +30 -0
- data/app/assets/javascripts/erp_tech_svcs/application.js +9 -0
- data/app/assets/stylesheets/erp_tech_svcs/application.css +7 -0
- data/app/controllers/erp_tech_svcs/session_controller.rb +19 -0
- data/app/controllers/erp_tech_svcs/user_controller.rb +40 -0
- data/app/helpers/erp_tech_svcs/application_helper.rb +4 -0
- data/app/mailers/user_mailer.rb +16 -0
- data/app/models/audit_log.rb +60 -0
- data/app/models/audit_log_item.rb +4 -0
- data/app/models/audit_log_item_type.rb +6 -0
- data/app/models/audit_log_type.rb +24 -0
- data/app/models/capability.rb +8 -0
- data/app/models/capability_type.rb +3 -0
- data/app/models/capable_model.rb +4 -0
- data/app/models/encryption_key.rb +9 -0
- data/app/models/extensions/contact_purpose.rb +3 -0
- data/app/models/extensions/contact_type.rb +3 -0
- data/app/models/extensions/note.rb +6 -0
- data/app/models/extensions/note_type.rb +3 -0
- data/app/models/extensions/party.rb +3 -0
- data/app/models/extensions/relationship_type.rb +3 -0
- data/app/models/extensions/role_type.rb +3 -0
- data/app/models/file_asset.rb +178 -0
- data/app/models/role.rb +17 -0
- data/app/models/secured_model.rb +13 -0
- data/app/models/user.rb +33 -0
- data/app/views/layouts/application.html.erb +14 -0
- data/app/views/layouts/erp_tech_svcs/application.html.erb +14 -0
- data/app/views/user_mailer/activation_needed_email.html.erb +14 -0
- data/app/views/user_mailer/reset_password_email.html.erb +14 -0
- data/config/initializers/erp_tech_svcs.rb +7 -0
- data/config/initializers/file_support.rb +1 -0
- data/config/initializers/pdfkit.rb +18 -0
- data/config/initializers/sorcery.rb +199 -0
- data/config/routes.rb +9 -0
- data/db/data_migrations/20110802200222_schedule_delete_expired_sessions_job.rb +15 -0
- data/db/data_migrations/20111111144706_setup_audit_log_types.rb +21 -0
- data/db/migrate/20080805000010_base_tech_services.rb +247 -0
- data/db/migrate/20111109161549_add_capabilites.rb +56 -0
- data/db/migrate/upgrade/20111109161550_update_roles.rb +33 -0
- data/db/migrate/upgrade/20111109161551_update_user.rb +88 -0
- data/lib/erp_tech_svcs/application_installer.rb +102 -0
- data/lib/erp_tech_svcs/config.rb +27 -0
- data/lib/erp_tech_svcs/engine.rb +14 -0
- data/lib/erp_tech_svcs/extensions/active_record/acts_as_versioned.rb +494 -0
- data/lib/erp_tech_svcs/extensions/active_record/has_capabilities.rb +139 -0
- data/lib/erp_tech_svcs/extensions/active_record/has_file_assets.rb +40 -0
- data/lib/erp_tech_svcs/extensions/active_record/has_roles.rb +126 -0
- data/lib/erp_tech_svcs/extensions.rb +5 -0
- data/lib/erp_tech_svcs/file_support/aws_s3_patch.rb +3 -0
- data/lib/erp_tech_svcs/file_support/base.rb +30 -0
- data/lib/erp_tech_svcs/file_support/file_manipulator.rb +37 -0
- data/lib/erp_tech_svcs/file_support/file_system_manager.rb +167 -0
- data/lib/erp_tech_svcs/file_support/manager.rb +147 -0
- data/lib/erp_tech_svcs/file_support/paperclip_patch.rb +28 -0
- data/lib/erp_tech_svcs/file_support/railties/s3_resolver.rb +79 -0
- data/lib/erp_tech_svcs/file_support/s3_manager.rb +211 -0
- data/lib/erp_tech_svcs/file_support.rb +10 -0
- data/lib/erp_tech_svcs/sessions/delete_expired_sessions_job.rb +40 -0
- data/lib/erp_tech_svcs/sessions/delete_expired_sessions_service.rb +15 -0
- data/lib/erp_tech_svcs/utils/attachment_fu_patch.rb +15 -0
- data/lib/erp_tech_svcs/utils/compass_access_negotiator.rb +57 -0
- data/lib/erp_tech_svcs/utils/compass_logger.rb +94 -0
- data/lib/erp_tech_svcs/utils/compass_pdf.rb +72 -0
- data/lib/erp_tech_svcs/utils/default_nested_set_methods.rb +33 -0
- data/lib/erp_tech_svcs/utils/pdf_processor.rb +106 -0
- data/lib/erp_tech_svcs/version.rb +3 -0
- data/lib/erp_tech_svcs.rb +20 -0
- data/lib/tasks/erp_tech_svcs_tasks.rake +42 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +9 -0
- data/spec/dummy/app/assets/stylesheets/application.css +7 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config/application.rb +43 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +8 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/spec.rb +27 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +10 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +12 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/schema.rb +571 -0
- data/spec/dummy/db/spec.sqlite3 +0 -0
- data/spec/dummy/log/spec.log +2862 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +26 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/factories/capability_type.rb +5 -0
- data/spec/factories/role.rb +5 -0
- data/spec/factories/users.rb +9 -0
- data/spec/lib/erp_tech_svcs/extensions/active_record/has_roles_spec.rb +68 -0
- data/spec/models/audit_log_spec.rb +48 -0
- data/spec/models/audit_log_type_spec.rb +9 -0
- data/spec/models/role_spec.rb +17 -0
- data/spec/models/user_spec.rb +27 -0
- data/spec/spec_helper.rb +61 -0
- metadata +273 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
module ErpTechSvcs
|
|
2
|
+
module Extensions
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module HasCapabilities
|
|
5
|
+
|
|
6
|
+
def self.included(base)
|
|
7
|
+
base.extend(ClassMethods)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
module ClassMethods
|
|
11
|
+
|
|
12
|
+
def has_capabilities
|
|
13
|
+
extend HasCapabilities::SingletonMethods
|
|
14
|
+
include HasCapabilities::InstanceMethods
|
|
15
|
+
|
|
16
|
+
after_initialize :initialize_capable_model
|
|
17
|
+
after_update :save_capable_model
|
|
18
|
+
after_create :save_capable_model
|
|
19
|
+
after_destroy :destroy_capable_model
|
|
20
|
+
|
|
21
|
+
has_one :capable_model, :as => :capable_model_record
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
module SingletonMethods
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
module InstanceMethods
|
|
29
|
+
def capabilities
|
|
30
|
+
capable_model.capabilities
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def available_capability_resources
|
|
34
|
+
capabilities.collect{|capability| capability.resource}.uniq
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def capabilites_by_resource(resource)
|
|
38
|
+
self.capabilities.where('resource = ?', resource)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def user_has_capability?(capability_type, resource, user)
|
|
42
|
+
capability_type = convert_capability_type(capability_type)
|
|
43
|
+
raise ErpTechSvcs::Utils::CompassAccessNegotiator::Errors::CapabilityTypeDoesNotExist if capability_type.nil?
|
|
44
|
+
|
|
45
|
+
capability = self.capabilities.where('capability_type_id = ? and resource = ?', capability_type.id, resource).first
|
|
46
|
+
unless capability.nil?
|
|
47
|
+
capability.has_access?(user)
|
|
48
|
+
else
|
|
49
|
+
raise ErpTechSvcs::Utils::CompassAccessNegotiator::Errors::CapabilityDoesNotExist
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def add_capability(capability_type, resource, *roles)
|
|
54
|
+
capability_type = convert_capability_type(capability_type)
|
|
55
|
+
raise ErpTechSvcs::Utils::CompassAccessNegotiator::Errors::CapabilityTypeDoesNotExist if capability_type.nil?
|
|
56
|
+
|
|
57
|
+
capability = self.capabilities.where('capability_type_id = ? and resource = ?', capability_type.id, resource).first
|
|
58
|
+
if capability.nil?
|
|
59
|
+
capability = Capability.create(:capability_type => capability_type, :resource => resource)
|
|
60
|
+
capability.add_roles(roles)
|
|
61
|
+
self.capable_model.capabilities << capability
|
|
62
|
+
self.capable_model.save
|
|
63
|
+
else
|
|
64
|
+
raise ErpTechSvcs::Utils::CompassAccessNegotiator::Errors::CapabilityAlreadytExists
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
capability
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def update_capability(capability_type, resource, *roles)
|
|
71
|
+
capability_type = convert_capability_type(capability_type)
|
|
72
|
+
raise ErpTechSvcs::Utils::CompassAccessNegotiator::Errors::CapabilityTypeDoesNotExist if capability_type.nil?
|
|
73
|
+
|
|
74
|
+
capability = self.capabilities.where('capability_type_id = ? and resource = ?', capability_type.id, resource).first
|
|
75
|
+
unless capability.nil?
|
|
76
|
+
capability.remove_all_roles
|
|
77
|
+
capability.add_roles(roles)
|
|
78
|
+
else
|
|
79
|
+
raise ErpTechSvcs::Utils::CompassAccessNegotiator::Errors::CapabilityDoesNotExist
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def remove_all_capabilities
|
|
84
|
+
self.capabilities.each do |capability|
|
|
85
|
+
remove_capability(capability.type, capability.resource)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def remove_capability(capability_type, resource)
|
|
90
|
+
capability_type = convert_capability_type(capability_type)
|
|
91
|
+
raise ErpTechSvcs::Utils::CompassAccessNegotiator::Errors::CapabilityTypeDoesNotExist if capability_type.nil?
|
|
92
|
+
|
|
93
|
+
capability = self.capabilities.where('capability_type_id = ? and resource = ?', capability_type.id, resource).first
|
|
94
|
+
unless capability.nil?
|
|
95
|
+
capability.destroy
|
|
96
|
+
else
|
|
97
|
+
raise ErpTechSvcs::Utils::CompassAccessNegotiator::Errors::CapabilityDoesNotExist
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def capabilites_to_hash
|
|
102
|
+
self.capabilities.map do|capability|
|
|
103
|
+
{
|
|
104
|
+
:capability_type_iid => capability.type.internal_identifier,
|
|
105
|
+
:resource => capability.resource,
|
|
106
|
+
:roles => capability.roles.collect{|role| role.internal_identifier}
|
|
107
|
+
}
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def initialize_capable_model
|
|
112
|
+
if self.capable_model.nil?
|
|
113
|
+
capable_model = CapableModel.new
|
|
114
|
+
self.capable_model = capable_model
|
|
115
|
+
capable_model.capable_model_record = self
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def save_capable_model
|
|
120
|
+
capable_model.save
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def destroy_capable_model
|
|
124
|
+
if self.capable_model && !self.capable_model.frozen?
|
|
125
|
+
self.capable_model.destroy
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
private
|
|
130
|
+
|
|
131
|
+
def convert_capability_type(type)
|
|
132
|
+
CapabilityType.find_by_internal_identifier(type.to_s) if (type.is_a?(String) || type.is_a?(Symbol))
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module ErpTechSvcs
|
|
2
|
+
module Extensions
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module HasFileAssets
|
|
5
|
+
|
|
6
|
+
def self.included(base)
|
|
7
|
+
base.extend(ClassMethods)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
module ClassMethods
|
|
11
|
+
def has_file_assets
|
|
12
|
+
extend HasFileAssets::SingletonMethods
|
|
13
|
+
include HasFileAssets::InstanceMethods
|
|
14
|
+
|
|
15
|
+
has_many :files, :as => :file_asset_holder, :class_name => 'FileAsset', :dependent => :delete_all
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
module SingletonMethods
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
module InstanceMethods
|
|
23
|
+
|
|
24
|
+
def add_file(data, path=nil)
|
|
25
|
+
FileAsset.create!(:file_asset_holder => self, :base_path => path, :data => data)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def images
|
|
29
|
+
self.files.where('type = ?', 'Image')
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def templates
|
|
33
|
+
self.files.where('type = ?', 'Template')
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
module ErpTechSvcs
|
|
2
|
+
module Extensions
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
module HasRoles
|
|
5
|
+
|
|
6
|
+
module Errors
|
|
7
|
+
exceptions = %w[UserDoesNotHaveAccess]
|
|
8
|
+
exceptions.each { |e| const_set(e, Class.new(StandardError)) }
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.included(base)
|
|
12
|
+
base.extend(ClassMethods)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module ClassMethods
|
|
16
|
+
def has_roles
|
|
17
|
+
extend HasRoles::SingletonMethods
|
|
18
|
+
include HasRoles::InstanceMethods
|
|
19
|
+
|
|
20
|
+
after_initialize :initialize_secured_model
|
|
21
|
+
after_update :save_secured_model
|
|
22
|
+
after_create :save_secured_model
|
|
23
|
+
after_destroy :destroy_secured_model
|
|
24
|
+
|
|
25
|
+
has_one :secured_model, :as => :secured_record
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
module SingletonMethods
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
module InstanceMethods
|
|
33
|
+
def roles
|
|
34
|
+
self.secured_model.roles
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def has_access?(user)
|
|
38
|
+
has_access = true
|
|
39
|
+
unless self.secured_model.roles.empty?
|
|
40
|
+
has_access = if user.nil?
|
|
41
|
+
false
|
|
42
|
+
else
|
|
43
|
+
user.has_role?(self.secured_model.roles.collect{|item| item.internal_identifier})
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
has_access
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def with_access(user, &block)
|
|
50
|
+
if has_access?(user)
|
|
51
|
+
yield
|
|
52
|
+
else
|
|
53
|
+
raise ErpTechSvcs::Extensions::ActiveRecord::HasRoles::UserDoesNotHaveAccess
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def add_role(role)
|
|
58
|
+
role = Role.find_by_internal_identifier(role) if role.is_a? String
|
|
59
|
+
unless self.has_role?(role)
|
|
60
|
+
self.secured_model.roles << role
|
|
61
|
+
self.secured_model.save
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def add_roles(*roles)
|
|
66
|
+
roles.flatten!
|
|
67
|
+
roles = roles[0] if roles[0].is_a? Array
|
|
68
|
+
roles.each do |role|
|
|
69
|
+
self.add_role(role)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def remove_role(role)
|
|
74
|
+
role = Role.find_by_internal_identifier(role) if role.is_a? String
|
|
75
|
+
self.secured_model.roles.delete(role) if has_role?(role)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def remove_roles(*roles)
|
|
79
|
+
roles.flatten!
|
|
80
|
+
roles.each do |role|
|
|
81
|
+
self.remove_role(role)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def remove_all_roles
|
|
86
|
+
self.roles.delete_all
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def has_role?(*passed_roles)
|
|
90
|
+
result = false
|
|
91
|
+
passed_roles.flatten!
|
|
92
|
+
passed_roles.each do |role|
|
|
93
|
+
role_iid = (role.is_a?(String)) ? role : role.internal_identifier
|
|
94
|
+
self.roles.each do |this_role|
|
|
95
|
+
result = true if (this_role.internal_identifier == role_iid)
|
|
96
|
+
break if result
|
|
97
|
+
end
|
|
98
|
+
break if result
|
|
99
|
+
end
|
|
100
|
+
result
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def initialize_secured_model
|
|
104
|
+
if self.new_record? && self.secured_model.nil?
|
|
105
|
+
secured_model = SecuredModel.new
|
|
106
|
+
self.secured_model = secured_model
|
|
107
|
+
secured_model.secured_record = self
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def save_secured_model
|
|
112
|
+
secured_model.save
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def destroy_secured_model
|
|
116
|
+
if self.secured_model && !self.secured_model.frozen?
|
|
117
|
+
self.secured_model.destroy
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
#active record extensions
|
|
2
|
+
require 'erp_tech_svcs/extensions/active_record/has_file_assets'
|
|
3
|
+
require 'erp_tech_svcs/extensions/active_record/has_roles'
|
|
4
|
+
require 'erp_tech_svcs/extensions/active_record/has_capabilities'
|
|
5
|
+
require 'erp_tech_svcs/extensions/active_record/acts_as_versioned'
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module ErpTechSvcs
|
|
2
|
+
module FileSupport
|
|
3
|
+
DEFAULT_OPTIONS = {
|
|
4
|
+
:storage => :filesystem
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
mattr_accessor :options
|
|
8
|
+
@@options = HashWithIndifferentAccess.new(DEFAULT_OPTIONS)
|
|
9
|
+
|
|
10
|
+
class Base
|
|
11
|
+
attr_accessor :storage
|
|
12
|
+
|
|
13
|
+
def initialize(options={})
|
|
14
|
+
@storage = options[:storage].nil? ? :filesystem : options[:storage]
|
|
15
|
+
|
|
16
|
+
case @storage
|
|
17
|
+
when :s3
|
|
18
|
+
@manager = S3Manager.new
|
|
19
|
+
when :filesystem
|
|
20
|
+
@manager = FileSystemManager.new
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def method_missing(m, *args, &block)
|
|
25
|
+
@manager.respond_to?(m) ? @manager.send(m, *args) : super
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module ErpTechSvcs
|
|
2
|
+
class FileManipulator
|
|
3
|
+
class << self
|
|
4
|
+
|
|
5
|
+
def patch_file(path, current, insert, options = {})
|
|
6
|
+
options = {
|
|
7
|
+
:patch_mode => :insert_after
|
|
8
|
+
}.merge(options)
|
|
9
|
+
|
|
10
|
+
old_text = current
|
|
11
|
+
new_text = patch_string(current, insert, options[:patch_mode])
|
|
12
|
+
|
|
13
|
+
content = File.open(path) { |f| f.read }
|
|
14
|
+
content.gsub!(old_text, new_text) unless content =~ /#{Regexp.escape(insert)}/mi
|
|
15
|
+
File.open(path, 'w') { |f| f.puts(content) }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def append_file(path, content)
|
|
19
|
+
File.open(path, 'a') { |f| f.puts(content) }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def patch_string(current, insert, mode = :insert_after)
|
|
23
|
+
case mode
|
|
24
|
+
when :change
|
|
25
|
+
"#{insert}"
|
|
26
|
+
when :insert_after
|
|
27
|
+
"#{current}\n#{insert}"
|
|
28
|
+
when :insert_before
|
|
29
|
+
"#{insert}\n#{current}"
|
|
30
|
+
else
|
|
31
|
+
patch_string(current, insert, :insert_after)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
module ErpTechSvcs
|
|
2
|
+
module FileSupport
|
|
3
|
+
class FileSystemManager < Manager
|
|
4
|
+
REMOVE_FILES_REGEX = /^\./
|
|
5
|
+
|
|
6
|
+
def root
|
|
7
|
+
File.join(Rails.root,'public')
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def update_file(path, content)
|
|
11
|
+
File.open(path, 'w+') {|f| f.puts(content) }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def create_file(path, name, contents)
|
|
15
|
+
FileUtils.mkdir_p path unless File.exists? path
|
|
16
|
+
File.open(File.join(path,name), 'w+') {|f| f.puts(contents) }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def create_folder(path, name)
|
|
20
|
+
FileUtils.mkdir_p File.join(path,name) unless File.directory? File.join(path,name)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def save_move(path, new_parent_path)
|
|
24
|
+
result = nil
|
|
25
|
+
unless File.exists? path
|
|
26
|
+
message = 'File does not exists'
|
|
27
|
+
else
|
|
28
|
+
name = File.basename(path)
|
|
29
|
+
#make sure path is there.
|
|
30
|
+
FileUtils.mkdir_p new_parent_path unless File.directory? new_parent_path
|
|
31
|
+
FileUtils.mv(path, new_parent_path + '/' + name)
|
|
32
|
+
message = "#{name} was moved to #{new_parent_path} successfully"
|
|
33
|
+
result = true
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
return result, message
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def exists?(path)
|
|
40
|
+
File.exists? path
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def rename_file(path, name)
|
|
44
|
+
result = nil
|
|
45
|
+
unless File.exists? path
|
|
46
|
+
message = 'File does not exists'
|
|
47
|
+
else
|
|
48
|
+
old_name = File.basename(path)
|
|
49
|
+
path_pieces = path.split('/')
|
|
50
|
+
path_pieces.delete(path_pieces.last)
|
|
51
|
+
path_pieces.push(name)
|
|
52
|
+
new_path = path_pieces.join('/')
|
|
53
|
+
File.rename(path, new_path)
|
|
54
|
+
message = "#{old_name} was renamed to #{name} successfully"
|
|
55
|
+
result = true
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
return result, message
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def delete_file(path, options={})
|
|
62
|
+
result = nil
|
|
63
|
+
name = File.basename(path)
|
|
64
|
+
is_directory = false
|
|
65
|
+
if !File.exists? path and !File.directory? path
|
|
66
|
+
message = 'File / Folder does not exist'
|
|
67
|
+
else
|
|
68
|
+
if File.directory? path
|
|
69
|
+
is_directory = true
|
|
70
|
+
entries = Dir.entries(path)
|
|
71
|
+
entries.delete_if{|entry| entry =~ REMOVE_FILES_REGEX}
|
|
72
|
+
if entries.count > 0 && !options[:force]
|
|
73
|
+
message = "Folder is not empty"
|
|
74
|
+
result = false;
|
|
75
|
+
else
|
|
76
|
+
FileUtils.rm_rf(path)
|
|
77
|
+
message = "Folder #{name} was deleted #{name} successfully"
|
|
78
|
+
result = true
|
|
79
|
+
end
|
|
80
|
+
else
|
|
81
|
+
FileUtils.rm_rf(path)
|
|
82
|
+
message = "File #{name} was deleted #{name} successfully"
|
|
83
|
+
result = true
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
return result, message, is_directory
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def get_contents(path)
|
|
91
|
+
contents = nil
|
|
92
|
+
message = nil
|
|
93
|
+
unless File.exists? path
|
|
94
|
+
message = 'File does not exists'
|
|
95
|
+
else
|
|
96
|
+
contents = IO.read(path)
|
|
97
|
+
end
|
|
98
|
+
return contents, message
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def build_tree(starting_path, options={})
|
|
102
|
+
find_node(starting_path, options)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def find_node(path, options={})
|
|
106
|
+
parent = if options[:file_asset_holder]
|
|
107
|
+
super
|
|
108
|
+
else
|
|
109
|
+
path_pieces = path.split('/')
|
|
110
|
+
parent = build_tree_for_directory(path, options)
|
|
111
|
+
unless parent[:id] == path
|
|
112
|
+
path_pieces.each do |path_piece|
|
|
113
|
+
next if path_piece.blank?
|
|
114
|
+
parent[:children].each do |child_node|
|
|
115
|
+
if child_node[:text] == path_piece
|
|
116
|
+
parent = child_node
|
|
117
|
+
break
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
parent = nil if parent[:id] != path
|
|
124
|
+
parent
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
parent
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
private
|
|
131
|
+
|
|
132
|
+
def build_tree_for_directory(directory, options)
|
|
133
|
+
keep_full_path = nil
|
|
134
|
+
if directory.index(Rails.root.to_s).nil?
|
|
135
|
+
tree_data = {:text => directory.split('/').last, :id => directory, :leaf => false, :children => []}
|
|
136
|
+
else
|
|
137
|
+
keep_full_path = true
|
|
138
|
+
tree_data = {:text => directory.split('/').last, :id => directory, :leaf => false, :children => []}
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
Dir.entries(directory).each do |entry|
|
|
142
|
+
#ignore .svn folders and any other folders starting with .
|
|
143
|
+
next if entry =~ REMOVE_FILES_REGEX
|
|
144
|
+
|
|
145
|
+
path = File.join(directory, entry)
|
|
146
|
+
path.gsub!(root,'') unless keep_full_path
|
|
147
|
+
|
|
148
|
+
if File.directory?(File.join(directory,entry))
|
|
149
|
+
tree_data[:children] << if options[:preload]
|
|
150
|
+
build_tree_for_directory(path, options) if options[:preload]
|
|
151
|
+
else
|
|
152
|
+
{:text => entry, :id => path}
|
|
153
|
+
end
|
|
154
|
+
elsif !options[:included_file_extensions_regex].nil? && entry =~ options[:included_file_extensions_regex]
|
|
155
|
+
tree_data[:children] << {:text => entry, :leaf => true, :downloadPath => path, :id => path}
|
|
156
|
+
elsif options[:included_file_extensions_regex].nil?
|
|
157
|
+
tree_data[:children] << {:text => entry, :leaf => true, :downloadPath => path, :id => path}
|
|
158
|
+
end
|
|
159
|
+
end if File.directory?(directory)
|
|
160
|
+
|
|
161
|
+
tree_data[:children].sort_by{|item| [item[:id]]}
|
|
162
|
+
tree_data
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
end#FileSystemManager
|
|
166
|
+
end#FileSupport
|
|
167
|
+
end#ErpTechSvcs
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
module ErpTechSvcs
|
|
2
|
+
module FileSupport
|
|
3
|
+
class Manager
|
|
4
|
+
|
|
5
|
+
class << self
|
|
6
|
+
def find_parent(item, parents)
|
|
7
|
+
parents.find do |parent|
|
|
8
|
+
path = item[:path].gsub(item[:text],'').split('/').join('/')
|
|
9
|
+
parent[:id] == path
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def sync(path, model)
|
|
15
|
+
result = nil
|
|
16
|
+
message = nil
|
|
17
|
+
|
|
18
|
+
node = find_node(path)
|
|
19
|
+
if node.nil?
|
|
20
|
+
message = "Nothing to sync"
|
|
21
|
+
else
|
|
22
|
+
sync_node(node, model)
|
|
23
|
+
message = "Sync successful"
|
|
24
|
+
result = true
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
return result, message
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def find_node(path, options={})
|
|
31
|
+
node_tree = build_file_assets_tree_for_model(options[:file_asset_holder], path.gsub(root, ''))
|
|
32
|
+
|
|
33
|
+
path_pieces = path.split('/')
|
|
34
|
+
parent = node_tree.first
|
|
35
|
+
path_pieces.each do |path_piece|
|
|
36
|
+
next if path_piece.blank?
|
|
37
|
+
parent[:children].each do |child_node|
|
|
38
|
+
if child_node[:text] == path_piece
|
|
39
|
+
parent = child_node
|
|
40
|
+
break
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
path.sub!(self.root,'') if parent[:id].scan(self.root).empty?
|
|
46
|
+
path = File.join(self.root, path) if !parent[:id].scan(self.root).empty? and path.scan(self.root).empty?
|
|
47
|
+
|
|
48
|
+
parent = [] if parent[:id] != path
|
|
49
|
+
parent
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def build_file_assets_tree_for_model(model, starting_path)
|
|
53
|
+
node_tree = [{:text => root, :leaf => false, :id => root, :children => []}]
|
|
54
|
+
|
|
55
|
+
paths = model.files.collect{|file| File.join(file.directory,file.name)}
|
|
56
|
+
|
|
57
|
+
node_tree.first[:children] << {:id => starting_path, :text => starting_path.split('/').last, :children => []} if paths.select{|path| path.split('/')[1] == starting_path.split('/')[1]}.empty?
|
|
58
|
+
|
|
59
|
+
nesting_depth = paths.collect{|item| item.split('/').count}.max
|
|
60
|
+
unless nesting_depth.nil?
|
|
61
|
+
levels = []
|
|
62
|
+
(1..nesting_depth).each do |i|
|
|
63
|
+
current_items = []
|
|
64
|
+
objects_this_depth = paths.collect{|item|
|
|
65
|
+
text = item.split('/')[i - 1]
|
|
66
|
+
path = item.split('/')[0..(i-1)].join('/')
|
|
67
|
+
if item.split('/').count >= i && current_items.select{|item| item[:text] == text and item[:path] == path}.empty?
|
|
68
|
+
item_hash = {:text => text, :path => path}
|
|
69
|
+
current_items << item_hash
|
|
70
|
+
item_hash
|
|
71
|
+
end
|
|
72
|
+
}
|
|
73
|
+
objects_this_depth.delete_if{|item| (item.nil? or item[:text].blank?)}
|
|
74
|
+
levels << objects_this_depth unless objects_this_depth.empty?
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
old_parents = []
|
|
78
|
+
new_parents = [node_tree[0]]
|
|
79
|
+
levels.each do |level|
|
|
80
|
+
old_parents = new_parents
|
|
81
|
+
new_parents = []
|
|
82
|
+
level.each do |item|
|
|
83
|
+
parent = old_parents.count == 1 ? old_parents.first : self.class.find_parent(item, old_parents)
|
|
84
|
+
path = File.join(parent[:id], item[:text]).gsub(root, '')
|
|
85
|
+
child_hash = {:text => item[:text], :downloadPath => path, :leaf => !File.extname(item[:text]).blank?, :id => path, :children => []}
|
|
86
|
+
new_parents << child_hash
|
|
87
|
+
parent[:children] << child_hash
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
insert_folders(node_tree.first[:children])
|
|
93
|
+
|
|
94
|
+
node_tree
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def insert_folders(file_asset_nodes)
|
|
98
|
+
file_asset_nodes.each do |child_asset_node|
|
|
99
|
+
node = find_node(File.join(self.root,child_asset_node[:id]))
|
|
100
|
+
folders = node[:children].select{|item| !item[:leaf]}
|
|
101
|
+
child_asset_node[:children] = [] if child_asset_node[:children].nil? && !folders.empty?
|
|
102
|
+
folders.each do |folder|
|
|
103
|
+
folder[:id].gsub!(self.root,'')
|
|
104
|
+
child_asset_node[:children] << folder unless child_asset_node[:children].collect{|child_node| child_node[:text] }.include?(folder[:text])
|
|
105
|
+
end
|
|
106
|
+
insert_folders(child_asset_node[:children])
|
|
107
|
+
end unless file_asset_nodes.nil?
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
private
|
|
111
|
+
|
|
112
|
+
def sync_node(node, model)
|
|
113
|
+
leaves = get_all_leaves(node)
|
|
114
|
+
leaves.each do |leaf|
|
|
115
|
+
create_file_asset_for_node(leaf, model)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
model.files.find(:all, :conditions => "directory like '#{node[:id].sub(self.root, '')}%'").each do |file_asset|
|
|
119
|
+
unless self.exists? File.join(self.root, file_asset.directory, file_asset.name)
|
|
120
|
+
puts "File #{File.join(self.root, file_asset.directory, file_asset.name)} does not exists removing"
|
|
121
|
+
file_asset.destroy
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def get_all_leaves(node)
|
|
127
|
+
node[:children].map{|child_node| child_node[:leaf] ? child_node : get_all_leaves(child_node) }.flatten
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def create_file_asset_for_node(node, model)
|
|
131
|
+
name = File.basename(node[:id])
|
|
132
|
+
directory = File.dirname(node[:id])
|
|
133
|
+
file_asset = model.files.find(:first, :conditions => ['directory = ? and name = ?', directory, name])
|
|
134
|
+
|
|
135
|
+
if file_asset.nil?
|
|
136
|
+
contents = get_contents(node[:id]).to_s
|
|
137
|
+
begin
|
|
138
|
+
model.add_file(contents, node[:id])
|
|
139
|
+
rescue Exception=>ex
|
|
140
|
+
#the file might already exist if it is in the file system.
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
end#Manager
|
|
146
|
+
end#FileSupport
|
|
147
|
+
end#ErpTechSvcs
|