├── LICENSE.txt ├── README.md ├── Rakefile ├── app ├── controllers │ └── mediabrowser_controller.rb └── views │ └── mediabrowser │ └── list.html.erb ├── config ├── application.rb └── routes.rb ├── init.rb ├── install.rb ├── lib ├── mediabrowser.rb └── routing.rb ├── public ├── css │ └── list.css └── images │ ├── delete.png │ ├── dir.png │ └── file.png ├── test ├── mediabrowser_test.rb └── test_helper.rb └── uninstall.rb /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2013 Vincent Agnano 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A file manager for rails 3 2 | 3 | Rails 3 plugin for browsing and managing files from a web page (admin 4 | in most cases). 5 | 6 | It does NOT use any database as it works directly on file structure. 7 | 8 | ![rails 3 media browser](https://raw.github.com/vinyll/rails-mediabrowser/doc/thumb.jpg) 9 | 10 | 11 | ## Run it 12 | 13 | open your browser at http://0.0.0.0:3000/mediabrowser, and manage files and 14 | directories from there. 15 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake' 2 | require 'rake/testtask' 3 | require 'rake/rdoctask' 4 | 5 | desc 'Default: run unit tests.' 6 | task :default => :test 7 | 8 | desc 'Test the mediabrowser plugin.' 9 | Rake::TestTask.new(:test) do |t| 10 | t.libs << 'lib' 11 | t.libs << 'test' 12 | t.pattern = 'test/**/*_test.rb' 13 | t.verbose = true 14 | end 15 | 16 | desc 'Generate documentation for the mediabrowser plugin.' 17 | Rake::RDocTask.new(:rdoc) do |rdoc| 18 | rdoc.rdoc_dir = 'rdoc' 19 | rdoc.title = 'Mediabrowser' 20 | rdoc.options << '--line-numbers' << '--inline-source' 21 | rdoc.rdoc_files.include('README') 22 | rdoc.rdoc_files.include('lib/**/*.rb') 23 | end -------------------------------------------------------------------------------- /app/controllers/mediabrowser_controller.rb: -------------------------------------------------------------------------------- 1 | class MediabrowserController < ApplicationController 2 | 3 | before_filter :define_path 4 | 5 | 6 | def define_path 7 | @public_path = File.join(Rails.root.to_s, 'public') 8 | @uploads_url = '/uploads' 9 | @upload_path = File.join(@public_path, @uploads_url) 10 | @current_url = params[:dir] || @uploads_url 11 | @current_path = File.join(@public_path, @current_url)+ '/*' 12 | end 13 | 14 | 15 | def list 16 | 17 | @dirs = [] 18 | @files = [] 19 | Dir.glob(@current_path).sort.each do |file| 20 | file_obj = { 21 | :url => file.gsub(@public_path, ''), 22 | :name => File.basename(file), 23 | } 24 | if File.directory?(file) 25 | @dirs << file_obj 26 | else 27 | file_obj.merge!({ 28 | :type => ['gif','jpg','jpeg','png'].index(File.extname(file)[1..-1]) ? :image : :file, 29 | :icon => '/mediabrowser/images/file.png', 30 | }) 31 | puts file_obj[:type] 32 | if file_obj[:type] == :image 33 | file_obj[:icon] = file_obj[:url] 34 | end 35 | @files << file_obj 36 | end 37 | end 38 | 39 | @breadcrumb = [] 40 | curr_crumb = '' 41 | @current_url.each(File::SEPARATOR) do |crumb| 42 | crumb.gsub!('/', '') 43 | if crumb != '' 44 | curr_crumb += File::SEPARATOR + crumb 45 | puts curr_crumb 46 | @breadcrumb << { 47 | :name => crumb, 48 | :url => curr_crumb, 49 | } 50 | end 51 | end 52 | end 53 | 54 | 55 | def create_dir 56 | slugged_name = slugify(params[:new_dir][:name]) 57 | path = File.join(@public_path, params[:new_dir][:path]) 58 | create_path = File.join(path, slugged_name) 59 | 60 | if secured_path?(path) && !File.exist?(create_path) && FileUtils.mkdir(create_path) 61 | notice = 'Directory "%s" was successfully created' % slugged_name 62 | else 63 | notice = 'Directory "%s" could not be created' % slugged_name 64 | end 65 | redirect_to request.referer, :notice => notice 66 | end 67 | 68 | 69 | def create_file 70 | data = params[:new_file][:file] 71 | filename = data.original_filename 72 | target_name = slugify(filename) 73 | 74 | if filename_ext = File.extname(filename) 75 | target_name = slugify(filename[0..-(filename_ext.length+1)]) + filename_ext 76 | end 77 | target = File.join(@public_path, params[:new_file][:path], target_name) 78 | File.open(target, 'w+') do |file| 79 | file.write(data.read) 80 | end 81 | notice = File.exist?(target) \ 82 | ? 'File "%s" was successfully added' % File.basename(target_name)\ 83 | : 'File "%s" could not be uploaded' % File.basename(target_name) 84 | redirect_to request.referer, :notice => notice 85 | end 86 | 87 | 88 | def delete 89 | file_path = File.join(@public_path, params[:file]) 90 | if secured_path?(file_path) && FileUtils.rm_r(file_path) 91 | notice = '"%s" was successfully deleted' % File.basename(params[:file]) 92 | else 93 | notice = '"%s" could not be deleted' % File.basename(params[:file]) 94 | end 95 | redirect_to request.referer, :notice => notice 96 | end 97 | 98 | 99 | protected 100 | 101 | def secured_path?(file_path) 102 | return File.exist?(file_path) && ! File.dirname(file_path).index(@public_path).nil? 103 | end 104 | 105 | 106 | 107 | def slugify(value) 108 | return value.mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/n, '').to_s\ 109 | .downcase\ 110 | .gsub(/[']+/, '')\ 111 | .gsub(/\W+/, ' ')\ 112 | .strip\ 113 | .gsub(' ', '-') 114 | end 115 | 116 | end 117 | -------------------------------------------------------------------------------- /app/views/mediabrowser/list.html.erb: -------------------------------------------------------------------------------- 1 | <% puts 'template talks' %> 2 | 3 | 4 | <% if flash[:notice] %> 5 |

<%= flash[:notice] %>

6 | <% end %> 7 | <% if flash[:error] %> 8 |

<%= flash[:error] %>

9 | <% end %> 10 | 11 | 12 |
13 | <%= token_tag %> 14 | 15 |

Add a file

16 | 17 | 18 | 19 |
20 | 21 |
22 | <%= token_tag %> 23 | 24 |

Create a directory

25 | 26 | 27 | 28 |
29 | 30 | 35 | 36 | 51 | 52 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | class Application < Rails::Application 2 | config.upload_url = '/uploads' 3 | end 4 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails::Application.routes.draw do 2 | match '/mediabrowser' => 'mediabrowser#list', :as => :mediabrowser 3 | match '/mediabrowser/delete' => 'mediabrowser#delete', :as => :delete_file_mediabrowser 4 | match '/mediabrowser/dir/create' => 'mediabrowser#create_dir', :as => :create_dir_mediabrowser 5 | match '/mediabrowser/file/create' => 'mediabrowser#create_file', :as => :create_file_mediabrowser 6 | end 7 | -------------------------------------------------------------------------------- /init.rb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinyll/rails-mediabrowser/febbc0b78ffeb2cb268851afc9d33cd87fa18e54/init.rb -------------------------------------------------------------------------------- /install.rb: -------------------------------------------------------------------------------- 1 | require 'fileutils' 2 | 3 | RAILS_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '/../../../')) unless defined? RAILS_ROOT 4 | 5 | public_dir = File.expand_path(File.join(RAILS_ROOT, 'public')) 6 | 7 | puts 'Publishing web assets to public folder' 8 | FileUtils.cp_r( 9 | File.join(File.dirname(__FILE__), 'public'),\ 10 | File.join(public_dir, 'mediabrowser') 11 | ) 12 | 13 | upload_dir = File.join(public_dir, 'uploads') 14 | unless File.exists?(upload_dir) 15 | puts 'Creating uploads directory at "%s"' % upload_dir 16 | FileUtils.mkdir(upload_dir) 17 | end 18 | 19 | puts 'chmod 777 on uploads directory "%s"' % upload_dir 20 | FileUtils.chmod_R(0777, upload_dir) 21 | -------------------------------------------------------------------------------- /lib/mediabrowser.rb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinyll/rails-mediabrowser/febbc0b78ffeb2cb268851afc9d33cd87fa18e54/lib/mediabrowser.rb -------------------------------------------------------------------------------- /lib/routing.rb: -------------------------------------------------------------------------------- 1 | module Mediabrowser 2 | module Routing 3 | module MapperExtensions 4 | def mediabrowser 5 | @set.add_route('/mediabrowser', {:controller => 'mediabrowser_controller', :action => 'list', :as => :mediabrowser}) 6 | @set.add_route('/mediabrowser/delete', {:controller => 'mediabrowser_controller', :action => 'delete', :as => :delete_file_mediabrowser}) 7 | @set.add_route('/mediabrowser/dir/create', { :controller => 'mediabrowser', :action => 'create_dir', :as => :create_dir_mediabrowser}) 8 | @set.add_route('/mediabrowser/file/create', { :controller => 'mediabrowser/file/create', :action => 'create_file', :as => :create_file_mediabrowser}) 9 | end 10 | end 11 | end 12 | end 13 | 14 | 15 | ActionController::Routing::RouteSet::Mapper.send(:include, Mediabrowser::Routing::MapperExtensions) -------------------------------------------------------------------------------- /public/css/list.css: -------------------------------------------------------------------------------- 1 | form#new_file, form#new_dir { 2 | float: left; 3 | background-color: #EEE; 4 | border: 1px solid #999; 5 | color: #333; 6 | margin-right: 50px; 7 | padding: 10px; 8 | width: 300px; 9 | } 10 | 11 | form#new_file h2, form#new_dir h2 { 12 | font-size: 1.2em; 13 | color: #333; 14 | margin: 0; 15 | } 16 | 17 | form#new_file input[type="submit"], form#new_dir input[type="submit"] { 18 | display: block; 19 | width: 150px; 20 | border-radius: 3px; 21 | background-color: #CCC; 22 | border: 1px solid #999; 23 | font-weight: bold; 24 | } 25 | form#new_file input[type="submit"]:hover, form#new_dir input[type="submit"]:hover { 26 | background-color: #BBB; 27 | cursor: pointer; 28 | } 29 | form#new_dir input[type="text"] { 30 | border: 1px solid #CCC; 31 | } 32 | 33 | #breadcrumb { 34 | clear: both; 35 | border-bottom: 1px solid #999; 36 | font-weight: bold; 37 | padding: 20px 0 10px 0; 38 | } 39 | #breadcrumb li { 40 | display: inline; 41 | } 42 | #breadcrumb li a { 43 | color: #333; 44 | } 45 | 46 | ul.directories, ul.files { 47 | clear: both; 48 | display: inline; 49 | list-style: none; 50 | } 51 | ul.directories > li, ul.files > li { 52 | float: left; 53 | width: 120px; 54 | height: 100px; 55 | margin: 10px; 56 | border: 1px solid #999; 57 | background-color: #EEE; 58 | text-align: center; 59 | } 60 | .directories .icon a { 61 | background: transparent url('/mediabrowser/images/dir.png') no-repeat 50% 10px; 62 | text-decoration: none; 63 | } 64 | .directories .icon a label { 65 | display: none; 66 | } 67 | 68 | ul.files > li:not(.image) .icon img { 69 | margin-top: 8px; 70 | } 71 | ul.files > li.image .icon img { 72 | margin: 0 auto; 73 | width: 100%; 74 | } 75 | 76 | .icon > a { 77 | display: block; 78 | height: 80px; 79 | overflow: hidden; 80 | } 81 | 82 | .infos { 83 | background-color: #CCC; 84 | border-top: 1px solid #999; 85 | width: auto; 86 | height: 19px; 87 | overflow: hidden; 88 | list-style: none; 89 | padding: 0; 90 | margin: 0; 91 | font-size: 12px; 92 | color: #333; 93 | position: relative; 94 | text-align: left; 95 | } 96 | ul.infos li { 97 | margin: 0; 98 | } 99 | .infos .label { 100 | width: 100px; 101 | } 102 | .infos .delete a { 103 | display: block; 104 | width: 20px; 105 | height: 20px; 106 | position: absolute; 107 | top: 2px; 108 | right: 0; 109 | text-indent: -5000px; 110 | background: transparent url('/mediabrowser/images/delete.png') no-repeat; 111 | } -------------------------------------------------------------------------------- /public/images/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinyll/rails-mediabrowser/febbc0b78ffeb2cb268851afc9d33cd87fa18e54/public/images/delete.png -------------------------------------------------------------------------------- /public/images/dir.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinyll/rails-mediabrowser/febbc0b78ffeb2cb268851afc9d33cd87fa18e54/public/images/dir.png -------------------------------------------------------------------------------- /public/images/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinyll/rails-mediabrowser/febbc0b78ffeb2cb268851afc9d33cd87fa18e54/public/images/file.png -------------------------------------------------------------------------------- /test/mediabrowser_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class MediabrowserTest < ActiveSupport::TestCase 4 | # Replace this with your real tests. 5 | test "the truth" do 6 | assert true 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'test/unit' 3 | require 'active_support' 4 | -------------------------------------------------------------------------------- /uninstall.rb: -------------------------------------------------------------------------------- 1 | require 'fileutils' 2 | 3 | RAILS_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '/../../../')) unless defined? RAILS_ROOT 4 | 5 | 6 | puts 'Removing mediabrowser web assets from public folder' 7 | 8 | 9 | FileUtils.rm_r(File.expand_path(File.join(RAILS_ROOT, 'public', 'mediabrowser'))) 10 | 11 | puts 'the uploads folder was not removed. Delete it manually if you do not need it nomore.' 12 | --------------------------------------------------------------------------------