$ cd /var/www/redmine
$ export RAILS_ENV="production"
$ ruby script/generate redmine_plugin repository
create vendor/plugins/redmine_repository/app/controllers
create vendor/plugins/redmine_repository/app/helpers
create vendor/plugins/redmine_repository/app/models
create vendor/plugins/redmine_repository/app/views
create vendor/plugins/redmine_repository/db/migrate
create vendor/plugins/redmine_repository/lib/tasks
create vendor/plugins/redmine_repository/assets/images
create vendor/plugins/redmine_repository/assets/javascripts
create vendor/plugins/redmine_repository/assets/stylesheets
create vendor/plugins/redmine_repository/lang
create vendor/plugins/redmine_repository/README
create vendor/plugins/redmine_repository/init.rb
create vendor/plugins/redmine_repository/lang/en.yml
require 'redmine' require 'dispatcher' Redmine::Plugin.register :redmine_repository do name 'Redmine Repository plugin' author 'Sanny' description 'This is a reposirory plugin for Redmine' version '0.0.2' requires_redmine :version_or_higher => '1.1.2' end
$ cp app/views/repositories/_dir_lsit.rhtml vendor/plugins/redmine_repository/app/views/repositories
$ cp app/views/repositories/_dir_lsit_content.rhtml vendor/plugins/redmine_repository/app/views/repositories
$ cp app/views/repositories/show.rhtml vendor/plugins/redmine_repository/app/views/repositories
<% if authorize_for('repositories', 'entries_operation') %> <div style="float: right;"> <%= submit_tag(l(:Download), :name => "download_entries") %> </div> <% end %>
<% form_tag({:action => "entries_operation"}, :method => :post, :id => "Entries") do %> ... <% if authorize_for('repositories', 'entries_operation') %> <div style="float: right;"> <%= submit_tag(l(:Download), :name => "download_entries") %> </div> <% end %> <p> </p> <% end %>
<% if entry.is_dir? %> <span class="expander" onclick="<%= remote_function :url => {:action => 'show', :id => @project, :path => to_path_param(ent_path), :rev => @rev, :depth => (depth + 1), :parent_id => tr_id}, :method => :get, :update => { :success => tr_id }, :position => :after, :success => "scmEntryLoaded('#{tr_id}')", :condition => "scmEntryClick('#{tr_id}')"%>"> </span> <% end %>
<% if entry.is_dir? %> <span class="expander" onclick="<%= remote_function :url => {:action => 'show', :id => @project, :path => to_path_param(entry.path), :rev => @rev, :depth => (depth + 1), :parent_id => tr_id, :p arent_val => entry.path}, :method => :get, :update => { :success => tr_id }, :position => :after, :success => "scmEntryLoaded('#{tr_id}')", :complete => "checkBranch('#{tr_id}', getParentNodeChecked('#{params[:parent_val]}'))", :condition => "scmEntryClick('#{tr_id}')"%>"> </span> <span><%= check_box_tag("folders[]", entry.path, false, :id => params[:parent_id], :onclick => "checkBranch('#{tr_id}', this.checked);" ) if authorize_for('repositories', 'entries_operation') %></span> <% else %> <span style="padding-left: 8px"> </span> <span><%= check_box_tag("files[]", entry.path, false, :id => params[:parent_id]) if authorize_for('repositories', 'entries_operation') %></span> <% end %>
getParentNodeChecked(parentVal)
- determines the state of the checkbox of the parent of this tree node,checkBranch(parentId, checked)
- sets the checkboxes of the descendants of the tree node to the state of the parent (roughly speaking, if a directory is selected, then all the subdirectories and files in this directory are highlighted). function getParentNodeChecked(parentVal) { var form = document.getElementById('Entries'); for (var i=0;i<form.elements.length;i++) { var e = form.elements[i]; if(e.type=='checkbox' && e.value == parentVal) return e.checked; } } function checkBranch(parentId, checked) { var allchecked = true; var has_check_tree = false; var form = document.getElementById('Entries'); for (var i=0;i<form.elements.length;i++) { var e = form.elements[i]; if(e.type=='checkbox') { if(e.id == parentId) { e.checked = !checked; e.click(); } allchecked = allchecked && e.checked; if(e.name == "check_tree") has_check_tree = true; } } if(has_check_tree) form.check_tree.checked = allchecked; }
... <% content_for :header_tags do %> <%= stylesheet_link_tag "scm" %> <%= javascript_include_tag "repository.js", :plugin => "redmine_repository" %> <% end %>
require 'zip/zip' require 'zip/zipfilesystem' class RepositoryZip attr_reader :file_count def initialize() @zip = Tempfile.new(["repository_zip",".zip"]) @zip_file = Zip::ZipOutputStream.new(@zip.path) @file_count = 0 end def finish @zip_file.close unless @zip_file.nil? @zip.path unless @zip.nil? end def close @zip_file.close unless @zip_file.nil? @zip.close unless @zip.nil? end def add_file(file, cat) @zip_file.put_next_entry(file) @zip_file.write(cat) @file_count += 1 end def add_folder(folder) @zip_file.put_next_entry(folder + "/") end end
require 'tree' require_dependency 'application_controller' require_dependency 'repositories_controller' require_dependency 'repository_zip' module RepositoriesControllerPatch def self.included(base) # :nodoc: base.extend(ClassMethods) base.send(:include, InstanceMethods) base.class_eval do unloadable # unloadable end end module ClassMethods end module InstanceMethods def entries_operation selected_folders = params[:folders].nil? ? [] : params[:folders] selected_files = params[:files].nil? ? [] : params[:files] if selected_folders.empty? && selected_files.empty? flash[:warning] = l(:warning_no_entries_selected) redirect_to :action => "show", :id => @project, :path => @path return end # make a selected files and folders tree selected_tree = Tree::TreeNode.new(".", "root") selected_files.each do |file| folder = Pathname.new(file).dirname.to_s selected_tree_node = selected_tree if !folder.match(/^\.+$/) folder.split("/").each do if selected_tree_node[folder].nil? selected_tree_node = selected_tree_node.add(Tree::TreeNode.new(folder, "folder")) else selected_tree_node = selected_tree_node[folder] end end selected_tree_node << Tree::TreeNode.new(file, "file") else selected_tree << Tree::TreeNode.new(file, "file") end end selected_folders.each do |folder| selected_tree_node = selected_tree folder.split("/").each do if selected_tree_node[folder].nil? selected_tree_node = selected_tree_node.add(Tree::TreeNode.new(folder, "folder")) else selected_tree_node = selected_tree_node[folder] end end selected_tree_node << Tree::TreeNode.new(file, "file") else selected_tree << Tree::TreeNode.new(file, "file") end end selected_folders.each do |folder| selected_tree_node = selected_tree folder.split("/").each do if selected_tree_node[folder].nil? selected_tree_node = selected_tree_node.add(Tree::TreeNode.new(folder, "folder")) else selected_tree_node = selected_tree_node[folder] end end end begin if !params[:email_entries].blank? email_entries(selected_tree) else download_entries(selected_tree) end rescue => e flash[:warning] = l(:error_in_getting_files) + " (" + e.message + ")" redirect_to :action => "show", :id => @project end end def download_entries(selected_tree) zip = RepositoryZip.new zip_entries(zip, selected_tree) send_file(zip.finish, :filename => filename_for_content_disposition(@project.name + "-" + DateTime.now.strftime("%y%m%d%H%M%S") + ".zip"), :type => "application/zip", :disposition => "attachment") ensure zip.close unless zip.nil? end def zip_entries(zip, selected_tree) selected_tree.children.each do |node| if node.content == "file" zip.add_file(node.name, @repository.cat(node.name, @rev)) else zip.add_folder(node.name) if node.hasChildren? # add selected subfolders zip_entries(zip, node) else # add all subfolders with files entries = @repository.entries(node.name, @rev) entries.each do |entry| node << Tree::TreeNode.new(entry.path, entry.is_dir? ? "folder" : "file") end end zip_entries(zip, node) end end zip end end # of InstaceMethods end # of module RepositoriesController.send(:include, RepositoriesControllerPatch)
entries_operation
method entries_operation
responsible for generating a list of files and folders for archiving.download_entries
method is responsible for downloading the archive by the user.zip_entries
method zip_entries
responsible for archiving the selected files and folders. require 'redmine' require 'dispatcher' require 'repositories_controller_patch' Redmine::Plugin.register :redmine_repository do name 'Redmine Repository plugin' author 'Sanny' description 'This is a reposirory plugin for Redmine' version '0.0.2' requires_redmine :version_or_higher => '1.1.2' end Redmine::AccessControl.map do |map| map.project_module :repository do |map| map.permission :operations, :repositories => [:entries_operation] end end
ru: Download: "Download" warning_no_entries_selected: " " error_in_getting_files: " " permission_operations: " "
Source: https://habr.com/ru/post/130088/
All Articles