##// END OF EJS Templates
Code cleanup....
Jean-Philippe Lang -
r15504:d8de3106ec5f
parent child
Show More
@@ -1,433 +1,439
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require 'SVG/Graph/Bar'
18 require 'SVG/Graph/Bar'
19 require 'SVG/Graph/BarHorizontal'
19 require 'SVG/Graph/BarHorizontal'
20 require 'digest/sha1'
20 require 'digest/sha1'
21 require 'redmine/scm/adapters'
21 require 'redmine/scm/adapters'
22
22
23 class ChangesetNotFound < Exception; end
23 class ChangesetNotFound < Exception; end
24 class InvalidRevisionParam < Exception; end
24 class InvalidRevisionParam < Exception; end
25
25
26 class RepositoriesController < ApplicationController
26 class RepositoriesController < ApplicationController
27 menu_item :repository
27 menu_item :repository
28 menu_item :settings, :only => [:new, :create, :edit, :update, :destroy, :committers]
28 menu_item :settings, :only => [:new, :create, :edit, :update, :destroy, :committers]
29 default_search_scope :changesets
29 default_search_scope :changesets
30
30
31 before_action :find_project_by_project_id, :only => [:new, :create]
31 before_action :find_project_by_project_id, :only => [:new, :create]
32 before_action :build_new_repository_from_params, :only => [:new, :create]
32 before_action :find_repository, :only => [:edit, :update, :destroy, :committers]
33 before_action :find_repository, :only => [:edit, :update, :destroy, :committers]
33 before_action :find_project_repository, :except => [:new, :create, :edit, :update, :destroy, :committers]
34 before_action :find_project_repository, :except => [:new, :create, :edit, :update, :destroy, :committers]
34 before_action :find_changeset, :only => [:revision, :add_related_issue, :remove_related_issue]
35 before_action :find_changeset, :only => [:revision, :add_related_issue, :remove_related_issue]
35 before_action :authorize
36 before_action :authorize
36 accept_rss_auth :revisions
37 accept_rss_auth :revisions
37
38
38 rescue_from Redmine::Scm::Adapters::CommandFailed, :with => :show_error_command_failed
39 rescue_from Redmine::Scm::Adapters::CommandFailed, :with => :show_error_command_failed
39
40
40 def new
41 def new
41 scm = params[:repository_scm] || (Redmine::Scm::Base.all & Setting.enabled_scm).first
42 @repository = Repository.factory(scm)
43 @repository.is_default = @project.repository.nil?
42 @repository.is_default = @project.repository.nil?
44 @repository.project = @project
45 end
43 end
46
44
47 def create
45 def create
48 @repository = Repository.factory(params[:repository_scm])
46 if @repository.save
49 @repository.safe_attributes = params[:repository]
50 @repository.project = @project
51 if request.post? && @repository.save
52 redirect_to settings_project_path(@project, :tab => 'repositories')
47 redirect_to settings_project_path(@project, :tab => 'repositories')
53 else
48 else
54 render :action => 'new'
49 render :action => 'new'
55 end
50 end
56 end
51 end
57
52
58 def edit
53 def edit
59 end
54 end
60
55
61 def update
56 def update
62 @repository.safe_attributes = params[:repository]
57 @repository.safe_attributes = params[:repository]
63 @repository.project = @project
64 if @repository.save
58 if @repository.save
65 redirect_to settings_project_path(@project, :tab => 'repositories')
59 redirect_to settings_project_path(@project, :tab => 'repositories')
66 else
60 else
67 render :action => 'edit'
61 render :action => 'edit'
68 end
62 end
69 end
63 end
70
64
71 def committers
65 def committers
72 @committers = @repository.committers
66 @committers = @repository.committers
73 @users = @project.users.to_a
67 @users = @project.users.to_a
74 additional_user_ids = @committers.collect(&:last).collect(&:to_i) - @users.collect(&:id)
68 additional_user_ids = @committers.collect(&:last).collect(&:to_i) - @users.collect(&:id)
75 @users += User.where(:id => additional_user_ids).to_a unless additional_user_ids.empty?
69 @users += User.where(:id => additional_user_ids).to_a unless additional_user_ids.empty?
76 @users.compact!
70 @users.compact!
77 @users.sort!
71 @users.sort!
78 if request.post? && params[:committers].is_a?(Hash)
72 if request.post? && params[:committers].is_a?(Hash)
79 # Build a hash with repository usernames as keys and corresponding user ids as values
73 # Build a hash with repository usernames as keys and corresponding user ids as values
80 @repository.committer_ids = params[:committers].values.inject({}) {|h, c| h[c.first] = c.last; h}
74 @repository.committer_ids = params[:committers].values.inject({}) {|h, c| h[c.first] = c.last; h}
81 flash[:notice] = l(:notice_successful_update)
75 flash[:notice] = l(:notice_successful_update)
82 redirect_to settings_project_path(@project, :tab => 'repositories')
76 redirect_to settings_project_path(@project, :tab => 'repositories')
83 end
77 end
84 end
78 end
85
79
86 def destroy
80 def destroy
87 @repository.destroy if request.delete?
81 @repository.destroy if request.delete?
88 redirect_to settings_project_path(@project, :tab => 'repositories')
82 redirect_to settings_project_path(@project, :tab => 'repositories')
89 end
83 end
90
84
91 def show
85 def show
92 @repository.fetch_changesets if @project.active? && Setting.autofetch_changesets? && @path.empty?
86 @repository.fetch_changesets if @project.active? && Setting.autofetch_changesets? && @path.empty?
93
87
94 @entries = @repository.entries(@path, @rev)
88 @entries = @repository.entries(@path, @rev)
95 @changeset = @repository.find_changeset_by_name(@rev)
89 @changeset = @repository.find_changeset_by_name(@rev)
96 if request.xhr?
90 if request.xhr?
97 @entries ? render(:partial => 'dir_list_content') : head(200)
91 @entries ? render(:partial => 'dir_list_content') : head(200)
98 else
92 else
99 (show_error_not_found; return) unless @entries
93 (show_error_not_found; return) unless @entries
100 @changesets = @repository.latest_changesets(@path, @rev)
94 @changesets = @repository.latest_changesets(@path, @rev)
101 @properties = @repository.properties(@path, @rev)
95 @properties = @repository.properties(@path, @rev)
102 @repositories = @project.repositories
96 @repositories = @project.repositories
103 render :action => 'show'
97 render :action => 'show'
104 end
98 end
105 end
99 end
106
100
107 alias_method :browse, :show
101 alias_method :browse, :show
108
102
109 def changes
103 def changes
110 @entry = @repository.entry(@path, @rev)
104 @entry = @repository.entry(@path, @rev)
111 (show_error_not_found; return) unless @entry
105 (show_error_not_found; return) unless @entry
112 @changesets = @repository.latest_changesets(@path, @rev, Setting.repository_log_display_limit.to_i)
106 @changesets = @repository.latest_changesets(@path, @rev, Setting.repository_log_display_limit.to_i)
113 @properties = @repository.properties(@path, @rev)
107 @properties = @repository.properties(@path, @rev)
114 @changeset = @repository.find_changeset_by_name(@rev)
108 @changeset = @repository.find_changeset_by_name(@rev)
115 end
109 end
116
110
117 def revisions
111 def revisions
118 @changeset_count = @repository.changesets.count
112 @changeset_count = @repository.changesets.count
119 @changeset_pages = Paginator.new @changeset_count,
113 @changeset_pages = Paginator.new @changeset_count,
120 per_page_option,
114 per_page_option,
121 params['page']
115 params['page']
122 @changesets = @repository.changesets.
116 @changesets = @repository.changesets.
123 limit(@changeset_pages.per_page).
117 limit(@changeset_pages.per_page).
124 offset(@changeset_pages.offset).
118 offset(@changeset_pages.offset).
125 includes(:user, :repository, :parents).
119 includes(:user, :repository, :parents).
126 to_a
120 to_a
127
121
128 respond_to do |format|
122 respond_to do |format|
129 format.html { render :layout => false if request.xhr? }
123 format.html { render :layout => false if request.xhr? }
130 format.atom { render_feed(@changesets, :title => "#{@project.name}: #{l(:label_revision_plural)}") }
124 format.atom { render_feed(@changesets, :title => "#{@project.name}: #{l(:label_revision_plural)}") }
131 end
125 end
132 end
126 end
133
127
134 def raw
128 def raw
135 entry_and_raw(true)
129 entry_and_raw(true)
136 end
130 end
137
131
138 def entry
132 def entry
139 entry_and_raw(false)
133 entry_and_raw(false)
140 end
134 end
141
135
142 def entry_and_raw(is_raw)
136 def entry_and_raw(is_raw)
143 @entry = @repository.entry(@path, @rev)
137 @entry = @repository.entry(@path, @rev)
144 (show_error_not_found; return) unless @entry
138 (show_error_not_found; return) unless @entry
145
139
146 # If the entry is a dir, show the browser
140 # If the entry is a dir, show the browser
147 (show; return) if @entry.is_dir?
141 (show; return) if @entry.is_dir?
148
142
149 if is_raw
143 if is_raw
150 # Force the download
144 # Force the download
151 send_opt = { :filename => filename_for_content_disposition(@path.split('/').last) }
145 send_opt = { :filename => filename_for_content_disposition(@path.split('/').last) }
152 send_type = Redmine::MimeType.of(@path)
146 send_type = Redmine::MimeType.of(@path)
153 send_opt[:type] = send_type.to_s if send_type
147 send_opt[:type] = send_type.to_s if send_type
154 send_opt[:disposition] = disposition(@path)
148 send_opt[:disposition] = disposition(@path)
155 send_data @repository.cat(@path, @rev), send_opt
149 send_data @repository.cat(@path, @rev), send_opt
156 else
150 else
157 if !@entry.size || @entry.size <= Setting.file_max_size_displayed.to_i.kilobyte
151 if !@entry.size || @entry.size <= Setting.file_max_size_displayed.to_i.kilobyte
158 content = @repository.cat(@path, @rev)
152 content = @repository.cat(@path, @rev)
159 (show_error_not_found; return) unless content
153 (show_error_not_found; return) unless content
160
154
161 if content.size <= Setting.file_max_size_displayed.to_i.kilobyte &&
155 if content.size <= Setting.file_max_size_displayed.to_i.kilobyte &&
162 is_entry_text_data?(content, @path)
156 is_entry_text_data?(content, @path)
163 # TODO: UTF-16
157 # TODO: UTF-16
164 # Prevent empty lines when displaying a file with Windows style eol
158 # Prevent empty lines when displaying a file with Windows style eol
165 # Is this needed? AttachmentsController simply reads file.
159 # Is this needed? AttachmentsController simply reads file.
166 @content = content.gsub("\r\n", "\n")
160 @content = content.gsub("\r\n", "\n")
167 end
161 end
168 end
162 end
169 @changeset = @repository.find_changeset_by_name(@rev)
163 @changeset = @repository.find_changeset_by_name(@rev)
170 end
164 end
171 end
165 end
172 private :entry_and_raw
166 private :entry_and_raw
173
167
174 def is_entry_text_data?(ent, path)
168 def is_entry_text_data?(ent, path)
175 # UTF-16 contains "\x00".
169 # UTF-16 contains "\x00".
176 # It is very strict that file contains less than 30% of ascii symbols
170 # It is very strict that file contains less than 30% of ascii symbols
177 # in non Western Europe.
171 # in non Western Europe.
178 return true if Redmine::MimeType.is_type?('text', path)
172 return true if Redmine::MimeType.is_type?('text', path)
179 # Ruby 1.8.6 has a bug of integer divisions.
173 # Ruby 1.8.6 has a bug of integer divisions.
180 # http://apidock.com/ruby/v1_8_6_287/String/is_binary_data%3F
174 # http://apidock.com/ruby/v1_8_6_287/String/is_binary_data%3F
181 return false if ent.is_binary_data?
175 return false if ent.is_binary_data?
182 true
176 true
183 end
177 end
184 private :is_entry_text_data?
178 private :is_entry_text_data?
185
179
186 def annotate
180 def annotate
187 @entry = @repository.entry(@path, @rev)
181 @entry = @repository.entry(@path, @rev)
188 (show_error_not_found; return) unless @entry
182 (show_error_not_found; return) unless @entry
189
183
190 @annotate = @repository.scm.annotate(@path, @rev)
184 @annotate = @repository.scm.annotate(@path, @rev)
191 if @annotate.nil? || @annotate.empty?
185 if @annotate.nil? || @annotate.empty?
192 @annotate = nil
186 @annotate = nil
193 @error_message = l(:error_scm_annotate)
187 @error_message = l(:error_scm_annotate)
194 else
188 else
195 ann_buf_size = 0
189 ann_buf_size = 0
196 @annotate.lines.each do |buf|
190 @annotate.lines.each do |buf|
197 ann_buf_size += buf.size
191 ann_buf_size += buf.size
198 end
192 end
199 if ann_buf_size > Setting.file_max_size_displayed.to_i.kilobyte
193 if ann_buf_size > Setting.file_max_size_displayed.to_i.kilobyte
200 @annotate = nil
194 @annotate = nil
201 @error_message = l(:error_scm_annotate_big_text_file)
195 @error_message = l(:error_scm_annotate_big_text_file)
202 end
196 end
203 end
197 end
204 @changeset = @repository.find_changeset_by_name(@rev)
198 @changeset = @repository.find_changeset_by_name(@rev)
205 end
199 end
206
200
207 def revision
201 def revision
208 respond_to do |format|
202 respond_to do |format|
209 format.html
203 format.html
210 format.js {render :layout => false}
204 format.js {render :layout => false}
211 end
205 end
212 end
206 end
213
207
214 # Adds a related issue to a changeset
208 # Adds a related issue to a changeset
215 # POST /projects/:project_id/repository/(:repository_id/)revisions/:rev/issues
209 # POST /projects/:project_id/repository/(:repository_id/)revisions/:rev/issues
216 def add_related_issue
210 def add_related_issue
217 issue_id = params[:issue_id].to_s.sub(/^#/,'')
211 issue_id = params[:issue_id].to_s.sub(/^#/,'')
218 @issue = @changeset.find_referenced_issue_by_id(issue_id)
212 @issue = @changeset.find_referenced_issue_by_id(issue_id)
219 if @issue && (!@issue.visible? || @changeset.issues.include?(@issue))
213 if @issue && (!@issue.visible? || @changeset.issues.include?(@issue))
220 @issue = nil
214 @issue = nil
221 end
215 end
222
216
223 if @issue
217 if @issue
224 @changeset.issues << @issue
218 @changeset.issues << @issue
225 end
219 end
226 end
220 end
227
221
228 # Removes a related issue from a changeset
222 # Removes a related issue from a changeset
229 # DELETE /projects/:project_id/repository/(:repository_id/)revisions/:rev/issues/:issue_id
223 # DELETE /projects/:project_id/repository/(:repository_id/)revisions/:rev/issues/:issue_id
230 def remove_related_issue
224 def remove_related_issue
231 @issue = Issue.visible.find_by_id(params[:issue_id])
225 @issue = Issue.visible.find_by_id(params[:issue_id])
232 if @issue
226 if @issue
233 @changeset.issues.delete(@issue)
227 @changeset.issues.delete(@issue)
234 end
228 end
235 end
229 end
236
230
237 def diff
231 def diff
238 if params[:format] == 'diff'
232 if params[:format] == 'diff'
239 @diff = @repository.diff(@path, @rev, @rev_to)
233 @diff = @repository.diff(@path, @rev, @rev_to)
240 (show_error_not_found; return) unless @diff
234 (show_error_not_found; return) unless @diff
241 filename = "changeset_r#{@rev}"
235 filename = "changeset_r#{@rev}"
242 filename << "_r#{@rev_to}" if @rev_to
236 filename << "_r#{@rev_to}" if @rev_to
243 send_data @diff.join, :filename => "#{filename}.diff",
237 send_data @diff.join, :filename => "#{filename}.diff",
244 :type => 'text/x-patch',
238 :type => 'text/x-patch',
245 :disposition => 'attachment'
239 :disposition => 'attachment'
246 else
240 else
247 @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline'
241 @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline'
248 @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type)
242 @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type)
249
243
250 # Save diff type as user preference
244 # Save diff type as user preference
251 if User.current.logged? && @diff_type != User.current.pref[:diff_type]
245 if User.current.logged? && @diff_type != User.current.pref[:diff_type]
252 User.current.pref[:diff_type] = @diff_type
246 User.current.pref[:diff_type] = @diff_type
253 User.current.preference.save
247 User.current.preference.save
254 end
248 end
255 @cache_key = "repositories/diff/#{@repository.id}/" +
249 @cache_key = "repositories/diff/#{@repository.id}/" +
256 Digest::MD5.hexdigest("#{@path}-#{@rev}-#{@rev_to}-#{@diff_type}-#{current_language}")
250 Digest::MD5.hexdigest("#{@path}-#{@rev}-#{@rev_to}-#{@diff_type}-#{current_language}")
257 unless read_fragment(@cache_key)
251 unless read_fragment(@cache_key)
258 @diff = @repository.diff(@path, @rev, @rev_to)
252 @diff = @repository.diff(@path, @rev, @rev_to)
259 show_error_not_found unless @diff
253 show_error_not_found unless @diff
260 end
254 end
261
255
262 @changeset = @repository.find_changeset_by_name(@rev)
256 @changeset = @repository.find_changeset_by_name(@rev)
263 @changeset_to = @rev_to ? @repository.find_changeset_by_name(@rev_to) : nil
257 @changeset_to = @rev_to ? @repository.find_changeset_by_name(@rev_to) : nil
264 @diff_format_revisions = @repository.diff_format_revisions(@changeset, @changeset_to)
258 @diff_format_revisions = @repository.diff_format_revisions(@changeset, @changeset_to)
265 end
259 end
266 end
260 end
267
261
268 def stats
262 def stats
269 end
263 end
270
264
271 def graph
265 def graph
272 data = nil
266 data = nil
273 case params[:graph]
267 case params[:graph]
274 when "commits_per_month"
268 when "commits_per_month"
275 data = graph_commits_per_month(@repository)
269 data = graph_commits_per_month(@repository)
276 when "commits_per_author"
270 when "commits_per_author"
277 data = graph_commits_per_author(@repository)
271 data = graph_commits_per_author(@repository)
278 end
272 end
279 if data
273 if data
280 headers["Content-Type"] = "image/svg+xml"
274 headers["Content-Type"] = "image/svg+xml"
281 send_data(data, :type => "image/svg+xml", :disposition => "inline")
275 send_data(data, :type => "image/svg+xml", :disposition => "inline")
282 else
276 else
283 render_404
277 render_404
284 end
278 end
285 end
279 end
286
280
287 private
281 private
288
282
283 def build_new_repository_from_params
284 scm = params[:repository_scm] || (Redmine::Scm::Base.all & Setting.enabled_scm).first
285 unless @repository = Repository.factory(scm)
286 render_404
287 return
288 end
289
290 @repository.project = @project
291 @repository.safe_attributes = params[:repository]
292 @repository
293 end
294
289 def find_repository
295 def find_repository
290 @repository = Repository.find(params[:id])
296 @repository = Repository.find(params[:id])
291 @project = @repository.project
297 @project = @repository.project
292 rescue ActiveRecord::RecordNotFound
298 rescue ActiveRecord::RecordNotFound
293 render_404
299 render_404
294 end
300 end
295
301
296 REV_PARAM_RE = %r{\A[a-f0-9]*\Z}i
302 REV_PARAM_RE = %r{\A[a-f0-9]*\Z}i
297
303
298 def find_project_repository
304 def find_project_repository
299 @project = Project.find(params[:id])
305 @project = Project.find(params[:id])
300 if params[:repository_id].present?
306 if params[:repository_id].present?
301 @repository = @project.repositories.find_by_identifier_param(params[:repository_id])
307 @repository = @project.repositories.find_by_identifier_param(params[:repository_id])
302 else
308 else
303 @repository = @project.repository
309 @repository = @project.repository
304 end
310 end
305 (render_404; return false) unless @repository
311 (render_404; return false) unless @repository
306 @path = params[:path].is_a?(Array) ? params[:path].join('/') : params[:path].to_s
312 @path = params[:path].is_a?(Array) ? params[:path].join('/') : params[:path].to_s
307 @rev = params[:rev].blank? ? @repository.default_branch : params[:rev].to_s.strip
313 @rev = params[:rev].blank? ? @repository.default_branch : params[:rev].to_s.strip
308 @rev_to = params[:rev_to]
314 @rev_to = params[:rev_to]
309
315
310 unless @rev.to_s.match(REV_PARAM_RE) && @rev_to.to_s.match(REV_PARAM_RE)
316 unless @rev.to_s.match(REV_PARAM_RE) && @rev_to.to_s.match(REV_PARAM_RE)
311 if @repository.branches.blank?
317 if @repository.branches.blank?
312 raise InvalidRevisionParam
318 raise InvalidRevisionParam
313 end
319 end
314 end
320 end
315 rescue ActiveRecord::RecordNotFound
321 rescue ActiveRecord::RecordNotFound
316 render_404
322 render_404
317 rescue InvalidRevisionParam
323 rescue InvalidRevisionParam
318 show_error_not_found
324 show_error_not_found
319 end
325 end
320
326
321 def find_changeset
327 def find_changeset
322 if @rev.present?
328 if @rev.present?
323 @changeset = @repository.find_changeset_by_name(@rev)
329 @changeset = @repository.find_changeset_by_name(@rev)
324 end
330 end
325 show_error_not_found unless @changeset
331 show_error_not_found unless @changeset
326 end
332 end
327
333
328 def show_error_not_found
334 def show_error_not_found
329 render_error :message => l(:error_scm_not_found), :status => 404
335 render_error :message => l(:error_scm_not_found), :status => 404
330 end
336 end
331
337
332 # Handler for Redmine::Scm::Adapters::CommandFailed exception
338 # Handler for Redmine::Scm::Adapters::CommandFailed exception
333 def show_error_command_failed(exception)
339 def show_error_command_failed(exception)
334 render_error l(:error_scm_command_failed, exception.message)
340 render_error l(:error_scm_command_failed, exception.message)
335 end
341 end
336
342
337 def graph_commits_per_month(repository)
343 def graph_commits_per_month(repository)
338 @date_to = User.current.today
344 @date_to = User.current.today
339 @date_from = @date_to << 11
345 @date_from = @date_to << 11
340 @date_from = Date.civil(@date_from.year, @date_from.month, 1)
346 @date_from = Date.civil(@date_from.year, @date_from.month, 1)
341 commits_by_day = Changeset.
347 commits_by_day = Changeset.
342 where("repository_id = ? AND commit_date BETWEEN ? AND ?", repository.id, @date_from, @date_to).
348 where("repository_id = ? AND commit_date BETWEEN ? AND ?", repository.id, @date_from, @date_to).
343 group(:commit_date).
349 group(:commit_date).
344 count
350 count
345 commits_by_month = [0] * 12
351 commits_by_month = [0] * 12
346 commits_by_day.each {|c| commits_by_month[(@date_to.month - c.first.to_date.month) % 12] += c.last }
352 commits_by_day.each {|c| commits_by_month[(@date_to.month - c.first.to_date.month) % 12] += c.last }
347
353
348 changes_by_day = Change.
354 changes_by_day = Change.
349 joins(:changeset).
355 joins(:changeset).
350 where("#{Changeset.table_name}.repository_id = ? AND #{Changeset.table_name}.commit_date BETWEEN ? AND ?", repository.id, @date_from, @date_to).
356 where("#{Changeset.table_name}.repository_id = ? AND #{Changeset.table_name}.commit_date BETWEEN ? AND ?", repository.id, @date_from, @date_to).
351 group(:commit_date).
357 group(:commit_date).
352 count
358 count
353 changes_by_month = [0] * 12
359 changes_by_month = [0] * 12
354 changes_by_day.each {|c| changes_by_month[(@date_to.month - c.first.to_date.month) % 12] += c.last }
360 changes_by_day.each {|c| changes_by_month[(@date_to.month - c.first.to_date.month) % 12] += c.last }
355
361
356 fields = []
362 fields = []
357 today = User.current.today
363 today = User.current.today
358 12.times {|m| fields << month_name(((today.month - 1 - m) % 12) + 1)}
364 12.times {|m| fields << month_name(((today.month - 1 - m) % 12) + 1)}
359
365
360 graph = SVG::Graph::Bar.new(
366 graph = SVG::Graph::Bar.new(
361 :height => 300,
367 :height => 300,
362 :width => 800,
368 :width => 800,
363 :fields => fields.reverse,
369 :fields => fields.reverse,
364 :stack => :side,
370 :stack => :side,
365 :scale_integers => true,
371 :scale_integers => true,
366 :step_x_labels => 2,
372 :step_x_labels => 2,
367 :show_data_values => false,
373 :show_data_values => false,
368 :graph_title => l(:label_commits_per_month),
374 :graph_title => l(:label_commits_per_month),
369 :show_graph_title => true
375 :show_graph_title => true
370 )
376 )
371
377
372 graph.add_data(
378 graph.add_data(
373 :data => commits_by_month[0..11].reverse,
379 :data => commits_by_month[0..11].reverse,
374 :title => l(:label_revision_plural)
380 :title => l(:label_revision_plural)
375 )
381 )
376
382
377 graph.add_data(
383 graph.add_data(
378 :data => changes_by_month[0..11].reverse,
384 :data => changes_by_month[0..11].reverse,
379 :title => l(:label_change_plural)
385 :title => l(:label_change_plural)
380 )
386 )
381
387
382 graph.burn
388 graph.burn
383 end
389 end
384
390
385 def graph_commits_per_author(repository)
391 def graph_commits_per_author(repository)
386 #data
392 #data
387 stats = repository.stats_by_author
393 stats = repository.stats_by_author
388 fields, commits_data, changes_data = [], [], []
394 fields, commits_data, changes_data = [], [], []
389 stats.each do |name, hsh|
395 stats.each do |name, hsh|
390 fields << name
396 fields << name
391 commits_data << hsh[:commits_count]
397 commits_data << hsh[:commits_count]
392 changes_data << hsh[:changes_count]
398 changes_data << hsh[:changes_count]
393 end
399 end
394
400
395 #expand to 10 values if needed
401 #expand to 10 values if needed
396 fields = fields + [""]*(10 - fields.length) if fields.length<10
402 fields = fields + [""]*(10 - fields.length) if fields.length<10
397 commits_data = commits_data + [0]*(10 - commits_data.length) if commits_data.length<10
403 commits_data = commits_data + [0]*(10 - commits_data.length) if commits_data.length<10
398 changes_data = changes_data + [0]*(10 - changes_data.length) if changes_data.length<10
404 changes_data = changes_data + [0]*(10 - changes_data.length) if changes_data.length<10
399
405
400 # Remove email address in usernames
406 # Remove email address in usernames
401 fields = fields.collect {|c| c.gsub(%r{<.+@.+>}, '') }
407 fields = fields.collect {|c| c.gsub(%r{<.+@.+>}, '') }
402
408
403 #prepare graph
409 #prepare graph
404 graph = SVG::Graph::BarHorizontal.new(
410 graph = SVG::Graph::BarHorizontal.new(
405 :height => 30 * commits_data.length,
411 :height => 30 * commits_data.length,
406 :width => 800,
412 :width => 800,
407 :fields => fields,
413 :fields => fields,
408 :stack => :side,
414 :stack => :side,
409 :scale_integers => true,
415 :scale_integers => true,
410 :show_data_values => false,
416 :show_data_values => false,
411 :rotate_y_labels => false,
417 :rotate_y_labels => false,
412 :graph_title => l(:label_commits_per_author),
418 :graph_title => l(:label_commits_per_author),
413 :show_graph_title => true
419 :show_graph_title => true
414 )
420 )
415 graph.add_data(
421 graph.add_data(
416 :data => commits_data,
422 :data => commits_data,
417 :title => l(:label_revision_plural)
423 :title => l(:label_revision_plural)
418 )
424 )
419 graph.add_data(
425 graph.add_data(
420 :data => changes_data,
426 :data => changes_data,
421 :title => l(:label_change_plural)
427 :title => l(:label_change_plural)
422 )
428 )
423 graph.burn
429 graph.burn
424 end
430 end
425
431
426 def disposition(path)
432 def disposition(path)
427 if Redmine::MimeType.is_type?('image', @path) || Redmine::MimeType.of(@path) == "application/pdf"
433 if Redmine::MimeType.is_type?('image', @path) || Redmine::MimeType.of(@path) == "application/pdf"
428 'inline'
434 'inline'
429 else
435 else
430 'attachment'
436 'attachment'
431 end
437 end
432 end
438 end
433 end
439 end
General Comments 0
You need to be logged in to leave comments. Login now