diff --git a/app/controllers/contributions_controller.rb b/app/controllers/contributions_controller.rb index dd1d17dad..cf68e2a9c 100644 --- a/app/controllers/contributions_controller.rb +++ b/app/controllers/contributions_controller.rb @@ -1,839 +1,26 @@ # encoding=utf-8 -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -require 'SVG/Graph/Bar' -require 'SVG/Graph/BarHorizontal' -require 'digest/sha1' -require 'redmine/scm/adapters/abstract_adapter' -require 'tempfile' -require 'json' -require 'open-uri' - -class ChangesetNotFound < Exception; end -class InvalidRevisionParam < Exception; end class ContributionsController < ApplicationController - include ApplicationHelper - menu_item :contribution - menu_item :settings, :only => [:new, :create, :edit, :update, :destroy, :committers] - default_search_scope :changesets - - before_filter :find_project_by_project_id, :only => [:new, :create, :newrepo, :stats, :quality_analysis] - before_filter :find_repository, :only => [:edit, :update, :destroy, :committers] - before_filter :find_project_repository, :except => [:new, :create, :newcreate, :edit, :update, :destroy, :committers, :newrepo, :to_gitlab, :forked, :export_rep_static, :training_project_extend] - # 连接gitlab - # before_filter :connect_gitlab, :only => [:quality_analysis, :commit_diff] - before_filter :find_changeset, :only => [:revision, :add_related_issue, :remove_related_issue] - # before_filter :authorize , :except => [:newrepo,:newcreate,:fork, :to_gitlab, :forked, :project_archive, :quality_analysis, :commit_diff] - before_filter :authorize_visible , :except => [:newrepo,:newcreate,:fork, :to_gitlab, :forked, :project_archive, :quality_analysis, :commit_diff] - # 版本库新增权限 - # before_filter :show_rep, :only => [:show, :stats, :revisions, :revision, :diff, :commit_diff ] - accept_rss_auth :revisions - # hidden repositories filter // 隐藏代码过滤器 - # before_filter :check_hidden_repo, :only => [:stats, :revisions, :revision, :diff ] - helper :repositories - include RepositoriesHelper - helper :project_score - require 'ostruct' - #@root_path = RepositoriesHelper::ROOT_PATH - # require 'net/ssh' - - rescue_from Redmine::Scm::Adapters::CommandFailed, :with => :show_error_command_failed - def new - if @project.repositories.count == 0 - scm = params[:repository_scm] || (Redmine::Scm::Base.all & Setting.enabled_scm).first - @repository = Repository.factory(scm) - @repository.is_default = @project.repository.nil? - @repository.project = @project - @course_tag = params[:course] - if @course_tag == 1 - render :layout => 'base_courses' - else - render :layout => 'base_projects' - end - else - render_403 - end - - end - - def export_rep_static - # 管理员界面导出所有项目 - @project = Project.find(params[:id]) - gpid = @project.gpid - rev = params[:rev] - cycle = params[:cycle] - respond_to do |format| - format.html - format.xls{ - filename = "#{@project.name.to_s}_#{l(:label_rep_xls)}.xls" - send_data(export_rep_xls(gpid, :rev => rev, :cycle => cycle), :type => 'application/octet-stream', :filename => filename_for_content_disposition(filename)) - } - end - end - - def forked - @project = Project.find(params[:id]) - @repository = Repository.where("project_id =? and type =?", @project.id, "Repository::Gitlab") - # 如果当前用户已经fork过该项目,不会新fork项目,则跳至已fork的项 - unless has_forked?(@project, User.current) - project = project_from_current_project(@project.id, User.current.id) - redirect_to project_path(project) - else - # 自己不能fork自己的项目 - if User.current.id == @project.user_id - flash[:notice] = l(:project_gitlab_fork_own) - redirect_to repository_url(@repository) - else - g = Gitlab.client - if User.current.gid.nil? - begin - s = Trustie::Gitlab::Sync.new - s.sync_user(User.current) - ensure - logger.error "Synv user failed ==>#{User.current.id}" - end - end - gproject = g.fork(@project.gpid, User.current.gid) - if gproject - copy_project(@project, gproject) - forked_count = @project.forked_count.to_i + 1 - @project.update_attributes(:forked_count => forked_count) - end - end - end - end - - # 一键ZIP下载 - def project_archive - token = Gitlab.private_token - token = aes_encrypt(token, "abcd") - # g = Gitlab.client - # g.project_archive(@project.gpid, @rev) - # 'git archive --format zip --output /path/to/file.zip master' # 将 master 以zip格式打包到指定文件 - # - # zip_path = Gitlab.endpoint.to_s + "/projects/" + @project.gpid.to_s + "/repository/archive?&private_token=" + Gitlab.private_token - # f = open(zip_path).read - # send_file "/path/to/file.zip" - end - - # 开启实训项目,学生会fork一个项目并自动发送任务 - def training_project_extend - @project = Project.find(params[:id]) - @repository = Repository.where("project_id =? and type =?", @project.id, "Repository::Gitlab") - # 如果当前用户已经fork过该项目,不会新fork项目,则跳至已fork的项 - unless has_forked?(@project, User.current) - project = project_from_current_project(@project.id, User.current.id) - redirect_to project_path(project) - else - ActiveRecord::Base.transaction do - g = Gitlab.client - if User.current.gid.nil? - begin - s = Trustie::Gitlab::Sync.new - s.sync_user(User.current) - ensure - logger.error "Syn user failed ==>#{User.current.id}" - end - end - gproject = g.fork(@project.gpid, User.current.gid) - if gproject - new_training_project = copu_project_and_module(@project, gproject) - forked_count = @project.forked_count.to_i + 1 - @project.update_attributes(:forked_count => forked_count) - # 发布实训任务,只发布实训任务的第一个 - publish_training_tasks(@project, new_training_project) - end - end - end - end - - def copu_project_and_module tproject, gproject - project = Project.new - project.name = tproject.name - project.is_public = tproject.is_public - project.status = tproject.status - project.description = tproject.description - project.hidden_repo = tproject.hidden_repo - project.user_id = User.current.id - project.project_type = 0 - project.project_new_type = tproject.project_new_type - project.gpid = gproject.id - project.forked_from_project_id = tproject.id - project.enabled_module_names = tproject.enabled_module_names - if project.save - project.update_attribute(:training_status,1) - r = Role.givable.find_by_id(Setting.new_project_user_role_id.to_i) || Role.givable.first - m = Member.new(:user => User.current, :roles => [r]) - if ProjectScore.where("project_id=?", project.id).first.nil? - ProjectScore.create(:project_id => project.id, :score => false) - end - project_info = ProjectInfo.new(:user_id => User.current.id, :project_id => project.id) - user_grades = UserGrade.create(:user_id => User.current.id, :project_id => project.id) - Rails.logger.debug "UserGrade created: #{user_grades.to_json}" - project_status = ProjectStatus.create(:project_id => @project.id, :watchers_count => 0, :changesets_count => 0, :project_type => @project.project_type,:grade => 0) - Rails.logger.debug "ProjectStatus created: #{project_status.to_json}" - project.members << m - project.project_infos << project_info - copy_repository(project, gproject) - return project - else - respond_to do |format| - format.html { render :action => 'forked', :layout => 'base_projects'} - format.api { render_validation_errors(@project) } - end - end - end - - # REDO: 如果实训项目还没有创建任务的时候应该跳出 - def publish_training_tasks original_project, new_training_project - original_task = TrainingTask.where(:project_id => original_project.id, :position => 1).first - training_task = TrainingTask.new - training_task.save_attachments(params[:attachments] || (params[:training_task] && params[:training_task][:uploads])) - training_task.subject = original_task.subject - training_task.description = original_task.description - training_task.position = original_task.position - training_task.project_id = new_training_project.id - training_task.author_id = User.current.id - if training_task.save - respond_to do |format| - format.html{redirect_to project_training_tasks_url(:project_id => new_training_project.id)} - end - else - raise "create task failed" - end - end - - - # 判断用户是否已经fork过该项目 - def has_forked?(project, user) - projects = Project.where("user_id =?", user) - projects.map(&:forked_from_project_id).detect{|s| s == @project.id}.nil? ? true : false - end - - # 获取当前用户fork过的项目 - def project_from_current_project(project, user) - project = Project.where("user_id =? and forked_from_project_id =?",user, project).first - end - - # copy a project for fork - def copy_project(tproject, gproject) - project = Project.new - project.name = tproject.name - project.is_public = tproject.is_public - project.status = tproject.status - project.description = tproject.description - project.hidden_repo = tproject.hidden_repo - project.user_id = User.current.id - project.project_type = 0 - project.project_new_type = tproject.project_new_type - project.gpid = gproject.id - project.forked_from_project_id = tproject.id - if project.save - r = Role.givable.find_by_id(Setting.new_project_user_role_id.to_i) || Role.givable.first - m = Member.new(:user => User.current, :roles => [r]) - if ProjectScore.where("project_id=?", project.id).first.nil? - ProjectScore.create(:project_id => project.id, :score => false) - end - project_info = ProjectInfo.new(:user_id => User.current.id, :project_id => project.id) - user_grades = UserGrade.create(:user_id => User.current.id, :project_id => project.id) - Rails.logger.debug "UserGrade created: #{user_grades.to_json}" - project_status = ProjectStatus.create(:project_id => @project.id, :watchers_count => 0, :changesets_count => 0, :project_type => @project.project_type,:grade => 0) - Rails.logger.debug "ProjectStatus created: #{project_status.to_json}" - project.members << m - project.project_infos << project_info - copy_repository(project, gproject) - respond_to do |format| - format.html { - flash[:notice] = l(:notice_successful_create) - if params[:continue] - attrs = {:parent_id => project.parent_id}.reject {|k,v| v.nil?} - redirect_to new_project_url(attrs, :course => '0') - else - redirect_to project_path(project) - end - } - format.api { render :action => 'show', :status => :created, :location => url_for(:controller => 'projects', :action => 'show', :id => project.id) } - format.js - end - return project - else - respond_to do |format| - format.html { render :action => 'forked', :layout => 'base_projects'} - format.api { render_validation_errors(@project) } - end - end - end - - def copy_repository(project, gproject) - # 避免 - # if is_sigle_identifier?(project.user_id, gproject.name) - repository = Repository.factory('Git') - repository.project_id = project.id - repository.type = 'Repository::Gitlab' - repository.url = gproject.name - repository.identifier = gproject.name - repository = repository.save - # else - # flash[:notice] = l(:project_gitlab_create_double_message) - # end - end - - def newrepo - scm = params[:repository_scm] || (Redmine::Scm::Base.all & Setting.enabled_scm).first - @repository = Repository.factory(scm) - @repository.is_default = @project.repository.nil? - @repository.project = @project - @course_tag = params[:course] - if @course_tag == 1 - render :layout => 'base_courses' - else - render :layout => 'base_projects' - end - end - - def fork - @repository_url = params[:repository_url] - - # @repository.url - # system "htpasswd -mb "+@root_path+"user.passwd "+params[:repository][:identifier]+" "+@upasswd - # system "echo -e '"+params[:project_id]+"-"+params[:repository][:identifier]+"-write:"+ - # " "+params[:repository][:identifier]+"' >> "+@root_path+"group.passwd" - system "git clone --bare "+@repository_url - # system "mv "+@project_path+"/hooks/post-update{.sample,}" - # system "chmod a+x "+@project_path+"/hooks/post-update" - # system "."+@project_path+"/hooks/post-update" - # system "echo -e 'Allow from all \n Order Deny,Allow \n "+ - # " \n"+ - # "Require group "+params[:project_id]+"-"+params[:repository][:identifier]+"-write \n "+ - # " \n ' >>"+ - # @project_path+"/.htaccess" - flash[:notice] = l(:label_notice_fork_successed) - @repositories = @project.repositories - render :action => 'show', :layout => 'base_projects' - end - - - HOOK_TEMPLATE = %Q{#!/bin/sh -exec sh -c ' -function update() -{ - CMD_PATH=`dirname $0`; - cd $CMD_PATH; - PY_PATH=$PWD/../../git_refresh_changes.py; - [[ -s "$PY_PATH" ]] && $(which python) $PY_PATH $PWD; - cd -; -} -git update-server-info -update -' - } - - def create - # 判断版本库创建者是否有同名版本库,避免版本库路径一致问题 - unless is_sigle_identifier?(@project.user_id, params[:repository].first[1]) - flash[:notice] = l(:project_gitlab_create_double_message) - redirect_to settings_project_url(@project, :tab => 'repositories') - else - attrs = pickup_extra_info - @repository = Repository.factory('Git') - @repository.safe_attributes = params[:repository] - if attrs[:attrs_extra].keys.any? - @repository.merge_extra_info(attrs[:attrs_extra]) - end - @repository.project = @project - @repository.type = 'Repository::Gitlab' - @repository.identifier = @repository.identifier.downcase - @repository.url = @repository.identifier - ActiveRecord::Base.transaction do - begin - if request.post? && @repository.save! - s = Trustie::Gitlab::Sync.new - s.create_project(@project, @repository) - raise "sync failed" if @project.gpid.blank? - redirect_to(:controller => 'repositories', :action => 'show', :id => @project, :repository_id => gitlab_repository(@project).try(:identifier)) - else - redirect_to settings_project_url(@project, :tab => 'repositories',:repository_error_message=>@repository.errors.full_messages) - end - rescue Exception => e - logger.info("create repository #{e.message}") - @repo_error= "666" - redirect_to settings_project_url(@project, :tab => 'repositories', :create_error => "版本库创建失败,用户名或版本库名中不允许包含特殊字符") - raise ActiveRecord::Rollback - end - end - end - end - - def edit - end - - def update - attrs = pickup_extra_info - @repository.safe_attributes = attrs[:attrs] - if attrs[:attrs_extra].keys.any? - @repository.merge_extra_info(attrs[:attrs_extra]) - end - @repository.project = @project - if request.put? && @repository.save - redirect_to settings_project_url(@project, :tab => 'repositories') - else - render :action => 'edit' - end - end - - def pickup_extra_info - p = {} - p_extra = {} - params[:repository].each do |k, v| - if k =~ /^extra_/ - p_extra[k] = v - else - p[k] = v - end - end - {:attrs => p, :attrs_extra => p_extra} - end - private :pickup_extra_info - - def committers - @committers = @repository.committers - @users = @project.users - additional_user_ids = @committers.collect(&:last).collect(&:to_i) - @users.collect(&:id) - @users += User.find_all_by_id(additional_user_ids) unless additional_user_ids.empty? - @users.compact! - @users.sort! - if request.post? && params[:committers].is_a?(Hash) - # Build a hash with repository usernames as keys and corresponding user ids as values - @repository.committer_ids = params[:committers].values.inject({}) {|h, c| h[c.first] = c.last; h} - flash[:notice] = l(:notice_successful_update) - respond_to do |format| - format.html{ - render :layout => "base_projects" - } - end - elsif request.get? - respond_to do |format| - format.html{ - render :layout => "base_projects" - } - end - end - end - - def quality_analysis - gitlab_branches = @g.branches(@project.gpid) - @branch_names = gitlab_branches.map{|b| b.name} - @gitlab_default_branch = @g_project.default_branch - # language = params[:language] - # branch = params[:branch] - # path = params[:path] - # user_name = User.find(@project.user_id).try(:login) - # rep_name = params[:repository_id] - # host = "192.168.0.200" - # port = "1125" - # username = "git" - # password = "123123" - # server_cmd1 = "sh gitclone.sh" + " " + user_name + " " + rep_name - # # 连接到远程主机 foobar - # ssh = Net::SSH.start(host, username, :port => port, :password => password) do |ssh| - # result = ssh.exec!(server_cmd1) - # path = "/home/git/repo/" + user_name + "/" + rep_name - # # sonar 分析 - # # server_cmd2 - # # 删除clone的版本库 - # # server_cmd3 - # end - respond_to do |format| - format.js - format.html{ - render :layout => "base_projects" - } - end - end - - def destroy - DestroyRepositoryTask.new.destroy(User.current.id, @repository.id) - @repository.hidden = true - @repository.save - redirect_to settings_project_url(@project, :tab => 'repositories') - end - - def to_gitlab - @project = Project.find(params[:project_id]) - @repository = Repository.find(params[:id]) - s = Trustie::Gitlab::Sync.new - s.sync_project(@project, path: params[:repo_name], import_url: @repository.url) - @repository.type = 'Repository::Gitlab' - @repository.save - redirect_to :controller => 'repositories', :action => 'show', :id => @project.id, to: 'gitlab' - end - - # 权限: - # 如果项目隐藏了版本库,则非项目成员及项目报告人员不能够访问版本库 - # 如果没有隐藏版本库,只要项目公开,其它成员都可以看到版本库 - # 项目关联了课程,课程的老师是可以看到版本库的 - # 超级管理员可以看到项目版本库 def show - Rails.logger.info("!!!!!!!!!!!!! in show function") - # 顶部导航 @project_menu_type = 12 - # TODO: the below will move to filter, done. # 获取版本库目录结构 Rails.logger.info("!!!!! this is to show the value of @path and @rev: ") Rails.logger.info(@path) Rails.logger.info(@rev) - render :layout => 'base_projects' end - alias_method :browse, :show - - # 获取版本文件目录的 - def tree_head_message - - end - - # 注:由于考虑到性能所以commits api每次返回20条记录 - def changes - # 顶部导航 - @project_menu_type = 5 - @entry = @repository.entry(@path, @rev) - (show_error_not_found; return) unless @entry - g = Gitlab.client - limit = 10 - # 每次页面的换回值从1开始,但是gitlab的页面查询是从0开始,所以先改变page的类型减一在改回来 - @commits = g.commits(@project.gpid, page:(params[:page].to_i - 1).to_s, ref_name:@rev) - @commits_count = params[:commit_count].nil? ? @g.user_static(@project.gpid, :rev => @rev).count : params[:commit_count].to_i - @commits_pages = Paginator.new @commits_count, limit, params[:page] - # @offset ||= @commits_pages.offset - # @commits = paginateHelper @commits, limit - - render :layout => 'base_projects' - end - - - def revisions - @changeset_count = @repository.changesets.count - @changeset_pages = Paginator.new @changeset_count, - per_page_option, - params['page'] - @changesets = @repository.changesets. - limit(@changeset_pages.per_page). - offset(@changeset_pages.offset). - includes(:user, :repository, :parents). - all - - respond_to do |format| - format.html { render :layout => 'base_projects' } - format.atom { render_feed(@changesets, :title => "#{@project.name}: #{l(:label_revision_plural)}") } - end - end - - def raw - entry_and_raw(true) - end - - def entry - # 顶部导航 - @project_menu_type = 5 - - entry_and_raw(false) - @content = @repository.cat(@path, @rev) - # @changesets_latest_coimmit = @g.commit(@project.gpid, @entry.try(:lastrev)) - @changesets_latest_coimmit = @g.commits(@project.gpid, :rev => @rev, :path => @paht).try(:first) - # @changesets_latest_coimmit = @g.rep_last_changes(@project.gpid, :rev => @rev, :path => @path) - # 总的提交数 - @changesets_all_count = @g.user_static(@project.gpid, :rev => @rev).count - if is_entry_text_data?(@content, @path) - render :layout => 'base_projects' - end - end - - def entry_edit - entry_and_raw(false) - @content = @repository.cat(@path, @rev) - # @changesets_latest_coimmit = @g.commit(@project.gpid, @entry.try(:lastrev)) - @changesets_latest_coimmit = @g.commits(@project.gpid, :rev => @rev, :path => @paht).try(:first) - # 总的提交数 - @changesets_all_count = @g.user_static(@project.gpid, :rev => @rev).count - if is_entry_text_data?(@content, @path) - render :layout => 'base_projects' - end - end - - def entry_update - g = Gitlab.client - @path = params[:path] - @rev = params[:rev] - @content = params[:content] - code_file = g.edit_file(@project.gpid, :content => params[:content], :file_path => @path, :branch_name => @rev, :commit_message => "...") - # if @shixun.try(:status).to_i < 2 - # shixun_modify_status_without_publish(@shixun, 1) - # end - respond_to do |format| - format.js - end - end - - def entry_and_raw(is_raw) - @entry = @repository.entry(@path, @rev) - (show_error_not_found; return) unless @entry - - # If the entry is a dir, show the browser - (show; return) if @entry.is_dir? - - @content = @repository.cat(@path, @rev) - (show_error_not_found; return) unless @content - if is_raw || (@content.size && @content.size > Setting.file_max_size_displayed.to_i.kilobyte) || !is_entry_text_data?(@content, @path) - # Force the download - send_opt = { :filename => filename_for_content_disposition(@path.split('/').last) } - send_type = Redmine::MimeType.of(@path) - send_opt[:type] = send_type.to_s if send_type - send_opt[:disposition] = (Redmine::MimeType.is_type?('image', @path) && !is_raw ? 'inline' : 'attachment') - send_data @content, send_opt - else - # Prevent empty lines when displaying a file with Windows style eol - # TODO: UTF-16 - # Is this needs? AttachmentsController reads file simply. - @content.gsub!("\r\n", "\n") - @changeset = @repository.find_changeset_by_name(@rev) - end - end - private :entry_and_raw - - def is_entry_text_data?(ent, path) - # UTF-16 contains "\x00". - # It is very strict that file contains less than 30% of ascii symbols - # in non Western Europe. - return true if Redmine::MimeType.is_type?('text', path) - # Ruby 1.8.6 has a bug of integer divisions. - # http://apidock.com/ruby/v1_8_6_287/String/is_binary_data%3F - return false if ent.is_binary_data? - true - end - private :is_entry_text_data? - - def annotate - @entry = @repository.entry(@path, @rev) - (show_error_not_found; return) unless @entry - - @annotate = @repository.scm.annotate(@path, @rev) - if @annotate.nil? || @annotate.empty? - (render_error l(:error_scm_annotate); return) - end - ann_buf_size = 0 - @annotate.lines.each do |buf| - ann_buf_size += buf.size - end - if ann_buf_size > Setting.file_max_size_displayed.to_i.kilobyte - (render_error l(:error_scm_annotate_big_text_file); return) - end - @changeset = @repository.find_changeset_by_name(@rev) - end - - def revision - respond_to do |format| - format.html{render :layout => 'base_projects'} - format.js {render :layout => false} - end - end - - # Adds a related issue to a changeset - # POST /projects/:project_id/repository/(:repository_id/)revisions/:rev/issues - def add_related_issue - @issue = @changeset.find_referenced_issue_by_id(params[:issue_id]) - if @issue && (!@issue.visible? || @changeset.issues.include?(@issue)) - @issue = nil - end - - if @issue - @changeset.issues << @issue - end - end - - # Removes a related issue from a changeset - # DELETE /projects/:project_id/repository/(:repository_id/)revisions/:rev/issues/:issue_id - def remove_related_issue - @issue = Issue.visible.find_by_id(params[:issue_id]) - if @issue - @changeset.issues.delete(@issue) - end - end - - # 每次提交对应的文件差异 - def commit_diff - # 顶部导航 - @project_menu_type = 5 - @commit_diff = @g.commit_diff(@project.gpid, params[:changeset]) - diff = ActiveSupport::JSON.decode(@commit_diff.to_json).first - diff = OpenStruct.new(diff) - @diff_file = Trustie::Gitlab::Diff::File.new(diff) - - - @commit_details = @g.commit(@project.gpid, params[:changeset]) - render :layout => 'base_projects' - end - - def diff - if params[:format] == 'diff' - @diff = @repository.diff(@path, @rev, @rev_to) - (show_error_not_found; return) unless @diff - filename = "changeset_r#{@rev}" - filename << "_r#{@rev_to}" if @rev_to - send_data @diff.join, :filename => "#{filename}.diff", - :type => 'text/x-patch', - :disposition => 'attachment' - else - @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline' - @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type) - - # Save diff type as user preference - if User.current.logged? && @diff_type != User.current.pref[:diff_type] - User.current.pref[:diff_type] = @diff_type - User.current.preference.save - end - @cache_key = "repositories/diff/#{@repository.id}/" + - Digest::MD5.hexdigest("#{@path}-#{@rev}-#{@rev_to}-#{@diff_type}-#{current_language}") - unless read_fragment(@cache_key) - @diff = @repository.diff(@path, @rev, @rev_to) - unless @diff - show_error_not_found - return - end - end - - @changeset = @repository.find_changeset_by_name(@rev) - @changeset_to = @rev_to ? @repository.find_changeset_by_name(@rev_to) : nil - @diff_format_revisions = @repository.diff_format_revisions(@changeset, @changeset_to) - end - render :layout => 'base_projects' - end - - def stats - if @project.gpid.nil? - render 404 - return - end - project_id = @project.gpid - # @repository_id = @repository.identifier - # creator = params[:creator] - rev = params[:rev] - g = Gitlab.client - begin - @static_total_per_user = g.rep_stats(project_id, :rev => rev) - # 更新rep_statics统计数 - @static_total_per_user.each do |static| - rep_static = RepStatics.where("project_id =? and email =?", @project.id, static.email.to_s).first - if rep_static.nil? - RepStatics.create(:project_id => @project.id, :uname => static.uname, :commits_num => static.commits_num, :email => static.email, :add => static.add, :del => static.del, :changeset => static.changes) - else - if @rev == params[:default_branch] - rep_static.update_attributes(:uname => static.uname, :commits_num => static.commits_num, :email => static.email, :add => static.add, :del => static.del, :changeset => static.changes) - end - end - end - rescue - render_404 - return - end - render :layout => 'base_projects' - end - - def graph - data = nil - case params[:graph] - when "commits_per_month" - data = graph_commits_per_month(@repository) - when "commits_per_author" - data = graph_commits_per_author(@repository) - when "author_commits_per_month" - data = graph_author_commits_per_month(@repository) - when "author_commits_six_month" - data = author_commits_six_month(@repository) - when "author_code_six_months" - data = author_code_six_month(@repository) - end - if data - headers["Content-Type"] = "image/svg+xml" - send_data(data, :type => "image/svg+xml", :disposition => "inline") - else - render_404 - end - end - - def authorize_visible - allowed = authorize_allowed(params[:controller], params[:action], global = false) - if allowed || User.current.admin? || (@project.hidden_repo && User.current.member_of?(@project) && !role_of_members_in_project(@project.id, User.current.id) == "Reporter") - true - else - if @project && @project.archived? - render_403 :message => :notice_not_authorized_archived_project - else - deny_access - end - end - end - private - # 更新项目统计数 - def update_commits_count project, count - project.project_score.update_attribute(:changeset_num, count) - end - - # 更新项目提交次数时间 - def update_commits_date project, date - project.project_score.update_attribute(:commit_time, date.created_at) - end - - # 链接gitlab - def connect_gitlab - begin - @g = Gitlab.client - unless @project.gpid.nil? - @g_project = @g.project(@project.gpid) - end - rescue => e - logger.error("connect gitlab failed ==> #{e}") - end - end - - def show_rep - visible_repository?(@project) - end - - def find_repository - @repository = Repository.find(params[:id]) - @project = @repository.project - rescue ActiveRecord::RecordNotFound - render_404 - end - REV_PARAM_RE = %r{\A[a-f0-9]*\Z}i REP_TYPE = "Repository::Gitlab" - # 获取项目、版本库、路劲、默认分支 def find_project_repository + Rails.logger.info("!!!!! in the find_project_repository function") @project = Project.find(params[:id]) @repository = Repository.where(:type => REP_TYPE, :project_id => @project).first (render_404; return false) unless (@repository || @project.gpid) @@ -854,225 +41,4 @@ update rescue InvalidRevisionParam show_error_not_found end - - def find_changeset - if @rev.present? - @changeset = @repository.find_changeset_by_name(@rev) - end - show_error_not_found unless @changeset - end - - def show_error_not_found - render_error :message => l(:error_scm_not_found), :status => 404 - end - - def show_error_forbidden - render_error :status => 403 - end - - # Handler for Redmine::Scm::Adapters::CommandFailed exception - def show_error_command_failed(exception) - render_error l(:error_scm_command_failed, exception.message) - end - - def graph_commits_per_month(repository) - @date_to = Date.today - @date_from = @date_to << 11 - @date_from = Date.civil(@date_from.year, @date_from.month, 1) - commits_by_day = Changeset.count( - :all, :group => :commit_date, - :conditions => ["repository_id = ? AND commit_date BETWEEN ? AND ?", repository.id, @date_from, @date_to]) - commits_by_month = [0] * 12 - commits_by_day.each {|c| commits_by_month[(@date_to.month - c.first.to_date.month) % 12] += c.last } - - changes_by_day = Change.count( - :all, :group => :commit_date, :include => :changeset, - :conditions => ["#{Changeset.table_name}.repository_id = ? AND #{Changeset.table_name}.commit_date BETWEEN ? AND ?", repository.id, @date_from, @date_to]) - changes_by_month = [0] * 12 - changes_by_day.each {|c| changes_by_month[(@date_to.month - c.first.to_date.month) % 12] += c.last } - - fields = [] - 12.times {|m| fields << month_name(((Date.today.month - 1 - m) % 12) + 1)} - - graph = SVG::Graph::Bar.new( - :height => 300, - :width => 600, - :fields => fields.reverse, - :stack => :side, - :scale_integers => true, - :step_x_labels => 2, - :show_data_values => true, - :graph_title => l(:label_commits_per_month), - :show_graph_title => true - ) - - # 具状图 - graph.add_data( - :data => commits_by_month[0..11].reverse, - :title => l(:label_revision_plural) - ) - - graph.add_data( - :data => changes_by_month[0..11].reverse, - :title => l(:label_change_plural) - ) - - graph.burn - end - - def graph_commits_per_author(repository) - commits_by_author = Changeset.count(:all, :group => :committer, :conditions => ["repository_id = ?", repository.id]) - commits_by_author = commits_by_author.to_a.sort! {|x, y| x.last <=> y.last}.last(25) - - changes_by_author = Change.count(:all, :group => :committer, :include => :changeset, :conditions => ["#{Changeset.table_name}.repository_id = ?", repository.id]) - h = changes_by_author.inject({}) {|o, i| o[i.first] = i.last; o} - - fields = commits_by_author.collect {|r| r.first} - commits_data = commits_by_author.collect {|r| r.last} - changes_data = commits_by_author.collect {|r| h[r.first] || 0} - - fields = fields + [""]*(10 - fields.length) if fields.length<10 - commits_data = commits_data + [0]*(10 - commits_data.length) if commits_data.length<10 - changes_data = changes_data + [0]*(10 - changes_data.length) if changes_data.length<10 - - # Remove email adress in usernames - fields = fields.collect {|c| c.gsub(%r{<.+@.+>}, '') } - - graph = SVG::Graph::BarHorizontal.new( - :height => 400, - :width => 600, - :fields => fields, - :stack => :side, - :scale_integers => true, - :show_data_values => true, - :rotate_y_labels => false, - :graph_title => l(:label_commits_per_author), - :show_graph_title => true - ) - graph.add_data( - :data => commits_data, - :title => l(:label_revision_plural) - ) - graph.add_data( - :data => changes_data, - :title => l(:label_change_plural) - ) - graph.burn - end - - # 用户最近一年的提交次数 - def graph_author_commits_per_month(repository) - @date_to = Date.today - @date_from = @date_to << 12 - @date_from = Date.civil(@date_from.year, @date_from.month, @date_from.day) - commits_by_author = Changeset.count(:all, :group => :committer, - :conditions => ["#{Changeset.table_name}.repository_id = ? AND #{Changeset.table_name}.commit_date BETWEEN ? AND ?", repository.id, @date_from, @date_to]) - commits_by_author = commits_by_author.to_a.sort! {|x, y| x.last <=> y.last}.last(25) - - fields = commits_by_author.collect {|r| r.first} - commits_data = commits_by_author.collect {|r| r.last} - - fields = fields + [""]*(10 - fields.length) if fields.length<10 - commits_data = commits_data + [0]*(10 - commits_data.length) if commits_data.length<10 - - # Remove email adress in usernames - fields = fields.collect {|c| c.gsub(%r{<.+@.+>}, '') } - - graph = SVG::Graph::BarHorizontal.new( - :height => 400, - :width => 600, - :fields => fields, - :stack => :side, - :scale_integers => true, - :show_data_values => true, - :rotate_y_labels => false, - :graph_title => l(:label_author_commits_year), - :show_graph_title => true, - :no_css => true - ) - graph.add_data( - :data => commits_data, - :title => l(:label_revision_commit_count) - ) - graph.burn - end - - # 用户最近六个月的提交次数 - def author_commits_six_month(repository) - @date_to = Date.today - @date_from = @date_to << 6 - @date_from = Date.civil(@date_from.year, @date_from.month, @date_from.day) - commits_by_author = Changeset.count(:all, :group => :committer, - :conditions => ["#{Changeset.table_name}.repository_id = ? AND #{Changeset.table_name}.commit_date BETWEEN ? AND ?", repository.id, @date_from, @date_to]) - commits_by_author = commits_by_author.to_a.sort! {|x, y| x.last <=> y.last}.last(25) - - fields = commits_by_author.collect {|r| r.first} - commits_data = commits_by_author.collect {|r| r.last} - - fields = fields + [""]*(10 - fields.length) if fields.length<10 - commits_data = commits_data + [0]*(10 - commits_data.length) if commits_data.length<10 - - # Remove email adress in usernames - fields = fields.collect {|c| c.gsub(%r{<.+@.+>}, '') } - - graph = SVG::Graph::BarHorizontal.new( - :height => 400, - :width => 600, - :fields => fields, - :stack => :side, - :scale_integers => true, - :show_data_values => true, - :rotate_y_labels => false, - :graph_title => l(:label_author_commits_six_month), - :show_graph_title => true - ) - graph.add_data( - :data => commits_data, - :title => l(:label_revision_commit_count) - ) - graph.burn - end - - # 最近六个月代码量统计 - def author_code_six_month(repository) - @date_to = Date.today - @date_from = @date_to << 6 - @date_from = Date.civil(@date_from.year, @date_from.month, @date_from.day) - commits_by_author = Changeset.count(:group => :committer, :conditions => ["#{Changeset.table_name}.repository_id = ? AND #{Changeset.table_name}.commit_date BETWEEN ? AND ?", repository.id, @date_from, @date_to]) - commits_by_author = commits_by_author.to_a.sort! {|x, y| x.last <=> y.last}.last(40) - all_author = [] - commits_by_author.each do |cba| - all_author << cba.first - end - # all_author = all_author.collect {|c| c.gsub(%r{/ /<.+@.+>}, '') } - all_author = all_author.collect {|c| c.split.first } - commits_by_author = repository.commits(all_author, "#{@date_from}", "#{@date_to}", repository.id == 150 ? "szzh" : 'master') - - fields = commits_by_author.collect {|r| r.first} - commits_data = commits_by_author.collect {|r| r.last} - - fields = fields + [""]*(10 - fields.length) if fields.length<10 - commits_data = commits_data + [0]*(10 - commits_data.length) if commits_data.length<10 - - # Remove email adress in usernames - fields = fields.collect {|c| c.gsub(%r{<.+@.+>}, '') } - - graph = SVG::Graph::BarHorizontal.new( - :height => 400, - :width => 600, - :fields => fields, - :stack => :side, - :scale_integers => true, - :show_data_values => true, - :rotate_y_labels => false, - :graph_title => l(:label_author_code_six_month), - :show_graph_title => true - ) - graph.add_data( - :data => commits_data, - :title => l(:lable_revision_code_count) - ) - graph.burn - end - -end +end \ No newline at end of file