рдПрдХ Redmine рдкреНрд▓рдЧрдЗрди рд▓реЗрдЦрди

рд╢рд╛рдпрдж рдХрдИ рдиреЗ рд░реЗрдбрдорд╛рдЗрди рдкрд░рд┐рдпреЛрдЬрдирд╛ рдкреНрд░рдмрдВрдзрди рдкреНрд░рдгрд╛рд▓реА рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реБрдирд╛ рд╣реИ, рдФрд░ рдХреБрдЫ рдиреЗ рдЕрдкрдиреЗ рдХрд╛рдо рдореЗрдВ рдЗрд╕рдХрд╛ рдЗрд╕реНрддреЗрдорд╛рд▓ рднреА рдХрд┐рдпрд╛ рд╣реЛрдЧрд╛ред рд░реЗрдбрдорд╛рдЗрди рдПрдХ рдХрд╛рдлреА рд▓рдЪреАрд▓рд╛ рдХреНрд░реЙрд╕-рдкреНрд▓реЗрдЯрдлрд╝реЙрд░реНрдо рд╕рд┐рд╕реНрдЯрдо рд╣реИ рдЬрд┐рд╕реЗ рдкреНрд░рд╕рд┐рджреНрдз рд░реВрдмреА рдСрди рд░реЗрд▓реНрд╕ рдлреНрд░реЗрдорд╡рд░реНрдХ рдореЗрдВ рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рд╣реИред рдЗрд╕ рддрд░рд╣ рдХреА рдЕрдзрд┐рдХрд╛рдВрд╢ рдкреНрд░рдгрд╛рд▓рд┐рдпреЛрдВ рдХреА рддрд░рд╣, Redmine рдЖрдкрдХреЛ рдерд░реНрдб-рдкрд╛рд░реНрдЯреА рдкреНрд▓рдЧ-рдЗрди рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЕрдкрдиреА рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдлрд┐рд▓рд╣рд╛рд▓, рдЕрд▓рдЧ-рдЕрд▓рдЧ рд╕реНрд╡рд╛рдж рдФрд░ рд░рдВрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдЗрдирдореЗрдВ рд╕реЗ рдПрдХ рд╣рдЬрд╛рд░ рд╕реЗ рдЕрдзрд┐рдХ рдкреНрд▓рдЧрдЗрдиреНрд╕ рдореМрдЬреВрдж рд╣реИрдВред рдореИрдВ рдЙрдирдореЗрдВ рд╕реЗ рдПрдХ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдФрд░ рдЗрд╕рдХреЗ рдЙрджрд╛рд╣рд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рд░реЗрдбрдорд╛рдЗрди рдкреНрд▓рдЧрдЗрди рдХреИрд╕реЗ рд▓рд┐рдЦрдирд╛ рд╣реИред

рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдкреНрд▓рдЧрдЗрди - рдПрдХ рдкреНрд▓рдЧрдЗрди рдЬреЛ рдЖрдкрдХреЛ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА (рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА) рд╕реЗ рдПрдХ рдЬрд╝рд┐рдк рд╕рдВрдЧреНрд░рд╣ рдореЗрдВ рдлрд╝рд╛рдЗрд▓реЛрдВ рдФрд░ рдлрд╝реЛрд▓реНрдбрд░реЛрдВ рдХреЛ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред Redmine рдкреНрд▓рдЧрдЗрдиреНрд╕ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╡рд┐рдЬреБрдЕрд▓ рдЧрд╛рдЗрдб рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред
рддреЛ, рдЪрд▓реЛ рдкреНрд▓рдЧрдЗрди рд▓рд┐рдЦрдирд╛ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВред рд╕рдм рдХреБрдЫ рд╣реИ рдХрд┐ рд▓рд┐рдирдХреНрд╕ рдУрдПрд╕ рдХреЗ рд╕рд╛рде рдПрдХ рд╡реЗрдм рд╕рд░реНрд╡рд░ рдкрд░ рд╕реНрдерд╛рдкрд┐рдд рдЪрд┐рдВрддрд╛рдУрдВ рдХреЛ рдХрдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рд╣реИред
рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рд╣рдо рдЙрд╕ рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдореЗрдВ рдЬрд╛рддреЗ рд╣реИрдВ рдЬрд╣рд╛рдБ Redmine рд╕реНрдерд╛рдкрд┐рдд рд╣реИ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, / var / www / redmine):

$ cd /var/www/redmine

рдкрд░реНрдпрд╛рд╡рд░рдг рдЪрд░ R рдирд╛рдЦреВрди_ENV рд╕реЗрдЯ рдХрд░реЗрдВ:

$ 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

рд╡рд┐рдХреНрд░реЗрддрд╛ / рдкреНрд▓рдЧрдЗрдиреНрд╕ / redmine_repository / init.rb рдлрд╝рд╛рдЗрд▓ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░реЗрдВ, рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░реЗрдВ
рдЗрд╕рдореЗрдВ рдкреНрд▓рдЧрд┐рди, рд▓реЗрдЦрдХ рдХрд╛ рдирд╛рдо рдФрд░ рдиреНрдпреВрдирддрдо рд╕рдВрд╕реНрдХрд░рдг рдХрд╛ рд╡рд┐рд╡рд░рдг рд╣реЛрддрд╛ рд╣реИ, рдЬрд┐рд╕рдХреЗ рд▓рд┐рдП рдкреНрд▓рдЧрдЗрди рд▓рд┐рдЦрд╛ рдЧрдпрд╛ рд╣реИ:
 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

_Dir_lsit.rhtml рдлрд╝рд╛рдЗрд▓ рдХреЛ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдлрд╝рд╛рдЗрд▓ рд╕рд┐рд╕реНрдЯрдо рдЯреНрд░реА рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрд╕реНрд╡реАрдХрд╛рд░ рдХрд░ рджрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рд╡рд╣рд╛рдВ рд╣рдо рдбрд╛рдЙрдирд▓реЛрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ "рдбрд╛рдЙрдирд▓реЛрдб" рдмрдЯрди рдЬреЛрдбрд╝ рджреЗрдВрдЧреЗ:
 <% if authorize_for('repositories', 'entries_operation') %> <div style="float: right;"> <%= submit_tag(l(:Download), :name => "download_entries") %> </div> <% end %> 

рдмрдЯрди рдХреЛ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╕рднреА рдХреЛрдб рдХреЛ form_tag рдореЗрдВ рд▓рдкреЗрдЯреЗрдВ:
 <% 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 %> 

рдЕрдм рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдбрд┐рд╕реНрдкреНрд▓реЗ рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐ рдХреЗ рд▓рд┐рдП рдПрдХ рдЪреЗрдХрдмреЙрдХреНрд╕ рдЬреЛрдбрд╝реЗрдВред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, _dir_lsit_content.rhtml рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдирд┐рдореНрди рдкрд░рд┐рд╡рд░реНрддрди рдХрд░реЗрдВ:
рдХреЗ рдмрдЬрд╛рдп
 <% 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) - рдЗрд╕ рдЯреНрд░реА рдиреЛрдб рдХреЗ рдЬрдирдХ рдХреЗ рдЪреЗрдХрдмреЙрдХреНрд╕ рдХреА рд╕реНрдерд┐рддрд┐ рдХреЛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддрд╛ рд╣реИ,
checkBranch(parentId, checked) - рдЯреНрд░реА рдиреЛрдб рдХреЗ рд╡рдВрд╢рдЬреЛрдВ рдХреЗ рдЪреЗрдХрдмреЙрдХреНрд╕ рдХреЛ рдЕрднрд┐рднрд╛рд╡рдХ рдХреЗ рд░реВрдк рдореЗрдВ рд░рд╛рдЬреНрдп рдореЗрдВ рд╕реЗрдЯ рдХрд░рддрд╛ рд╣реИ (рдореЛрдЯреЗ рддреМрд░ рдкрд░, рдпрджрд┐ рдХреЛрдИ рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдЪреБрдиреА рдЬрд╛рддреА рд╣реИ, рддреЛ рдЗрд╕ рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдореЗрдВ рд╕рднреА рдЙрдкрдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛рдПрдБ рдФрд░ рдлрд╝рд╛рдЗрд▓реЗрдВ рдЪрдпрдирд┐рдд рд╣реИрдВ)ред
рдЙрдиреНрд╣реЗрдВ рдирдИ рд╕рдВрдкрддреНрддрд┐ / javascripts / repository.js рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рдмрдирд╛рдПрдБ
 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; } 

рд╣рдорд╛рд░реА рдирдИ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореИрдкрд┐рдВрдЧ (show.rhtml рдлрд╝рд╛рдЗрд▓ рдореЗрдВ) рд╕реЗ рд╣рдорд╛рд░реЗ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА.рдЬреЗрдПрд╕ рдХреЛ рдХрдиреЗрдХреНрдЯ рдХрд░реЗрдВ:
 ... <% 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 

рдЕрдм рд╣рдо Redmine рдореЗрдВ рдореМрдЬреВрдж рд░рд┐рдкреЙрдЬрд┐рдЯрд░реАрдХрдВрдЯреНрд░реЛрд▓рд░ рдХреНрд▓рд╛рд╕ рдХреЛ "рдкреИрдЪ" рдХрд░реЗрдВрдЧреЗ, рдЗрд╕рдореЗрдВ рдХрдИ рддрд░реАрдХреЗ рдЬреЛрдбрд╝рдХрд░ (рдлрд╝рд╛рдЗрд▓ lib / repositories_controller_patch.rb)ред рдореИрдВ рдЗрд╕ "рдкреИрдЪ" рдХреЗ рддрд░реНрдХ рдкрд░ рдзреНрдпрд╛рди рдирд╣реАрдВ рджреВрдВрдЧрд╛, рдореИрдВ рд╕рд┐рд░реНрдл рдХреЛрдб рджреЗ рджреВрдВрдЧрд╛:
 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 рд╡рд┐рдзрд┐ рд╕рдВрдЧреНрд░рд╣ рдХреЗ рд▓рд┐рдП рдлрд╝рд╛рдЗрд▓реЛрдВ рдФрд░ рдлрд╝реЛрд▓реНрдбрд░реЛрдВ рдХреА рд╕реВрдЪреА рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИред
рдбрд╛рдЙрдирд▓реЛрдб_реЗрдВрдЯреНрд░реА рд╡рд┐рдзрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рджреНрд╡рд╛рд░рд╛ рд╕рдВрдЧреНрд░рд╣ рдХреЛ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИред
рдЪрдпрдирд┐рдд рдлрд╝рд╛рдЗрд▓реЛрдВ рдФрд░ рдлрд╝реЛрд▓реНрдбрд░реЛрдВ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП zip_entries рд╡рд┐рдзрд┐ рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИред

рдмрд╕ рдЗрддрдирд╛ рд╣реАред рдпрд╣ рдХреЗрд╡рд▓ Redmine рд╕рд┐рд╕реНрдЯрдо рдХреЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдФрд░ рдкреНрд▓рдЧрдЗрди рдХреЗ рд╕реНрдерд╛рдиреАрдпрдХрд░рдг рдХреЗ рд▓рд┐рдП рдлрд╛рдЗрд▓ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдиреБрдорддрд┐рдпрд╛рдБ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдиреА рд╣реБрдИ рд╣реИред рдЕрдиреБрдорддрд┐рдпрд╛рдБ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП init.rb рдлрд╝рд╛рдЗрд▓ рд╕рдВрдкрд╛рджрд┐рдд рдХрд░реЗрдВ:
 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.yml рдлрд╝рд╛рдЗрд▓ рдмрдирд╛рдПрдБ:
 ru: Download: "Download" warning_no_entries_selected: "  " error_in_getting_files: "    " permission_operations: "    " 

рд╣рдо Redmine рдХреЛ рдкреБрдирд░рд╛рд░рдВрдн рдХрд░рддреЗ рд╣реИрдВ, рд╕рд┐рд╕реНрдЯрдо рдХреЗ рд╡рд┐рднрд┐рдиреНрди рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рдВрдЧреНрд░рд╣ рдореЗрдВ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреЛ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдиреБрдорддрд┐рдпреЛрдВ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред

Source: https://habr.com/ru/post/In130088/


All Articles