From d2cb53a027659d068373c17d8cc2b3d3d4bd3f90 Mon Sep 17 00:00:00 2001 From: "mavimo@gmail.com" Date: Sat, 31 Mar 2012 17:56:49 +0000 Subject: [PATCH] * worinkg on Issue #19: DMSF document and folder can have custom fields git-svn-id: http://redmine-dmsf.googlecode.com/svn/trunk/redmine_dmsf@280 5e329b0b-a2ee-ea63-e329-299493fc886d --- app/controllers/dmsf_controller.rb | 4 +- app/controllers/dmsf_files_controller.rb | 2 + app/controllers/dmsf_files_copy_controller.rb | 2 + app/controllers/dmsf_state_controller.rb | 2 + app/controllers/dmsf_upload_controller.rb | 14 +++- app/models/dmsf_file.rb | 66 ++++++++++++++++--- app/models/dmsf_file_revision.rb | 28 +++++++- app/models/dmsf_file_revision_custom_field.rb | 13 ++++ app/models/dmsf_folder.rb | 34 +++++++++- app/views/dmsf/_custom_fields.html.erb | 9 +++ app/views/dmsf/edit.html.erb | 4 ++ app/views/dmsf/show.html.erb | 10 ++- .../dmsf_files/_file_new_revision.html.erb | 19 ++++-- app/views/dmsf_files/show.html.erb | 3 + app/views/dmsf_state/_user_pref.html.erb | 18 +++++ app/views/dmsf_upload/_upload_file.html.erb | 5 ++ assets/stylesheets/dmsf.css | 16 +++++ init.rb | 6 ++ lib/redmine_dmsf.rb | 6 ++ .../patches/acts_as_customizable.rb | 16 +++++ .../patches/custom_fields_helper.rb | 16 +++++ lib/redmine_dmsf/patches/project_patch.rb | 9 +++ 22 files changed, 275 insertions(+), 27 deletions(-) create mode 100644 app/models/dmsf_file_revision_custom_field.rb create mode 100644 app/views/dmsf/_custom_fields.html.erb create mode 100644 lib/redmine_dmsf.rb create mode 100644 lib/redmine_dmsf/patches/acts_as_customizable.rb create mode 100644 lib/redmine_dmsf/patches/custom_fields_helper.rb create mode 100644 lib/redmine_dmsf/patches/project_patch.rb diff --git a/app/controllers/dmsf_controller.rb b/app/controllers/dmsf_controller.rb index c22528e3..07dfe002 100644 --- a/app/controllers/dmsf_controller.rb +++ b/app/controllers/dmsf_controller.rb @@ -26,7 +26,9 @@ class DmsfController < ApplicationController verify :method => :post, :only => [:delete_entries, :create, :save, :delete, :save_root, :notify_activate, :notify_deactivate], :render => { :nothing => true, :status => :method_not_allowed } - + + helper :all + def show if @folder.nil? @subfolders = DmsfFolder.project_root_folders(@project) diff --git a/app/controllers/dmsf_files_controller.rb b/app/controllers/dmsf_files_controller.rb index 19580d46..9c774ff3 100644 --- a/app/controllers/dmsf_files_controller.rb +++ b/app/controllers/dmsf_files_controller.rb @@ -28,6 +28,8 @@ class DmsfFilesController < ApplicationController verify :method => :post, :only => [:create_revision, :delete_revision, :delete, :lock, :unlock, :notify_activate, :notify_deactivate], :render => { :nothing => true, :status => :method_not_allowed } + helper :all + def show # download is put here to provide more clear and usable links if params.has_key?(:download) diff --git a/app/controllers/dmsf_files_copy_controller.rb b/app/controllers/dmsf_files_copy_controller.rb index 728be22b..806075ff 100644 --- a/app/controllers/dmsf_files_copy_controller.rb +++ b/app/controllers/dmsf_files_copy_controller.rb @@ -26,6 +26,8 @@ class DmsfFilesCopyController < ApplicationController verify :method => :post, :only => [:create, :move], :render => { :nothing => true, :status => :method_not_allowed } + helper :all + def new @target_project = DmsfFile.allowed_target_projects_on_copy.detect {|p| p.id.to_s == params[:target_project_id]} if params[:target_project_id] @target_project ||= @project if User.current.allowed_to?(:file_manipulation, @project) diff --git a/app/controllers/dmsf_state_controller.rb b/app/controllers/dmsf_state_controller.rb index ce9859b9..5f4a15fa 100644 --- a/app/controllers/dmsf_state_controller.rb +++ b/app/controllers/dmsf_state_controller.rb @@ -26,6 +26,8 @@ class DmsfStateController < ApplicationController verify :method => :post, :only => [:user_pref_save], :render => { :nothing => true, :status => :method_not_allowed } + helper :all + def user_pref_save member = @project.members.find(:first, :conditions => {:user_id => User.current.id}) if member diff --git a/app/controllers/dmsf_upload_controller.rb b/app/controllers/dmsf_upload_controller.rb index dc927638..a6ef0c61 100644 --- a/app/controllers/dmsf_upload_controller.rb +++ b/app/controllers/dmsf_upload_controller.rb @@ -27,7 +27,9 @@ class DmsfUploadController < ApplicationController verify :method => :post, :only => [:upload_files, :upload_file, :commit_files], :render => { :nothing => true, :status => :method_not_allowed } - + + helper :all + def upload_files uploaded_files = params[:uploaded_files] @uploads = [] @@ -141,6 +143,14 @@ class DmsfUploadController < ApplicationController File.delete(commited_disk_filepath) files.push(file) + + unless commited_file["dmsf_file_revision"].blank? + commited_file["dmsf_file_revision"]["custom_field_values"].each do |v| + cv = CustomValue.find(:first, :conditions => ["customized_id = " + new_revision.id.to_s + " AND custom_field_id = " + v[0]]) + cv.value = v[1] + cv.save + end + end else failed_uploads.push(commited_file) end @@ -183,4 +193,4 @@ class DmsfUploadController < ApplicationController end end -end \ No newline at end of file +end diff --git a/app/models/dmsf_file.rb b/app/models/dmsf_file.rb index eaa45812..a7c001ce 100644 --- a/app/models/dmsf_file.rb +++ b/app/models/dmsf_file.rb @@ -90,6 +90,9 @@ class DmsfFile < ActiveRecord::Base return false end if Setting.plugin_redmine_dmsf["dmsf_really_delete_files"] + CustomValue.find(:all, :conditions => "customized_id = " + self.id.to_s).each do |v| + v.destroy + end self.revisions.each {|r| r.delete(true)} self.destroy else @@ -186,7 +189,22 @@ class DmsfFile < ActiveRecord::Base end projects end - + + # Overrides Redmine::Acts::Customizable::InstanceMethods#available_custom_fields + def available_custom_fields + search_project = nil + if self.project.present? + search_project = self.project + elsif self.project_id.present? + search_project = Project.find(self.project_id) + end + if search_project + search_project.all_dmsf_custom_fields + else + DmsfFileRevisionCustomField.all + end + end + def move_to(project, folder) if self.locked_for_user? errors.add_to_base(l(:error_file_is_locked)) @@ -197,7 +215,19 @@ class DmsfFile < ActiveRecord::Base new_revision.folder = folder ? folder : nil new_revision.project = folder ? folder.project : project - new_revision.comment = l(:comment_moved_from, :source => "#{self.project.identifier}:#{self.dmsf_path_str}") + new_revision.comment = l(:comment_moved_from, :source => "#{self.project.identifier}:#{self.dmsf_path_str}") + + new_revision.custom_values = [] + temp_custom_values = self.last_revision.custom_values.select{|cv| new_revision.project.all_dmsf_custom_fields.include?(cv.custom_field)}.map(&:clone) + new_revision.custom_values = temp_custom_values + + #add default value for CFs not existing + present_custom_fields = new_revision.custom_values.collect(&:custom_field).uniq + Project.find(new_revision.project_id).all_dmsf_custom_fields.each do |cf| + unless present_custom_fields.include?(cf) + new_revision.custom_values << CustomValue.new({:custom_field => cf, :value => cf.default_value}) + end + end self.folder = new_revision.folder self.project = new_revision.project @@ -212,14 +242,30 @@ class DmsfFile < ActiveRecord::Base file.name = self.name file.notification = !Setting.plugin_redmine_dmsf["dmsf_default_notifications"].blank? - new_revision = self.last_revision.clone - - new_revision.file = file - new_revision.folder = folder ? folder : nil - new_revision.project = folder ? folder.project : project - new_revision.comment = l(:comment_copied_from, :source => "#{self.project.identifier}:#{self.dmsf_path_str}") - - new_revision.save if file.save + if file.save + new_revision = self.last_revision.clone + + new_revision.file = file + new_revision.folder = folder ? folder : nil + new_revision.project = folder ? folder.project : project + new_revision.comment = l(:comment_copied_from, :source => "#{self.project.identifier}: #{self.dmsf_path_str}") + + new_revision.custom_values = [] + temp_custom_values = self.last_revision.custom_values.select{|cv| new_revision.project.all_dmsf_custom_fields.include?(cv.custom_field)}.map(&:clone) + new_revision.custom_values = temp_custom_values + + #add default value for CFs not existing + present_custom_fields = new_revision.custom_values.collect(&:custom_field).uniq + new_revision.project.all_dmsf_custom_fields.each do |cf| + unless present_custom_fields.include?(cf) + new_revision.custom_values << CustomValue.new({:custom_field => cf, :value => cf.default_value}) + end + end + + unless new_revision.save + file.delete + end + end return file end diff --git a/app/models/dmsf_file_revision.rb b/app/models/dmsf_file_revision.rb index 663dee40..bbc63bb9 100644 --- a/app/models/dmsf_file_revision.rb +++ b/app/models/dmsf_file_revision.rb @@ -24,7 +24,9 @@ class DmsfFileRevision < ActiveRecord::Base belongs_to :folder, :class_name => "DmsfFolder", :foreign_key => "dmsf_folder_id" belongs_to :deleted_by_user, :class_name => "User", :foreign_key => "deleted_by_user_id" belongs_to :project - + + acts_as_customizable + acts_as_event :title => Proc.new {|o| "#{l(:label_dmsf_updated)}: #{o.file.dmsf_path_str}"}, :url => Proc.new {|o| {:controller => 'dmsf_files', :action => 'show', :id => o.file}}, :datetime => Proc.new {|o| o.updated_at }, @@ -77,6 +79,9 @@ class DmsfFileRevision < ActiveRecord::Base ["disk_filename = :filename", {:filename => self.disk_filename}]) File.delete(self.disk_file) if dependent.length <= 1 && File.exist?(self.disk_file) DmsfFileRevisionAccess.find(:all, :conditions => ["dmsf_file_revision_id = ?", self.id]).each {|a| a.destroy} + CustomValue.find(:all, :conditions => "customized_id = " + self.id.to_s).each do |v| + v.destroy + end self.destroy else self.deleted = true @@ -128,7 +133,9 @@ class DmsfFileRevision < ActiveRecord::Base new_revision.name = self.name new_revision.folder = self.folder - + + new_revision.custom_values = self.custom_values.map(&:clone) + return new_revision end @@ -202,5 +209,20 @@ class DmsfFileRevision < ActiveRecord::Base end end end - + + # Overrides Redmine::Acts::Customizable::InstanceMethods#available_custom_fields + def available_custom_fields + search_project = nil + if self.project.present? + search_project = self.project + elsif self.project_id.present? + search_project = Project.find(self.project_id) + end + if search_project + search_project.all_dmsf_custom_fields + else + DmsfFileRevisionCustomField.all + end + end + end \ No newline at end of file diff --git a/app/models/dmsf_file_revision_custom_field.rb b/app/models/dmsf_file_revision_custom_field.rb new file mode 100644 index 00000000..30d28ec3 --- /dev/null +++ b/app/models/dmsf_file_revision_custom_field.rb @@ -0,0 +1,13 @@ +class DmsfFileRevisionCustomField < CustomField + unloadable + has_and_belongs_to_many :projects, :join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}", :foreign_key => "custom_field_id" + + def initialize(attributes = nil) + super + self.searchable = true + end + + def type_name + :DMSF_custom_field + end +end \ No newline at end of file diff --git a/app/models/dmsf_folder.rb b/app/models/dmsf_folder.rb index b0dc0ff8..38425468 100644 --- a/app/models/dmsf_folder.rb +++ b/app/models/dmsf_folder.rb @@ -27,7 +27,9 @@ class DmsfFolder < ActiveRecord::Base has_many :subfolders, :class_name => "DmsfFolder", :foreign_key => "dmsf_folder_id", :order => "title ASC" has_many :files, :class_name => "DmsfFile", :foreign_key => "dmsf_folder_id", :conditions => { :deleted => false } - belongs_to :user + belongs_to :user + + acts_as_customizable validates_presence_of :title validates_uniqueness_of :title, :scope => [:dmsf_folder_id, :project_id] @@ -152,6 +154,19 @@ class DmsfFolder < ActiveRecord::Base new_folder.title = self.title new_folder.description = self.description new_folder.user = User.current + + #copy only cfs present in destination project + temp_custom_values = self.custom_values.select{|cv| new_folder.project.all_dmsf_custom_fields.include?(cv.custom_field)}.map(&:clone) + + new_folder.custom_values = temp_custom_values + + #add default value for CFs not existing + present_custom_fields = new_folder.custom_values.collect(&:custom_field).uniq + new_folder.project.all_dmsf_custom_fields.each do |cf| + unless present_custom_fields.include?(cf) + new_folder.custom_values << CustomValue.new({:custom_field => cf, :value => cf.default_value}) + end + end return new_folder unless new_folder.save @@ -164,7 +179,22 @@ class DmsfFolder < ActiveRecord::Base end return new_folder - end + end + + # Overrides Redmine::Acts::Customizable::InstanceMethods#available_custom_fields + def available_custom_fields + search_project = nil + if self.project.present? + search_project = self.project + elsif self.project_id.present? + search_project = Project.find(self.project_id) + end + if search_project + search_project.all_dmsf_custom_fields + else + DmsfFileRevisionCustomField.all + end + end # To fullfill searchable module expectations def self.search(tokens, projects=nil, options={}) diff --git a/app/views/dmsf/_custom_fields.html.erb b/app/views/dmsf/_custom_fields.html.erb new file mode 100644 index 00000000..1fa7de3d --- /dev/null +++ b/app/views/dmsf/_custom_fields.html.erb @@ -0,0 +1,9 @@ +<% unless object.nil? %> +
+ <% object.show_custom_field_values.each do |custom_value| %> +
+ <%= label_tag("", h(custom_value.custom_field.name) + ":") %> <%= show_value(custom_value) %> +
+ <% end %> +
+<% end %> \ No newline at end of file diff --git a/app/views/dmsf/edit.html.erb b/app/views/dmsf/edit.html.erb index 919241a0..60695d76 100644 --- a/app/views/dmsf/edit.html.erb +++ b/app/views/dmsf/edit.html.erb @@ -36,6 +36,10 @@
<%= f.text_area(:description, :rows => 15, :class => "wiki-edit") %>
+ <% values = @folder ? @folder.custom_field_values : @parent ? @parent.custom_field_values : DmsfFolder.new(:project => @project).custom_field_values %> + <% values.each do |value| %> +

<%= custom_field_tag_with_label(:dmsf_folder, value) %>

+ <% end %> <%= submit_tag(create ? l(:submit_create) : l(:submit_save)) %> <% end %> diff --git a/app/views/dmsf/show.html.erb b/app/views/dmsf/show.html.erb index 9b7c7732..aa8bae89 100644 --- a/app/views/dmsf/show.html.erb +++ b/app/views/dmsf/show.html.erb @@ -19,10 +19,12 @@ <%= render(:partial => 'path', :locals => {:path => path}) %> -
-<%= textilizable(@folder.nil? ? @project.dmsf_description : @folder.description) %> +
+
+ <%= textilizable(@folder.nil? ? @project.dmsf_description : @folder.description) %> +
+ <%= render "custom_fields", :object => @folder %>
- <% form_tag({:action => "entries_operation", :id => @project, :folder_id => @folder}, :method => :post, :class => "dmfs_entries", :id => "entries_form") do @@ -60,6 +62,7 @@ form_tag({:action => "entries_operation", :id => @project, :folder_id => @folder {:action => "show", :id => @project, :folder_id => subfolder}, :class => "icon icon-folder") %>
[<%= subfolder.deep_file_count %>]
+ <%= render "custom_fields", :object => subfolder %> <%= number_to_human_size(subfolder.deep_size) %> <%= subfolder.updated_at.strftime("%Y-%m-%d %H:%M") %> @@ -110,6 +113,7 @@ form_tag({:action => "entries_operation", :id => @project, :folder_id => @folder :title => l(:title_title_version_version_download, :title => h(file.title), :version => file.version), "data-downloadurl" => "#{file.last_revision.detect_content_type}:#{h(file.name)}:#{file_download_url}") %>
<%= h(file.display_name) %>
+ <%= render "custom_fields", :object => file.last_revision %> <%= number_to_human_size(file.last_revision.size) %> diff --git a/app/views/dmsf_files/_file_new_revision.html.erb b/app/views/dmsf_files/_file_new_revision.html.erb index a7d8c048..fb34df80 100644 --- a/app/views/dmsf_files/_file_new_revision.html.erb +++ b/app/views/dmsf_files/_file_new_revision.html.erb @@ -81,12 +81,19 @@ form_for(:dmsf_file_revision, @revision, :url => {:action => "create_revision",


-

- <%= label_tag("dmsf_file_revision_comment", l(:label_comment) + ":") %> -

- <%= f.text_area(:comment, :rows=> "2", :style => "width: 99%;") %> -
-

+
+ <% @revision.custom_field_values.each do |value| %> +

<%= custom_field_tag_with_label(:dmsf_file_revision, value) %>

+ <% end %> +
+
+

+ <%= label_tag("dmsf_file_revision_comment", l(:label_comment) + ":") %> +

+ <%= f.text_area(:comment, :rows=> "2", :style => "width: 99%;") %> +
+

+

<%= submit_tag(l(:submit_create)) %> <% end %> diff --git a/app/views/dmsf_files/show.html.erb b/app/views/dmsf_files/show.html.erb index 689d0bc9..4d689e89 100644 --- a/app/views/dmsf_files/show.html.erb +++ b/app/views/dmsf_files/show.html.erb @@ -117,6 +117,9 @@


+
+ <%= render "dmsf/custom_fields", :object => revision %> +

<%= label_tag("", l(:label_comment) + ":") %> <%= h(revision.comment) %> diff --git a/app/views/dmsf_state/_user_pref.html.erb b/app/views/dmsf_state/_user_pref.html.erb index 1c276329..80747fdc 100644 --- a/app/views/dmsf_state/_user_pref.html.erb +++ b/app/views/dmsf_state/_user_pref.html.erb @@ -14,6 +14,24 @@ :selected => mail_notification)) %> <%= submit_tag(l(:submit_save), :title => l(:title_save_preferences)) %> + <% end %> + + <% form_for :project, @project, :url => project_path(@project), :html => {:method=>:post} do %> + <% custom_fields = DmsfFileRevisionCustomField.find(:all) %> + <% unless custom_fields.empty? %> +

<%=l(:label_custom_field_plural)%> + <% custom_fields.each do |custom_field| %> + + <% end %> + <%= hidden_field_tag 'project[dmsf_file_revision_custom_field_ids][]', '' %> + <%= hidden_field_tag '_method', 'put' %> +
+ <% end %> + + <%= submit_tag(l(:submit_save), :title => l(:title_save_preferences)) %> <% end %> diff --git a/app/views/dmsf_upload/_upload_file.html.erb b/app/views/dmsf_upload/_upload_file.html.erb index 2a90abb8..3264915a 100644 --- a/app/views/dmsf_upload/_upload_file.html.erb +++ b/app/views/dmsf_upload/_upload_file.html.erb @@ -66,6 +66,11 @@ end


+ <% @folder ? folder_exists = true : folder_exists = false %> + <% values = folder_exists ? @folder.custom_field_values : DmsfFileRevision.new(:file => DmsfFile.new(:project => @project)).custom_field_values %> + <% values.each do |value| %> +

<%= custom_field_tag_with_label("commited_files[#{i}][dmsf_file_revision]", value) %>

+ <% end %>

<%= label_tag("commited_files[#{i}][comment]", l(:label_comment) + ":") %>

diff --git a/assets/stylesheets/dmsf.css b/assets/stylesheets/dmsf.css index 614a23ef..e5382a23 100644 --- a/assets/stylesheets/dmsf.css +++ b/assets/stylesheets/dmsf.css @@ -217,3 +217,19 @@ p.no-ident { table.access-table tbody td, table.access-table tbody tr:hover td { border: solid 1px #D7D7D7; } + +/* Custom field */ +.dmsf-customfields { + margin: 5px 0 5px 25px; +} + +.dmsf-customfields .customfield { + +} + +.dmsf-customfields .customfield label { + font-weight: bold; + width: 100px; + display: block; + float: left; +} diff --git a/init.rb b/init.rb index acab4a8c..8fd997d0 100644 --- a/init.rb +++ b/init.rb @@ -22,7 +22,13 @@ require 'dispatcher' Dispatcher.to_prepare :redmine_dmsf do unless ProjectsHelper.included_modules.include?(ProjectTabsExtended) ProjectsHelper.send(:include, ProjectTabsExtended) + end + + unless CustomFieldsHelper.included_modules.include?(CustomFieldsHelper) + CustomFieldsHelper.send(:include, RedmineDmsf::Patches::CustomFieldsHelper) end + + Project.send(:include, RedmineDmsf::Patches::ProjectPatch) end Redmine::Plugin.register :redmine_dmsf do diff --git a/lib/redmine_dmsf.rb b/lib/redmine_dmsf.rb new file mode 100644 index 00000000..6e870418 --- /dev/null +++ b/lib/redmine_dmsf.rb @@ -0,0 +1,6 @@ +require 'redmine_dmsf/patches/custom_fields_helper' +require 'redmine_dmsf/patches/acts_as_customizable' +require 'redmine_dmsf/patches/project_patch' + +module RedmineDmsf +end diff --git a/lib/redmine_dmsf/patches/acts_as_customizable.rb b/lib/redmine_dmsf/patches/acts_as_customizable.rb new file mode 100644 index 00000000..fbc859dd --- /dev/null +++ b/lib/redmine_dmsf/patches/acts_as_customizable.rb @@ -0,0 +1,16 @@ +module Redmine + module Acts + module Customizable + module InstanceMethods + def available_custom_fields + cf_classname = self.class.name == 'DmsfFolder' ? 'DmsfFileRevision' : self.class.name + CustomField.find(:all, :conditions => "type = '#{cf_classname}CustomField'", :order => 'position') + end + + def show_custom_field_values + custom_field_values.delete_if { |x| (!x.id && x.id.blank?) || x.value.blank? } + end + end + end + end +end \ No newline at end of file diff --git a/lib/redmine_dmsf/patches/custom_fields_helper.rb b/lib/redmine_dmsf/patches/custom_fields_helper.rb new file mode 100644 index 00000000..4b63b583 --- /dev/null +++ b/lib/redmine_dmsf/patches/custom_fields_helper.rb @@ -0,0 +1,16 @@ +module RedmineDmsf + module Patches + module CustomFieldsHelper + def self.included(base) + base.class_eval do + alias_method_chain :custom_fields_tabs, :customer_tab + end + end + + def custom_fields_tabs_with_customer_tab + tabs = custom_fields_tabs_without_customer_tab + tabs << {:name => 'DmsfFileRevisionCustomField', :partial => 'custom_fields/index', :label => :DMSF_custom_field} + end + end + end +end diff --git a/lib/redmine_dmsf/patches/project_patch.rb b/lib/redmine_dmsf/patches/project_patch.rb new file mode 100644 index 00000000..d200430d --- /dev/null +++ b/lib/redmine_dmsf/patches/project_patch.rb @@ -0,0 +1,9 @@ +module RedmineDmsf + module Patches + module ProjectPatch + def all_dmsf_custom_fields + @all_dmsf_custom_fields ||= (DmsfFileRevisionCustomField.for_all + dmsf_file_revision_custom_fields).uniq.sort + end + end + end +end \ No newline at end of file