drg_elfinder 0.1.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.
Files changed (185) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +28 -0
  4. data/Rakefile +8 -0
  5. data/app/assets/config/drg_elfinder_manifest.js +1 -0
  6. data/app/assets/javascripts/drg_elfinder.js +15 -0
  7. data/app/assets/javascripts/elfinder/Changelog +1283 -0
  8. data/app/assets/javascripts/elfinder/LICENSE.md +15 -0
  9. data/app/assets/javascripts/elfinder/README.md +216 -0
  10. data/app/assets/javascripts/elfinder/bower.json +28 -0
  11. data/app/assets/javascripts/elfinder/composer.json +39 -0
  12. data/app/assets/javascripts/elfinder/css/elfinder.full.css +5350 -0
  13. data/app/assets/javascripts/elfinder/css/elfinder.min.css +9 -0
  14. data/app/assets/javascripts/elfinder/css/theme.css +430 -0
  15. data/app/assets/javascripts/elfinder/elfinder.html +74 -0
  16. data/app/assets/javascripts/elfinder/elfinder.legacy.html +94 -0
  17. data/app/assets/javascripts/elfinder/img/arrows-active.png +0 -0
  18. data/app/assets/javascripts/elfinder/img/arrows-normal.png +0 -0
  19. data/app/assets/javascripts/elfinder/img/crop.gif +0 -0
  20. data/app/assets/javascripts/elfinder/img/dialogs.png +0 -0
  21. data/app/assets/javascripts/elfinder/img/edit_aceeditor.png +0 -0
  22. data/app/assets/javascripts/elfinder/img/edit_ckeditor.png +0 -0
  23. data/app/assets/javascripts/elfinder/img/edit_ckeditor5.png +0 -0
  24. data/app/assets/javascripts/elfinder/img/edit_codemirror.png +0 -0
  25. data/app/assets/javascripts/elfinder/img/edit_creativecloud.png +0 -0
  26. data/app/assets/javascripts/elfinder/img/edit_onlineconvert.png +0 -0
  27. data/app/assets/javascripts/elfinder/img/edit_pixlreditor.png +0 -0
  28. data/app/assets/javascripts/elfinder/img/edit_pixlrexpress.png +0 -0
  29. data/app/assets/javascripts/elfinder/img/edit_simplemde.png +0 -0
  30. data/app/assets/javascripts/elfinder/img/edit_tinymce.png +0 -0
  31. data/app/assets/javascripts/elfinder/img/edit_tuiimgedit.png +0 -0
  32. data/app/assets/javascripts/elfinder/img/edit_zohooffice.png +0 -0
  33. data/app/assets/javascripts/elfinder/img/editor-icons.png +0 -0
  34. data/app/assets/javascripts/elfinder/img/icons-big.png +0 -0
  35. data/app/assets/javascripts/elfinder/img/icons-big.svg +1 -0
  36. data/app/assets/javascripts/elfinder/img/icons-small.png +0 -0
  37. data/app/assets/javascripts/elfinder/img/logo.png +0 -0
  38. data/app/assets/javascripts/elfinder/img/progress.gif +0 -0
  39. data/app/assets/javascripts/elfinder/img/quicklook-bg.png +0 -0
  40. data/app/assets/javascripts/elfinder/img/quicklook-icons.png +0 -0
  41. data/app/assets/javascripts/elfinder/img/resize.png +0 -0
  42. data/app/assets/javascripts/elfinder/img/spinner-mini.gif +0 -0
  43. data/app/assets/javascripts/elfinder/img/toolbar.png +0 -0
  44. data/app/assets/javascripts/elfinder/img/trashmesh.png +0 -0
  45. data/app/assets/javascripts/elfinder/img/tui-icon-a.svg +235 -0
  46. data/app/assets/javascripts/elfinder/img/tui-icon-b.svg +224 -0
  47. data/app/assets/javascripts/elfinder/img/tui-icon-c.svg +224 -0
  48. data/app/assets/javascripts/elfinder/img/tui-icon-d.svg +224 -0
  49. data/app/assets/javascripts/elfinder/img/ui-icons_ffffff_256x240.png +0 -0
  50. data/app/assets/javascripts/elfinder/img/volume_icon_box.png +0 -0
  51. data/app/assets/javascripts/elfinder/img/volume_icon_box.svg +1 -0
  52. data/app/assets/javascripts/elfinder/img/volume_icon_dropbox.png +0 -0
  53. data/app/assets/javascripts/elfinder/img/volume_icon_dropbox.svg +1 -0
  54. data/app/assets/javascripts/elfinder/img/volume_icon_ftp.png +0 -0
  55. data/app/assets/javascripts/elfinder/img/volume_icon_ftp.svg +1 -0
  56. data/app/assets/javascripts/elfinder/img/volume_icon_googledrive.png +0 -0
  57. data/app/assets/javascripts/elfinder/img/volume_icon_googledrive.svg +1 -0
  58. data/app/assets/javascripts/elfinder/img/volume_icon_local.png +0 -0
  59. data/app/assets/javascripts/elfinder/img/volume_icon_local.svg +1 -0
  60. data/app/assets/javascripts/elfinder/img/volume_icon_network.png +0 -0
  61. data/app/assets/javascripts/elfinder/img/volume_icon_network.svg +1 -0
  62. data/app/assets/javascripts/elfinder/img/volume_icon_onedrive.png +0 -0
  63. data/app/assets/javascripts/elfinder/img/volume_icon_onedrive.svg +1 -0
  64. data/app/assets/javascripts/elfinder/img/volume_icon_sql.png +0 -0
  65. data/app/assets/javascripts/elfinder/img/volume_icon_sql.svg +1 -0
  66. data/app/assets/javascripts/elfinder/img/volume_icon_trash.png +0 -0
  67. data/app/assets/javascripts/elfinder/img/volume_icon_trash.svg +1 -0
  68. data/app/assets/javascripts/elfinder/img/volume_icon_zip.png +0 -0
  69. data/app/assets/javascripts/elfinder/img/volume_icon_zip.svg +1 -0
  70. data/app/assets/javascripts/elfinder/js/elfinder.full.js +36019 -0
  71. data/app/assets/javascripts/elfinder/js/elfinder.min.js +25 -0
  72. data/app/assets/javascripts/elfinder/js/extras/editors.default.js +2643 -0
  73. data/app/assets/javascripts/elfinder/js/extras/editors.default.min.js +2 -0
  74. data/app/assets/javascripts/elfinder/js/extras/quicklook.googledocs.js +75 -0
  75. data/app/assets/javascripts/elfinder/js/extras/quicklook.googledocs.min.js +1 -0
  76. data/app/assets/javascripts/elfinder/js/i18n/elfinder.LANG.js +587 -0
  77. data/app/assets/javascripts/elfinder/js/i18n/elfinder.ar.js +580 -0
  78. data/app/assets/javascripts/elfinder/js/i18n/elfinder.bg.js +559 -0
  79. data/app/assets/javascripts/elfinder/js/i18n/elfinder.ca.js +375 -0
  80. data/app/assets/javascripts/elfinder/js/i18n/elfinder.cs.js +581 -0
  81. data/app/assets/javascripts/elfinder/js/i18n/elfinder.da.js +580 -0
  82. data/app/assets/javascripts/elfinder/js/i18n/elfinder.de.js +582 -0
  83. data/app/assets/javascripts/elfinder/js/i18n/elfinder.el.js +374 -0
  84. data/app/assets/javascripts/elfinder/js/i18n/elfinder.es.js +546 -0
  85. data/app/assets/javascripts/elfinder/js/i18n/elfinder.fa.js +580 -0
  86. data/app/assets/javascripts/elfinder/js/i18n/elfinder.fallback.js +11 -0
  87. data/app/assets/javascripts/elfinder/js/i18n/elfinder.fo.js +419 -0
  88. data/app/assets/javascripts/elfinder/js/i18n/elfinder.fr.js +578 -0
  89. data/app/assets/javascripts/elfinder/js/i18n/elfinder.fr_CA.js +580 -0
  90. data/app/assets/javascripts/elfinder/js/i18n/elfinder.he.js +375 -0
  91. data/app/assets/javascripts/elfinder/js/i18n/elfinder.hr.js +434 -0
  92. data/app/assets/javascripts/elfinder/js/i18n/elfinder.hu.js +580 -0
  93. data/app/assets/javascripts/elfinder/js/i18n/elfinder.id.js +498 -0
  94. data/app/assets/javascripts/elfinder/js/i18n/elfinder.it.js +552 -0
  95. data/app/assets/javascripts/elfinder/js/i18n/elfinder.ja.js +581 -0
  96. data/app/assets/javascripts/elfinder/js/i18n/elfinder.ko.js +582 -0
  97. data/app/assets/javascripts/elfinder/js/i18n/elfinder.nl.js +581 -0
  98. data/app/assets/javascripts/elfinder/js/i18n/elfinder.no.js +374 -0
  99. data/app/assets/javascripts/elfinder/js/i18n/elfinder.pl.js +580 -0
  100. data/app/assets/javascripts/elfinder/js/i18n/elfinder.pt_BR.js +580 -0
  101. data/app/assets/javascripts/elfinder/js/i18n/elfinder.ro.js +417 -0
  102. data/app/assets/javascripts/elfinder/js/i18n/elfinder.ru.js +582 -0
  103. data/app/assets/javascripts/elfinder/js/i18n/elfinder.si.js +537 -0
  104. data/app/assets/javascripts/elfinder/js/i18n/elfinder.sk.js +581 -0
  105. data/app/assets/javascripts/elfinder/js/i18n/elfinder.sl.js +374 -0
  106. data/app/assets/javascripts/elfinder/js/i18n/elfinder.sr.js +374 -0
  107. data/app/assets/javascripts/elfinder/js/i18n/elfinder.sv.js +375 -0
  108. data/app/assets/javascripts/elfinder/js/i18n/elfinder.tr.js +583 -0
  109. data/app/assets/javascripts/elfinder/js/i18n/elfinder.ug_CN.js +374 -0
  110. data/app/assets/javascripts/elfinder/js/i18n/elfinder.uk.js +580 -0
  111. data/app/assets/javascripts/elfinder/js/i18n/elfinder.vi.js +579 -0
  112. data/app/assets/javascripts/elfinder/js/i18n/elfinder.zh_CN.js +585 -0
  113. data/app/assets/javascripts/elfinder/js/i18n/elfinder.zh_TW.js +582 -0
  114. data/app/assets/javascripts/elfinder/js/i18n/help/cs.html.js +10 -0
  115. data/app/assets/javascripts/elfinder/js/i18n/help/de.html.js +15 -0
  116. data/app/assets/javascripts/elfinder/js/i18n/help/en.html.js +10 -0
  117. data/app/assets/javascripts/elfinder/js/i18n/help/es.html.js +10 -0
  118. data/app/assets/javascripts/elfinder/js/i18n/help/ja.html.js +10 -0
  119. data/app/assets/javascripts/elfinder/js/i18n/help/ko.html.js +10 -0
  120. data/app/assets/javascripts/elfinder/js/i18n/help/pl.html.js +10 -0
  121. data/app/assets/javascripts/elfinder/js/i18n/help/ru.html.js +10 -0
  122. data/app/assets/javascripts/elfinder/js/i18n/help/sk.html.js +10 -0
  123. data/app/assets/javascripts/elfinder/js/i18n/help/tr.html.js +10 -0
  124. data/app/assets/javascripts/elfinder/js/proxy/elFinderSupportVer1.js +408 -0
  125. data/app/assets/javascripts/elfinder/js/worker/calcfilehash.js +20 -0
  126. data/app/assets/javascripts/elfinder/js/worker/quicklook.tiff.js +7 -0
  127. data/app/assets/javascripts/elfinder/js/worker/quicklook.unzip.js +55 -0
  128. data/app/assets/javascripts/elfinder/main.default.js +175 -0
  129. data/app/assets/javascripts/elfinder/package.json +13 -0
  130. data/app/assets/javascripts/elfinder/php/MySQLStorage.sql +47 -0
  131. data/app/assets/javascripts/elfinder/php/autoload.php +56 -0
  132. data/app/assets/javascripts/elfinder/php/connector.maximal.php-dist +449 -0
  133. data/app/assets/javascripts/elfinder/php/connector.minimal.php-dist +180 -0
  134. data/app/assets/javascripts/elfinder/php/editors/OnlineConvert/editor.php +113 -0
  135. data/app/assets/javascripts/elfinder/php/editors/ZipArchive/editor.php +12 -0
  136. data/app/assets/javascripts/elfinder/php/editors/ZohoOffice/editor.php +206 -0
  137. data/app/assets/javascripts/elfinder/php/editors/editor.php +79 -0
  138. data/app/assets/javascripts/elfinder/php/elFinder.class.php +5401 -0
  139. data/app/assets/javascripts/elfinder/php/elFinderConnector.class.php +380 -0
  140. data/app/assets/javascripts/elfinder/php/elFinderFlysystemGoogleDriveNetmount.php +380 -0
  141. data/app/assets/javascripts/elfinder/php/elFinderPlugin.php +113 -0
  142. data/app/assets/javascripts/elfinder/php/elFinderSession.php +335 -0
  143. data/app/assets/javascripts/elfinder/php/elFinderSessionInterface.php +57 -0
  144. data/app/assets/javascripts/elfinder/php/elFinderVolumeBox.class.php +1972 -0
  145. data/app/assets/javascripts/elfinder/php/elFinderVolumeDriver.class.php +7651 -0
  146. data/app/assets/javascripts/elfinder/php/elFinderVolumeDropbox.class.php +1464 -0
  147. data/app/assets/javascripts/elfinder/php/elFinderVolumeDropbox2.class.php +1516 -0
  148. data/app/assets/javascripts/elfinder/php/elFinderVolumeFTP.class.php +1810 -0
  149. data/app/assets/javascripts/elfinder/php/elFinderVolumeGoogleDrive.class.php +2163 -0
  150. data/app/assets/javascripts/elfinder/php/elFinderVolumeGroup.class.php +315 -0
  151. data/app/assets/javascripts/elfinder/php/elFinderVolumeLocalFileSystem.class.php +1477 -0
  152. data/app/assets/javascripts/elfinder/php/elFinderVolumeMySQL.class.php +1022 -0
  153. data/app/assets/javascripts/elfinder/php/elFinderVolumeOneDrive.class.php +2131 -0
  154. data/app/assets/javascripts/elfinder/php/elFinderVolumeSFTPphpseclib.class.php +838 -0
  155. data/app/assets/javascripts/elfinder/php/elFinderVolumeTrash.class.php +51 -0
  156. data/app/assets/javascripts/elfinder/php/elFinderVolumeTrashMySQL.class.php +51 -0
  157. data/app/assets/javascripts/elfinder/php/libs/GdBmp.php +473 -0
  158. data/app/assets/javascripts/elfinder/php/mime.types +781 -0
  159. data/app/assets/javascripts/elfinder/php/plugins/AutoResize/plugin.php +151 -0
  160. data/app/assets/javascripts/elfinder/php/plugins/AutoRotate/plugin.php +148 -0
  161. data/app/assets/javascripts/elfinder/php/plugins/Normalizer/plugin.php +204 -0
  162. data/app/assets/javascripts/elfinder/php/plugins/Sanitizer/plugin.php +157 -0
  163. data/app/assets/javascripts/elfinder/php/plugins/Watermark/logo.png +0 -0
  164. data/app/assets/javascripts/elfinder/php/plugins/Watermark/plugin.php +432 -0
  165. data/app/assets/javascripts/elfinder/php/plugins/WinRemoveTailDots/plugin.php +114 -0
  166. data/app/assets/javascripts/elfinder/php/resources/image.png +0 -0
  167. data/app/assets/javascripts/elfinder/php/resources/video.png +0 -0
  168. data/app/assets/javascripts/elfinder/sounds/rm.wav +0 -0
  169. data/app/controllers/dc_elfinder_controller.rb +63 -0
  170. data/app/models/drgcms_form_fields/elfinder.rb +85 -0
  171. data/changelog.md +0 -0
  172. data/lib/drg_elfinder/engine.rb +5 -0
  173. data/lib/drg_elfinder/version.rb +3 -0
  174. data/lib/drg_elfinder.rb +9 -0
  175. data/lib/el_finder/action.rb +19 -0
  176. data/lib/el_finder/base64.rb +24 -0
  177. data/lib/el_finder/connector.rb +625 -0
  178. data/lib/el_finder/image.rb +33 -0
  179. data/lib/el_finder/mime_type.rb +86 -0
  180. data/lib/el_finder/pathname.rb +185 -0
  181. data/lib/el_finder/version.rb +5 -0
  182. data/lib/el_finder.rb +8 -0
  183. data/lib/patches/patch_for_elfinder.rb +115 -0
  184. data/lib/tasks/drg_elfinder_tasks.rake +10 -0
  185. metadata +245 -0
@@ -0,0 +1,625 @@
1
+ #
2
+ # http://elrte.org/redmine/projects/elfinder/wiki/Client-Server_Protocol_EN
3
+ #
4
+
5
+ require 'base64'
6
+
7
+ module ElFinder
8
+
9
+ # Represents ElFinder connector on Rails side.
10
+ class Connector
11
+
12
+ # Valid commands to run.
13
+ # @see #run
14
+ VALID_COMMANDS = %w[archive duplicate edit extract mkdir mkfile open paste ping read rename resize rm tmb upload]
15
+
16
+ # Default options for instances.
17
+ # @see #initialize
18
+ DEFAULT_OPTIONS = {
19
+ :mime_handler => ElFinder::MimeType,
20
+ :image_handler => ElFinder::Image,
21
+ :original_filename_method => lambda { |file| file.original_filename.respond_to?(:force_encoding) ? file.original_filename.force_encoding('utf-8') : file.original_filename },
22
+ :disabled_commands => [],
23
+ :allow_dot_files => true,
24
+ :upload_max_size => '50M',
25
+ :upload_file_mode => 0644,
26
+ :archivers => {},
27
+ :extractors => {},
28
+ :home => 'Home',
29
+ :default_perms => { :read => true, :write => true, :rm => true, :hidden => false },
30
+ :perms => [],
31
+ :thumbs => false,
32
+ :thumbs_directory => '.thumbs',
33
+ :thumbs_size => 48,
34
+ :thumbs_at_once => 5,
35
+ :tree_sub_folders => true, # list sub/sub folders in the tree
36
+ }
37
+
38
+ # Initializes new instance.
39
+ # @param [Hash] options Instance options. :url and :root options are required.
40
+ # @option options [String] :url Entry point of ElFinder router.
41
+ # @option options [String] :root Root directory of ElFinder directory structure.
42
+ # @see DEFAULT_OPTIONS
43
+ def initialize(options)
44
+ @options = DEFAULT_OPTIONS.merge(options)
45
+
46
+ raise(ArgumentError, "Missing required :url option") unless @options.key?(:url)
47
+ raise(ArgumentError, "Missing required :root option") unless @options.key?(:root)
48
+ raise(ArgumentError, "Mime Handler is invalid") unless mime_handler.respond_to?(:for)
49
+ raise(ArgumentError, "Image Handler is invalid") unless image_handler.nil? || ([:size, :resize, :thumbnail].all?{|m| image_handler.respond_to?(m)})
50
+
51
+ @root = ElFinder::Pathname.new(options[:root])
52
+
53
+ @headers = {}
54
+ @response = {}
55
+ end # of initialize
56
+
57
+ # Runs request-response cycle.
58
+ # @param [Hash] params Request parameters. :cmd option is required.
59
+ # @option params [String] :cmd Command to be performed.
60
+ # @see VALID_COMMANDS
61
+ def run(params)
62
+ @params = params.dup
63
+ @headers = {}
64
+ @response = {}
65
+ @response[:errorData] = {}
66
+
67
+ if VALID_COMMANDS.include?(@params[:cmd])
68
+
69
+ if @options[:thumbs]
70
+ @thumb_directory = @root + @options[:thumbs_directory]
71
+ @thumb_directory.mkdir unless @thumb_directory.exist?
72
+ raise(RuntimeError, "Unable to create thumbs directory") unless @thumb_directory.directory?
73
+ end
74
+
75
+ @current = @params[:current] ? from_hash(@params[:current]) : nil
76
+ @target = (@params[:target] and !@params[:target].empty?) ? from_hash(@params[:target]) : nil
77
+ if params[:targets]
78
+ @targets = @params[:targets].map{|t| from_hash(t)}
79
+ end
80
+
81
+ send("_#{@params[:cmd]}")
82
+ else
83
+ invalid_request
84
+ end
85
+
86
+ @response.delete(:errorData) if @response[:errorData].empty?
87
+
88
+ return @headers, @response
89
+ end # of run
90
+
91
+ #
92
+ def to_hash(pathname)
93
+ # note that '=' are removed
94
+ Base64.urlsafe_encode64(pathname.path.to_s).chomp.tr("=\n", "")
95
+ end # of to_hash
96
+
97
+ #
98
+ def from_hash(hash)
99
+ # restore missing '='
100
+ len = hash.length % 4
101
+ hash += '==' if len == 1 or len == 2
102
+ hash += '=' if len == 3
103
+
104
+ decoded_hash = Base64.urlsafe_decode64(hash)
105
+ decoded_hash = decoded_hash.respond_to?(:force_encoding) ? decoded_hash.force_encoding('utf-8') : decoded_hash
106
+ pathname = @root + decoded_hash
107
+ rescue ArgumentError => e
108
+ if e.message != 'invalid base64'
109
+ raise
110
+ end
111
+ nil
112
+ end # of from_hash
113
+
114
+ # @!attribute [w] options
115
+ # Options setter.
116
+ # @param value [Hash] Options to be merged with instance ones.
117
+ # @return [Hash] Updated options.
118
+ def options=(value = {})
119
+ value.each_pair do |k, v|
120
+ @options[k.to_sym] = v
121
+ end
122
+ @options
123
+ end # of options=
124
+
125
+ ################################################################################
126
+ protected
127
+
128
+ #
129
+ def _open(target = nil)
130
+ target ||= @target
131
+
132
+ if target.nil?
133
+ _open(@root)
134
+ return
135
+ end
136
+
137
+ if perms_for(target)[:read] == false
138
+ @response[:error] = 'Access Denied'
139
+ return
140
+ end
141
+
142
+ if target.file?
143
+ command_not_implemented
144
+ elsif target.directory?
145
+ @response[:cwd] = cwd_for(target)
146
+ @response[:cdc] = target.children.
147
+ reject{ |child| perms_for(child)[:hidden]}.
148
+ sort_by{|e| e.basename.to_s.downcase}.map{|e| cdc_for(e)}.compact
149
+
150
+ if @params[:tree]
151
+ @response[:tree] = {
152
+ :name => @options[:home],
153
+ :hash => to_hash(@root),
154
+ :dirs => tree_for(@root),
155
+ }.merge(perms_for(@root))
156
+ end
157
+
158
+ if @params[:init]
159
+ @response[:disabled] = @options[:disabled_commands]
160
+ @response[:params] = {
161
+ :dotFiles => @options[:allow_dot_files],
162
+ :uplMaxSize => @options[:upload_max_size],
163
+ :archives => @options[:archivers].keys,
164
+ :extract => @options[:extractors].keys,
165
+ :url => @options[:url]
166
+ }
167
+ end
168
+
169
+ else
170
+ @response[:error] = "Directory does not exist"
171
+ _open(@root) if File.directory?(@root)
172
+ end
173
+
174
+ end # of open
175
+
176
+ #
177
+ def _mkdir
178
+ if perms_for(@current)[:write] == false
179
+ @response[:error] = 'Access Denied'
180
+ return
181
+ end
182
+
183
+ dir = @current + @params[:name]
184
+ if !dir.exist? && dir.mkdir
185
+ @params[:tree] = true
186
+ @response[:select] = [to_hash(dir)]
187
+ _open(@current)
188
+ else
189
+ @response[:error] = "Unable to create folder"
190
+ end
191
+ end # of mkdir
192
+
193
+ #
194
+ def _mkfile
195
+ if perms_for(@current)[:write] == false
196
+ @response[:error] = 'Access Denied'
197
+ return
198
+ end
199
+
200
+ file = @current + @params[:name]
201
+ if !file.exist? && file.touch
202
+ @response[:select] = [to_hash(file)]
203
+ _open(@current)
204
+ else
205
+ @response[:error] = "Unable to create file"
206
+ end
207
+ end # of mkfile
208
+
209
+ #
210
+ def _rename
211
+ to = @current + @params[:name]
212
+
213
+ perms_for_target = perms_for(@target)
214
+ if perms_for_target[:rm] == false
215
+ @response[:error] = 'Access Denied'
216
+ return
217
+ end
218
+
219
+ perms_for_current = perms_for(@current)
220
+ if perms_for_current[:write] == false
221
+ @response[:error] = 'Access Denied'
222
+ return
223
+ end
224
+
225
+ if to.exist?
226
+ @response[:error] = "Unable to rename #{@target.ftype}. '#{to.basename}' already exists"
227
+ elsif @target.rename(to)
228
+ @params[:tree] = to.directory?
229
+ @response[:select] = [to_hash(to)]
230
+ _open(@current)
231
+ else
232
+ @response[:error] = "Unable to rename #{@target.ftype}"
233
+ end
234
+ end # of rename
235
+
236
+ #
237
+ def _upload
238
+ if perms_for(@current)[:write] == false
239
+ @response[:error] = 'Access Denied'
240
+ return
241
+ end
242
+ select = []
243
+ @params[:upload].to_a.each do |file|
244
+ if file.respond_to?(:tempfile)
245
+ the_file = file.tempfile
246
+ else
247
+ the_file = file
248
+ end
249
+ if upload_max_size_in_bytes > 0 && File.size(the_file.path) > upload_max_size_in_bytes
250
+ @response[:error] ||= "Some files were not uploaded"
251
+ @response[:errorData][@options[:original_filename_method].call(file)] = 'File exceeds the maximum allowed filesize'
252
+ else
253
+ dst = @current + @options[:original_filename_method].call(file)
254
+ the_file.close
255
+ src = the_file.path
256
+ FileUtils.mv(src, dst.fullpath)
257
+ FileUtils.chmod @options[:upload_file_mode], dst
258
+ select << to_hash(dst)
259
+ end
260
+ end
261
+ @response[:select] = select unless select.empty?
262
+ _open(@current)
263
+ end # of upload
264
+
265
+ #
266
+ def _ping
267
+ @headers['Connection'] = 'Close'
268
+ end # of ping
269
+
270
+ #
271
+ def _paste
272
+ if perms_for(from_hash(@params[:dst]))[:write] == false
273
+ @response[:error] = 'Access Denied'
274
+ return
275
+ end
276
+
277
+ @targets.to_a.each do |src|
278
+ if perms_for(src)[:read] == false || (@params[:cut].to_i > 0 && perms_for(src)[:rm] == false)
279
+ @response[:error] ||= 'Some files were not copied.'
280
+ @response[:errorData][src.basename.to_s] = "Access Denied"
281
+ return
282
+ else
283
+ dst = from_hash(@params[:dst]) + src.basename
284
+ if dst.exist?
285
+ @response[:error] ||= 'Some files were unable to be copied'
286
+ @response[:errorData][src.basename.to_s] = "already exists in '#{dst.dirname}'"
287
+ else
288
+ if @params[:cut].to_i > 0
289
+ src.rename(dst)
290
+ else
291
+ if src.directory?
292
+ FileUtils.cp_r(src.fullpath, dst.fullpath)
293
+ else
294
+ FileUtils.cp(src.fullpath, dst.fullpath)
295
+ end
296
+ end
297
+ end
298
+ end
299
+ end
300
+ @params[:tree] = true
301
+ _open(@current)
302
+ end # of paste
303
+
304
+ #
305
+ def _rm
306
+ if @targets.empty?
307
+ @response[:error] = "No files were selected for removal"
308
+ else
309
+ @targets.to_a.each do |target|
310
+ remove_target(target)
311
+ end
312
+ @params[:tree] = true
313
+ _open(@current)
314
+ end
315
+ end # of rm
316
+
317
+ #
318
+ def _duplicate
319
+ if perms_for(@target)[:read] == false
320
+ @response[:error] = 'Access Denied'
321
+ @response[:errorData][@target.basename.to_s] = 'Unable to read'
322
+ return
323
+ end
324
+ if perms_for(@target.dirname)[:write] == false
325
+ @response[:error] = 'Access Denied'
326
+ @response[:errorData][@target.dirname.to_s] = 'Unable to write'
327
+ return
328
+ end
329
+
330
+ duplicate = @target.duplicate
331
+ if @target.directory?
332
+ FileUtils.cp_r(@target, duplicate.fullpath)
333
+ else
334
+ FileUtils.copy(@target, duplicate.fullpath)
335
+ end
336
+ @response[:select] = [to_hash(duplicate)]
337
+ _open(@current)
338
+ end # of duplicate
339
+
340
+ #
341
+ def _read
342
+ if perms_for(@target)[:read] == true
343
+ @response[:content] = @target.read
344
+ else
345
+ @response[:error] = 'Access Denied'
346
+ end
347
+ end # of read
348
+
349
+ #
350
+ def _edit
351
+ perms = perms_for(@target)
352
+ if perms[:read] == true && perms[:write] == true
353
+ @target.open('w') { |f| f.write @params[:content] }
354
+ @response[:file] = cdc_for(@target)
355
+ else
356
+ @response[:error] = 'Access Denied'
357
+ end
358
+ end # of edit
359
+
360
+ #
361
+ def _extract
362
+ @response[:error] = 'Invalid Parameters' and return if @target.nil? || @current.nil? || !(@target.file? && @current.directory?)
363
+ @response[:error] = 'Access Denied' and return unless perms_for(@target)[:read] == true && perms_for(@current)[:write] == true
364
+ @response[:error] = 'No extractor available for this file type' and return if (extractor = @options[:extractors][mime_handler.for(@target)]).nil?
365
+ cmd = ['cd', @current.to_s.shellescape, '&&', extractor.map(&:shellescape), @target.basename.to_s.shellescape].flatten.join(' ')
366
+ if system(cmd)
367
+ @params[:tree] = true
368
+ _open(@current)
369
+ else
370
+ @response[:error] = 'Unable to extract files from archive'
371
+ end
372
+ end # of extract
373
+
374
+ #
375
+ def _archive
376
+ @response[:error] = 'Invalid Parameters' and return unless !@targets.nil? && @targets.all?{|e| e && e.exist?} && @current && @current.directory?
377
+ @response[:error] = 'Access Denied' and return unless !@targets.nil? && @targets.all?{|e| perms_for(e)[:read]} && perms_for(@current)[:write] == true
378
+ @response[:error] = 'No archiver available for this file type' and return if (archiver = @options[:archivers][@params[:type]]).nil?
379
+ extension = archiver.shift
380
+ basename = @params[:name] || @targets.first.basename_sans_extension
381
+ archive = (@root + "#{basename}#{extension}").unique
382
+ cmd = ['cd', @current.to_s.shellescape, '&&', archiver.map(&:shellescape), archive.to_s.shellescape, @targets.map{|t| t.basename.to_s.shellescape}].flatten.join(' ')
383
+ if system(cmd)
384
+ @response[:select] = [to_hash(archive)]
385
+ _open(@current)
386
+ else
387
+ @response[:error] = 'Unable to create archive'
388
+ end
389
+ end # of archive
390
+
391
+ #
392
+ def _tmb
393
+ if image_handler.nil?
394
+ command_not_implemented
395
+ else
396
+ @response[:current] = to_hash(@current)
397
+ @response[:images] = {}
398
+ idx = 0
399
+ @current.children.select{|e| mime_handler.for(e) =~ /image/}.each do |img|
400
+ if idx >= @options[:thumbs_at_once]
401
+ @response[:tmb] = true
402
+ break
403
+ end
404
+ thumbnail = thumbnail_for(img)
405
+ unless thumbnail.file?
406
+ mime = mime_handler.for(img)
407
+
408
+ # For animated Gifs (mime-type 'image/gif'), it doesn't create "#{thumbnail}" file, but it creates a series of "#{thumbnail}-x" files, depending
409
+ # on how many frames that src-gif contains
410
+ # same thing applies for photoshop files ('image/vnd.adobe.photoshop')
411
+ # So you need to add [0] to the src to get the first frame.
412
+ has_frames = true if ["image/gif", "image/vnd.adobe.photoshop"].include?(mime)
413
+ image_handler.thumbnail(img, thumbnail, :width => @options[:thumbs_size].to_i, :height => @options[:thumbs_size].to_i, has_frames: has_frames)
414
+
415
+ #Just-in-Case, if the file is not created don't send it
416
+ if thumbnail.file?
417
+ @response[:images][to_hash(img)] = @options[:url] + '/' + thumbnail.path.to_s
418
+ idx += 1
419
+ end
420
+ end
421
+ end
422
+ end
423
+
424
+ end # of tmb
425
+
426
+ #
427
+ def _resize
428
+ if image_handler.nil?
429
+ command_not_implemented
430
+ else
431
+ if @target.file?
432
+ perms = perms_for(@target)
433
+ if perms[:read] == true && perms[:write] == true
434
+ image_handler.resize(@target, :width => @params[:width].to_i, :height => @params[:height].to_i)
435
+ @response[:select] = [to_hash(@target)]
436
+ _open(@current)
437
+ else
438
+ @response[:error] = 'Access Denied'
439
+ end
440
+ else
441
+ @response[:error] = "Unable to resize file. It does not exist"
442
+ end
443
+ end
444
+ end # of resize
445
+
446
+ ################################################################################
447
+ private
448
+
449
+ #
450
+ def upload_max_size_in_bytes
451
+ bytes = @options[:upload_max_size]
452
+ if bytes.is_a?(String) && bytes.strip =~ /(\d+)([KMG]?)/
453
+ bytes = $1.to_i
454
+ unit = $2
455
+ case unit
456
+ when 'K'
457
+ bytes *= 1024
458
+ when 'M'
459
+ bytes *= 1024 * 1024
460
+ when 'G'
461
+ bytes *= 1024 * 1024 * 1024
462
+ end
463
+ end
464
+ bytes.to_i
465
+ end
466
+
467
+ #
468
+ def thumbnail_for(pathname)
469
+ @thumb_directory + "#{to_hash(pathname)}.png"
470
+ end
471
+
472
+ #
473
+ def remove_target(target)
474
+ if target.directory?
475
+ target.children.each do |child|
476
+ remove_target(child)
477
+ end
478
+ end
479
+ if perms_for(target)[:rm] == false
480
+ @response[:error] ||= 'Some files/directories were unable to be removed'
481
+ @response[:errorData][target.basename.to_s] = "Access Denied"
482
+ else
483
+ begin
484
+ target.unlink
485
+ if @options[:thumbs] && (thumbnail = thumbnail_for(target)).file?
486
+ thumbnail.unlink
487
+ end
488
+ rescue
489
+ @response[:error] ||= 'Some files/directories were unable to be removed'
490
+ @response[:errorData][target.basename.to_s] = "Remove failed"
491
+ end
492
+ end
493
+ end
494
+
495
+ def mime_handler
496
+ @options[:mime_handler]
497
+ end
498
+
499
+ #
500
+ def image_handler
501
+ @options[:image_handler]
502
+ end
503
+
504
+ #
505
+ def cwd_for(pathname)
506
+ {
507
+ :name => pathname.basename.to_s,
508
+ :hash => to_hash(pathname),
509
+ :mime => 'directory',
510
+ :rel => pathname.is_root? ? @options[:home] : (@options[:home] + '/' + pathname.path.to_s),
511
+ :size => 0,
512
+ :date => pathname.mtime.to_s,
513
+ }.merge(perms_for(pathname))
514
+ end
515
+
516
+ def cdc_for(pathname)
517
+ return nil if @options[:thumbs] && pathname.to_s == @thumb_directory.to_s
518
+ response = {
519
+ :name => pathname.basename.to_s,
520
+ :hash => to_hash(pathname),
521
+ :date => pathname.mtime.to_s,
522
+ }
523
+ response.merge! perms_for(pathname)
524
+
525
+ if pathname.directory?
526
+ response.merge!(
527
+ :size => 0,
528
+ :mime => 'directory'
529
+ )
530
+ elsif pathname.file?
531
+ response.merge!(
532
+ :size => pathname.size,
533
+ :mime => mime_handler.for(pathname),
534
+ :url => (@options[:url] + '/' + pathname.path.to_s)
535
+ )
536
+
537
+ if pathname.readable? && response[:mime] =~ /image/ && !image_handler.nil?
538
+ response.merge!(
539
+ :resize => true,
540
+ :dim => image_handler.size(pathname)
541
+ )
542
+ if @options[:thumbs]
543
+ if (thumbnail = thumbnail_for(pathname)).exist?
544
+ response.merge!( :tmb => (@options[:url] + '/' + thumbnail.path.to_s))
545
+ else
546
+ @response[:tmb] = true
547
+ end
548
+ end
549
+ end
550
+
551
+ end
552
+
553
+ if pathname.symlink?
554
+ response.merge!(
555
+ :link => to_hash(@root + pathname.readlink), # hash of file to which point link
556
+ :linkTo => (@root + pathname.readlink).relative_to(pathname.dirname.path).to_s, # relative path to
557
+ :parent => to_hash((@root + pathname.readlink).dirname) # hash of directory in which is linked file
558
+ )
559
+ end
560
+
561
+ return response
562
+ end
563
+
564
+ #
565
+ def tree_for(root)
566
+ root.child_directories(@options[:tree_sub_folders]).
567
+ reject{ |child|
568
+ ( @options[:thumbs] && child.to_s == @thumb_directory.to_s ) || perms_for(child)[:hidden]
569
+ }.
570
+ sort_by{|e| e.basename.to_s.downcase}.
571
+ map { |child|
572
+ {:name => child.basename.to_s,
573
+ :hash => to_hash(child),
574
+ :dirs => tree_for(child),
575
+ }.merge(perms_for(child))
576
+ }
577
+ end # of tree_for
578
+
579
+ #
580
+ def perms_for(pathname, options = {})
581
+ skip = [options[:skip]].flatten
582
+ response = {}
583
+
584
+ response[:read] = pathname.readable? if pathname.exist?
585
+ response[:read] &&= specific_perm_for(pathname, :read)
586
+ response[:read] &&= @options[:default_perms][:read]
587
+
588
+ response[:write] = pathname.writable? if pathname.exist?
589
+ response[:write] &&= specific_perm_for(pathname, :write)
590
+ response[:write] &&= @options[:default_perms][:write]
591
+
592
+ response[:rm] = !pathname.is_root?
593
+ response[:rm] &&= specific_perm_for(pathname, :rm)
594
+ response[:rm] &&= @options[:default_perms][:rm]
595
+
596
+ response[:hidden] = false
597
+ response[:hidden] ||= specific_perm_for(pathname, :hidden)
598
+ response[:hidden] ||= @options[:default_perms][:hidden]
599
+
600
+ response
601
+ end # of perms_for
602
+
603
+ #
604
+ def specific_perm_for(pathname, perm)
605
+ pathname = pathname.path if pathname.is_a?(ElFinder::Pathname)
606
+ matches = @options[:perms].select{ |k,v| pathname.to_s.send((k.is_a?(String) ? :== : :match), k) }
607
+ if perm == :hidden
608
+ matches.one?{|e| e.last[perm] }
609
+ else
610
+ matches.none?{|e| e.last[perm] == false}
611
+ end
612
+ end # of specific_perm_for
613
+
614
+ #
615
+ def invalid_request
616
+ @response[:error] = "Invalid command '#{@params[:cmd]}'"
617
+ end # of invalid_request
618
+
619
+ #
620
+ def command_not_implemented
621
+ @response[:error] = "Command '#{@params[:cmd]}' not yet implemented"
622
+ end # of command_not_implemented
623
+
624
+ end # of class Connector
625
+ end # of module ElFinder
@@ -0,0 +1,33 @@
1
+ require 'rubygems'
2
+ require 'shellwords'
3
+ require 'image_size'
4
+
5
+ module ElFinder
6
+
7
+ # Represents default image handler.
8
+ # It uses *mogrify* to resize images and *convert* to create thumbnails.
9
+ class Image
10
+
11
+ def self.size(pathname)
12
+ return nil unless File.exist?(pathname)
13
+ s = ::ImageSize.path(pathname).size.to_s
14
+ s = nil if s.empty?
15
+ return s
16
+ rescue
17
+ nil
18
+ end
19
+
20
+ def self.resize(pathname, options = {})
21
+ return nil unless File.exist?(pathname)
22
+ system( ::Shellwords.join(['mogrify', '-resize', "#{options[:width]}x#{options[:height]}!", pathname.to_s]) )
23
+ end # of self.resize
24
+
25
+ def self.thumbnail(src, dst, options = {})
26
+ return nil unless File.exist?(src)
27
+ src = "#{src.to_s}[0]" if options[:has_frames]
28
+ system( ::Shellwords.join(['convert', '-resize', "#{options[:width]}x#{options[:height]}", '-background', 'white', '-gravity', 'center', '-extent', "#{options[:width]}x#{options[:height]}", src.to_s, dst.to_s]) )
29
+ end # of self.resize
30
+
31
+ end # of class Image
32
+
33
+ end # of module ElFinder