├── .gitignore ├── README.md ├── app ├── controllers │ └── assets_controller.rb └── views │ └── assets │ ├── _links.erb │ ├── by_type.html.erb │ └── index.html.erb ├── config ├── locales │ ├── cs.yml │ ├── de.yml │ ├── en.yml │ ├── es.yml │ ├── fr.yml │ ├── it.yml │ ├── ja.yml │ ├── ko.yml │ ├── ru.yml │ ├── sl.yml │ └── zh.yml ├── mappings.yml └── routes.rb └── init.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | /nbproject -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Assets plugin for redmine 2 | ========================= 3 | 4 | Provides a central location to view all your project's assets. 5 | 6 | Overview 7 | -------- 8 | 9 | This will enable the `Assets` tab in your project. The assets tab groups assets by your different asset types. 10 | The asset types currently supported are `Issues`, `Messages`, `Documents`, `Versions` (from the Files module), and `WikiPages`. 11 | Only the types that have uploaded files in the current project will be displayed. Drilling down into an asset type 12 | will show an alphabetical list of assets, grouped by category if applicable. 13 | 14 | Requirements 15 | ------------ 16 | 17 | * Rails 3 18 | 19 | Installation 20 | ------------ 21 | 22 | 0. Follow the Redmine plugin installation steps at: [http://www.redmine.org/wiki/redmine/Plugins](http://www.redmine.org/wiki/redmine/Plugins) 23 | 1. Cd to your redmine `plugins/` dir 24 | 2. Git-clone the plugin from this repo into a folder in there: `git clone git://github.com/bshaffer/redmine-assets-plugin.git redmine_assets_plugin` (*You must name your directory with underscores as shown here, or the plugin will throw a fatal error*) 25 | 3. Run the plugin migrations `rake redmine:plugins:migrate` 26 | 4. Restart your Redmine web servers (e.g. mongrel, thin, mod_rails) 27 | 5. Login to your Redmine install as an Administrator 28 | 6. Setup the permissions for the assets module for your roles 29 | 7. Enable the module on a per-project basis as needed. 30 | 31 | NOTE: the plugin directory *has* to be "redmine_assets_plugin" 32 | 33 | Activation 34 | ---------- 35 | 36 | To activate in your project: 37 | 38 | * Navigate to your project's "Settings" page 39 | * Under the "Modules" tab, check the box next to "Assets list" and save 40 | 41 | Config 42 | ------ 43 | 44 | You can configure additional asset types via the `config/mappings.yml` file. Mappings to the 45 | content type's project_ids and categories are found here. Contact me or submit a pull request for additional asset types. 46 | 47 | * Leaving out the "category" key in `mappings.yml` will disable categorization. 48 | * Leaving out the "project_id" key will default to *project_id*. 49 | 50 | As a bare minimum, the mappings.yml file requires the name of the asset type, followed by an empty hash: 51 | 52 | NewAssetType: {} 53 | 54 | This will display the assets for class NewAssetType with a project_id field and no categories. 55 | 56 | Screenshots 57 | ----------- 58 | 59 | When you click the **Assets** Tab in your project, you will see all the content types in your project that have assets uploaded to them: 60 | ![Asset Landing Page](http://brentertainment.com/other/screenshots/redmine_assets_plugin_landing.png) 61 | 62 | If anyone has attached any files to the **Document** content type, they will be listed here, organized by Document Category 63 | ![Document Assets](http://brentertainment.com/other/screenshots/redmine_assets_plugin_documents.png) 64 | 65 | All files attached to **Issues** will be listed here, organized by Issue Category 66 | ![Issue Assets](http://brentertainment.com/other/screenshots/redmine_assets_plugin_issues.png) 67 | -------------------------------------------------------------------------------- /app/controllers/assets_controller.rb: -------------------------------------------------------------------------------- 1 | class AssetsController < ApplicationController 2 | 3 | before_filter :authorize, :asset_types 4 | before_filter :find_project, :only => [:index, :by_type] 5 | 6 | def index 7 | @types = types_for_project #Attachment.find(:all, :group => "container_type", :select => "container_type" ).collect(&:container_type) 8 | end 9 | 10 | def by_type 11 | @type = params[:type]; 12 | 13 | # Forward 404 if type does not exist in the mapping 14 | @mappings[@type].nil? rescue return render :file => "#{Rails.root}/public/404.html", :status => 404 15 | 16 | @mapping = @mappings[@type]; 17 | table_name = (eval @type).table_name 18 | @options = {:deletable => true, :author => true} 19 | 20 | # Every type will have this join 21 | joins = ["INNER JOIN #{table_name} ON #{table_name}.id = container_id and container_type = '#{@type}'"] 22 | 23 | # Add extra joins if applicable (for categories or project ID) 24 | if !@mapping['joins'].nil? 25 | joins << "LEFT JOIN #{@mapping['joins']}" 26 | end 27 | 28 | # Every type will have these conditions 29 | conditions = "container_type = '#{@type}' AND #{@mapping['project_id']} = #{@project.id}"; 30 | 31 | # If a category mapping exists 32 | if(!@mapping['category'].nil?) 33 | @assets = Attachment.find(:all, { 34 | :conditions => conditions, 35 | :joins => joins.join(' '), 36 | :order => "#{@mapping['category']['name']} ASC, attachments.filename ASC"}) 37 | 38 | # If a category mapping doesnt exist 39 | else 40 | @assets = Attachment.find(:all, { 41 | :conditions => conditions, 42 | :joins => joins.join(' '), 43 | :order => "attachments.filename ASC"}) 44 | 45 | end 46 | end 47 | 48 | private 49 | def types_for_project 50 | joins = [] 51 | wheres = [] 52 | @mappings.each_pair do |type, mapping| 53 | table = (eval type).table_name 54 | 55 | joins << "LEFT JOIN #{table} ON #{table}.id = container_id AND container_type = '#{type}'" 56 | 57 | if !mapping['joins'].nil? 58 | joins << "LEFT JOIN #{mapping['joins']}" 59 | end 60 | 61 | wheres << "(#{mapping['project_id']} = #{@project.id})" 62 | end 63 | 64 | return Attachment.find(:all, {:select => "container_type", :group => "container_type", :conditions => wheres.join(' OR '), :joins => joins.join(' ')}).collect(&:container_type).compact 65 | end 66 | 67 | def find_project 68 | @project = Project.find(params[:project_id]) 69 | raise ActiveRecord::RecordNotFound, l(:asset_project_not_found_error) + " id:" + params[:project_id] unless @project 70 | end 71 | 72 | def asset_types 73 | require 'yaml' 74 | @mappings = YAML::load(File.open("#{Rails.root}/plugins/redmine_assets_plugin/config/mappings.yml")) 75 | # set defaults 76 | @mappings.each_pair do |type, mapping| 77 | table = (eval type).table_name 78 | if mapping.nil? 79 | @mappings[type] = mapping = {} 80 | end 81 | 82 | if mapping['project_id'].nil? 83 | @mappings[type]['project_id'] = "#{table}.project_id" 84 | end 85 | 86 | if !mapping['category'].nil? && mapping['category']['relation'].nil? 87 | @mappings[type]['category']['relation'] = 'category' 88 | end 89 | 90 | if !mapping['category'].nil? && mapping['category']['id'].nil? 91 | @mappings[type]['category']['id'] = 'category_id' 92 | end 93 | 94 | if !mapping['category'].nil? && mapping['category']['name'].nil? 95 | @mappings[type]['category']['name'] = 'name' 96 | end 97 | end 98 | end 99 | 100 | def authorize 101 | find_project 102 | super 103 | end 104 | end 105 | -------------------------------------------------------------------------------- /app/views/assets/_links.erb: -------------------------------------------------------------------------------- 1 | <% if category_relation %> 2 | <%= current_category = nil %> 3 | <% end %> 4 | 5 |
6 | <% for attachment in attachments %> 7 | <% if category_relation %> 8 | <% category = eval "attachment.container.#{category_relation}" %> 9 | <% if(current_category != category) %> 10 |

<%= category %>

11 | <% current_category = category %> 12 | <% end %> 13 | <% end %> 14 | 15 |

<%= link_to_attachment attachment, :class => 'icon icon-attachment' -%> 16 | <%= h(" - #{attachment.description}") unless attachment.description.blank? %> 17 | (<%= number_to_human_size attachment.filesize %>) 18 | <% if options[:deletable] %> 19 | <%= link_to image_tag('delete.png'), {:controller => 'attachments', :action => 'destroy', :id => attachment}, 20 | :confirm => l(:text_are_you_sure), 21 | :method => :delete, 22 | :class => 'delete', 23 | :title => l(:button_delete) %> 24 | <% end %> 25 | <% if options[:author] %> 26 | <%= attachment.author %>, <%= format_time(attachment.created_on) %> 27 | <% end %> 28 |

29 | <% end %> 30 |
31 | -------------------------------------------------------------------------------- /app/views/assets/by_type.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

<%= l(@mapping['i18n'].nil? ? 'label_'+@type.underscore : @mapping['i18n']) %> <%= l(:assets_project_heading) %> <%= @project.name %>

3 |
4 | 5 | <%= render :partial => 'assets/links', :locals => {:attachments => @assets, :options => @options, :category_relation => @mapping['category'].nil? ? nil : @mapping['category']['relation']} %> 6 | 7 |
8 |
-------------------------------------------------------------------------------- /app/views/assets/index.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

<%= l(:assets_project_heading) %> <%= @project.name %>

3 | <% if !@types.blank? %> 4 | 9 | <% else %> 10 | <%= l(:no_assets_added) %> 11 | <% end %> 12 |
-------------------------------------------------------------------------------- /config/locales/cs.yml: -------------------------------------------------------------------------------- 1 | #Assets English locale File for Rails >= 2.2.2 2 | cs: 3 | asset_project_not_found_error: "Projekt nebyl nalezen!" 4 | assets_project_heading: Přílohy pro 5 | label_asset_plural: Přílohy 6 | no_assets_added: Žádné přílohy nebyly nalezeny -------------------------------------------------------------------------------- /config/locales/de.yml: -------------------------------------------------------------------------------- 1 | #language file for de - post rails 2.2.2 2 | de: 3 | asset_project_not_found_error: "Projekte nicht gefunden!" 4 | assets_project_heading: Assets für 5 | label_asset_plural: Assets -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | #Assets English locale File for Rails >= 2.2.2 2 | en: 3 | asset_project_not_found_error: "Project not found!" 4 | assets_project_heading: Assets for 5 | label_asset_plural: Assets 6 | no_assets_added: No assets have been added -------------------------------------------------------------------------------- /config/locales/es.yml: -------------------------------------------------------------------------------- 1 | #Assets en locacles file 2 | es: 3 | asset_project_not_found_error: "Project not found!" 4 | assets_project_heading: Assets for 5 | label_asset_plural: Assets -------------------------------------------------------------------------------- /config/locales/fr.yml: -------------------------------------------------------------------------------- 1 | #language file for fr - post rails 2.2.2 2 | fr: 3 | asset_project_not_found_error: "Project not found!" 4 | assets_project_heading: Assets for 5 | label_asset_plural: Assets -------------------------------------------------------------------------------- /config/locales/it.yml: -------------------------------------------------------------------------------- 1 | #language file for it - pre rails 2.2.2 2 | it: 3 | asset_project_not_found_error: "Project not found!" 4 | assets_project_heading: Assets for 5 | label_asset_plural: Assets -------------------------------------------------------------------------------- /config/locales/ja.yml: -------------------------------------------------------------------------------- 1 | #Assets Japanese locale File for Rails >= 2.2.2 2 | ja: 3 | asset_project_not_found_error: "Project not found!" 4 | assets_project_heading: Assets for 5 | label_asset_plural: Assets -------------------------------------------------------------------------------- /config/locales/ko.yml: -------------------------------------------------------------------------------- 1 | #Assets Korean locale File for Rails >= 2.2.2 2 | ko: 3 | asset_project_not_found_error: "Project not found!" 4 | assets_project_heading: Assets for 5 | label_asset_plural: Assets -------------------------------------------------------------------------------- /config/locales/ru.yml: -------------------------------------------------------------------------------- 1 | #Assets Russian locale File for Rails >= 2.2.2 2 | ru: 3 | asset_project_not_found_error: "Project not found!" 4 | assets_project_heading: Assets for 5 | label_asset_plural: Assets -------------------------------------------------------------------------------- /config/locales/sl.yml: -------------------------------------------------------------------------------- 1 | #Assets English locale File for Rails >= 2.2.2 2 | sl: 3 | asset_project_not_found_error: "Projekt ne obstaja!" 4 | assets_project_heading: Priponke za 5 | label_asset_plural: Priponke 6 | no_assets_added: Priponke niso dodane -------------------------------------------------------------------------------- /config/locales/zh.yml: -------------------------------------------------------------------------------- 1 | #Assets zh locacles file 2 | zh: 3 | asset_project_not_found_error: "Project not found!" 4 | assets_project_heading: Assets for 5 | label_asset_plural: Assets -------------------------------------------------------------------------------- /config/mappings.yml: -------------------------------------------------------------------------------- 1 | # Tells plugin where to find project_id and asset category on each item 2 | 3 | Document: 4 | category: 5 | id: category_id 6 | relation: category 7 | name: name 8 | table: enumerations 9 | 10 | joins: enumerations on documents.category_id = enumerations.id AND type='DocumentCategory' 11 | 12 | Issue: 13 | category: 14 | id: category_id 15 | relation: category 16 | name: name 17 | table: issue_categories 18 | 19 | joins: issue_categories on issues.category_id = issue_categories.id 20 | 21 | Message: 22 | category: 23 | id: board_id 24 | relation: board 25 | table: boards 26 | name: name 27 | 28 | joins: boards on board_id = boards.id 29 | project_id: boards.project_id 30 | i18n: label_board 31 | 32 | Version: 33 | project_id: versions.project_id 34 | 35 | Project: 36 | project_id: projects.id 37 | 38 | WikiPage: 39 | category: 40 | id: id 41 | relation: title 42 | table: wiki_pages 43 | name: wiki_pages.title 44 | 45 | joins: wikis on wiki_id = wikis.id 46 | project_id: wikis.project_id 47 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | #custom routes for this plugin 2 | RedmineApp::Application.routes.draw do 3 | match '/projects/:project_id/assets' => 'assets#index', :via => [:get], :as => 'assets' 4 | match '/projects/:project_id/assets/:type/type' => 'assets#by_type', :as => 'assets_by_type', :via => [:get] 5 | end 6 | -------------------------------------------------------------------------------- /init.rb: -------------------------------------------------------------------------------- 1 | require 'redmine' 2 | 3 | Dir[File.join(File.dirname(__FILE__),'vendor','plugins','*')].each do |dir| 4 | path = File.join(dir, 'lib') 5 | $LOAD_PATH << path 6 | Dependencies.load_paths << path 7 | Dependencies.load_once_paths.delete(path) 8 | end 9 | 10 | Redmine::Plugin.register :redmine_assets_plugin do 11 | name 'Redmine Assets plugin' 12 | author 'Brent Shaffer' 13 | url 'https://github.com/bshaffer/redmine-assets-plugin' 14 | author_url 'http://brentertainment.com' 15 | description 'Provides a central location to view all your project\'s assets.' 16 | version '0.0.1' 17 | 18 | project_module :assets_list do 19 | permission :view_asset, {:assets => [:index, :by_type] } 20 | 21 | permission :edit_asset, 22 | {:asset => [:create, :destroy, :new, :toggle_complete, :sort, :edit, :update], 23 | :issues => [:edit, :update]} 24 | end 25 | 26 | menu :project_menu, :project_assets, {:controller => 'assets', :action => 'index'}, :caption => :label_asset_plural, :after => :new_issue, :param => :project_id 27 | end 28 | 29 | 30 | --------------------------------------------------------------------------------