Merge branch 'szzh' of http://repository.trustie.net/xianbo/trustie2 into szzh
This commit is contained in:
commit
86354028ed
3
Gemfile
3
Gemfile
|
@ -7,6 +7,7 @@ unless RUBY_PLATFORM =~ /w32/
|
|||
end
|
||||
|
||||
gem 'grack', path:'./lib/grack'
|
||||
gem 'gitlab', path: 'lib/gitlab-cli'
|
||||
gem 'rest-client'
|
||||
gem "mysql2", "= 0.3.18"
|
||||
gem 'redis-rails'
|
||||
|
@ -45,7 +46,7 @@ group :development, :test do
|
|||
gem 'pry-stack_explorer'
|
||||
if RUBY_PLATFORM =~ /darwin/
|
||||
gem 'puma'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
gem 'rspec-rails', '~> 3.0'
|
||||
|
|
|
@ -38,7 +38,8 @@ class ApplicationController < ActionController::Base
|
|||
protect_from_forgery
|
||||
def handle_unverified_request
|
||||
super
|
||||
cookies.delete(autologin_cookie_name)
|
||||
raise(ActionController::InvalidAuthenticityToken)
|
||||
# cookies.delete(autologin_cookie_name)
|
||||
end
|
||||
|
||||
before_filter :find_first_page
|
||||
|
|
|
@ -227,6 +227,8 @@ class AttachmentsController < ApplicationController
|
|||
format.js
|
||||
elsif @attachment.container.is_a?(Message)
|
||||
format.html { redirect_to_referer_or new_board_message_path(@attachment.container) }
|
||||
elsif @attachment.container.is_a?(BlogComment)
|
||||
format.html { redirect_to_referer_or user_blog_blog_comment_path(:user_id=>@attachment.container.author.id,:blog_id=>@attachment.container.blog_id,:id=>@attachment.container.id)}
|
||||
elsif @course.nil?
|
||||
format.html { redirect_to_referer_or forum_memo_path(@attachment.container.forum, @attachment.container) }
|
||||
else
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
class BlogCommentsController < ApplicationController
|
||||
include ApplicationHelper
|
||||
before_filter :find_user
|
||||
def index
|
||||
|
||||
end
|
||||
def create
|
||||
if User.current.logged?
|
||||
@article = BlogComment.new
|
||||
@article.author = User.current
|
||||
@article.blog_id = params[:blog_id]
|
||||
@article.safe_attributes = params[:blog_comment]
|
||||
if request.post?
|
||||
@article.save_attachments(params[:attachments])
|
||||
if @article.save
|
||||
# 更新kindeditor上传的图片资源所有者
|
||||
# if params[:asset_id]
|
||||
# ids = params[:asset_id].split(',')
|
||||
# update_kindeditor_assets_owner ids,@article.id,OwnerTypeHelper::BLOGCOMMENT
|
||||
# end
|
||||
render_attachment_warning_if_needed(@article)
|
||||
else
|
||||
end
|
||||
redirect_to user_blogs_path(:user_id=>params[:user_id])
|
||||
else
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
render :layout => 'new_base_user'
|
||||
}
|
||||
end
|
||||
end
|
||||
else
|
||||
redirect_to signin_path
|
||||
end
|
||||
end
|
||||
def new
|
||||
respond_to do |format|
|
||||
format.html {render :layout=>'new_base_user'}
|
||||
end
|
||||
end
|
||||
def show
|
||||
@article = BlogComment.find(params[:id])
|
||||
respond_to do |format|
|
||||
format.html {render :layout=>'new_base_user'}
|
||||
end
|
||||
end
|
||||
def update
|
||||
@article = BlogComment.find(params[:id])
|
||||
@article.safe_attributes = params[:blog_comment]
|
||||
@article.save_attachments(params[:attachments])
|
||||
if @article.save
|
||||
render_attachment_warning_if_needed(@article)
|
||||
else
|
||||
end
|
||||
redirect_to user_blog_blog_comment_path(:user_id=>params[:user_id],:blog_id=>params[:blog_id],:id=>params[:id])
|
||||
end
|
||||
def destroy
|
||||
@article = BlogComment.find(params[:id])
|
||||
if @article.parent_id.nil? #如果是文章被删,那么跳转到用户博客界面
|
||||
@article.children.delete
|
||||
@article.delete
|
||||
redirect_to user_blogs_path(:user_id=>User.current)
|
||||
else
|
||||
root = @article.root
|
||||
@article.delete
|
||||
redirect_to user_blog_blog_comment_path(:user_id=>root.author_id,:blog_id=>root.blog_id,:id=>root.id)
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
@article = BlogComment.find(params[:id])
|
||||
respond_to do |format|
|
||||
format.html {render :layout=>'new_base_user'}
|
||||
end
|
||||
end
|
||||
|
||||
def quote
|
||||
@blogComment = BlogComment.find(params[:id])
|
||||
@subject = @blogComment.title
|
||||
@subject = "RE: #{@subject}" unless @subject.starts_with?('RE:')
|
||||
|
||||
@content = "> #{ll(Setting.default_language, :text_user_wrote, @blogComment.author.realname)}\n> "
|
||||
@temp = BlogComment.new
|
||||
@temp.content = "<blockquote>#{ll(Setting.default_language, :text_user_wrote, @blogComment.author.realname)} <br/>#{@blogComment.content.html_safe}</blockquote>".html_safe
|
||||
respond_to do | format|
|
||||
format.js
|
||||
end
|
||||
end
|
||||
|
||||
#回复
|
||||
def reply
|
||||
@article = BlogComment.find(params[:id]).root
|
||||
@quote = params[:quote][:quote]
|
||||
@blogComment = BlogComment.new
|
||||
@blogComment.author = User.current
|
||||
@blogComment.blog = Blog.find(params[:blog_id])
|
||||
params[:blog_comment][:sticky] = params[:blog_comment][:sticky] || 0
|
||||
params[:blog_comment][:locked] = params[:blog_comment][:locked] || 0
|
||||
@blogComment.safe_attributes = params[:blog_comment]
|
||||
@blogComment.content = @quote + @blogComment.content
|
||||
@blogComment.title = "RE: #{@article.title}" unless params[:blog_comment][:title]
|
||||
@article.children << @blogComment
|
||||
@user_activity_id = params[:user_activity_id]
|
||||
|
||||
attachments = Attachment.attach_files(@blogComment, params[:attachments])
|
||||
render_attachment_warning_if_needed(@blogComment)
|
||||
#@article.save
|
||||
# redirect_to user_blogs_path(:user_id=>params[:user_id])
|
||||
respond_to do |format|
|
||||
format.html { redirect_to user_blog_blog_comment_path(:user_id=>@article.author_id,:blog_id=>@article.blog_id,:id=>@article)}
|
||||
format.js
|
||||
end
|
||||
rescue Exception => e #如果上面的代码执行发生异常就捕获
|
||||
flash[:notice] = e.message
|
||||
end
|
||||
|
||||
private
|
||||
def find_user
|
||||
@user = User.find(params[:user_id])
|
||||
end
|
||||
end
|
|
@ -0,0 +1,47 @@
|
|||
class BlogsController < ApplicationController
|
||||
before_filter :find_blog,:except => [:index,:create,:new]
|
||||
before_filter :find_user
|
||||
def index
|
||||
@articls = @user.blog.articles
|
||||
@article = BlogComment.new
|
||||
respond_to do |format|
|
||||
format.html {render :layout=>'new_base_user'}
|
||||
end
|
||||
end
|
||||
def create
|
||||
|
||||
end
|
||||
def new
|
||||
|
||||
end
|
||||
def show
|
||||
|
||||
end
|
||||
def update
|
||||
|
||||
end
|
||||
def destory
|
||||
|
||||
end
|
||||
def edit
|
||||
|
||||
end
|
||||
private
|
||||
def find_blog
|
||||
if params[:blog_id]
|
||||
@blog = Blog.find(params[:blog_id])
|
||||
else
|
||||
render_404
|
||||
end
|
||||
if @blog.nil?
|
||||
#如果某个user的blog不存在,那么就创建一条
|
||||
@blog = Blog.create(:name=>User.find(params[:id]).realname ,
|
||||
:description=>'',
|
||||
:author_id=>params[:id])
|
||||
end
|
||||
end
|
||||
|
||||
def find_user
|
||||
@user = User.find(params[:user_id])
|
||||
end
|
||||
end
|
|
@ -31,13 +31,11 @@ class CoursesController < ApplicationController
|
|||
|
||||
def join
|
||||
if User.current.logged?
|
||||
# if params[:role] == 10
|
||||
cs = CoursesService.new
|
||||
@user = User.current
|
||||
join = cs.join_course params,@user
|
||||
@state = join[:state]
|
||||
@course = join[:course]
|
||||
Mailer.run.join_course_request(@course, User.current, params[:role])
|
||||
# else
|
||||
# @course = Course.find_by_id params[:object_id]
|
||||
# CourseMessage.create(:user_id => @course.tea_id, :course_id => @course.id, :viewed => false,:content=> params[:role],:course_message_id=>User.current.id,:course_message_type=>'JoinCourseRequest')
|
||||
|
@ -290,14 +288,11 @@ class CoursesController < ApplicationController
|
|||
def export_course_member_excel
|
||||
@all_members = student_homework_score(0,0,0,"desc")
|
||||
filename="#{@course.teacher.lastname.to_s + @course.teacher.firstname.to_s }_#{@course.name}_#{@course.time.to_s + @course.term}#{l(:excel_member_list)}";
|
||||
# 如果是ie 需要转码
|
||||
if(/trident/.match(request.env["HTTP_USER_AGENT"]) != nil)
|
||||
filename= URI::encode(filename)
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
format.xls {
|
||||
send_data(member_to_xls(@all_members,@course.course_groups), :type => "text/excel;charset=utf-8; header=present",
|
||||
:filename => "#{filename}.xls")
|
||||
:filename => filename_for_content_disposition("#{filename}.xls"))
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -42,8 +42,8 @@ class GanttsController < ApplicationController
|
|||
|
||||
respond_to do |format|
|
||||
format.html { render :action => "show", :layout => 'base_projects' }#by young
|
||||
format.png { send_data(@gantt.to_image, :disposition => 'inline', :type => 'image/png', :filename => "#{basename}.png") } if @gantt.respond_to?('to_image')
|
||||
format.pdf { send_data(@gantt.to_pdf, :type => 'application/pdf', :filename => "#{basename}.pdf") }
|
||||
format.png { send_data(@gantt.to_image, :disposition => 'inline', :type => 'image/png', :filename => filename_for_content_disposition("#{basename}.png")) } if @gantt.respond_to?('to_image')
|
||||
format.pdf { send_data(@gantt.to_pdf, :type => 'application/pdf', :filename => filename_for_content_disposition("#{basename}.pdf") ) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -33,7 +33,7 @@ class HomeworkAttachController < ApplicationController
|
|||
format.js
|
||||
format.xls {
|
||||
send_data(homework_to_xls(@all_homework_list), :type => "text/excel;charset=utf-8; header=present",
|
||||
:filename => "#{@course.teacher.lastname.to_s + @course.teacher.firstname}_#{@course.name}_#{@course.time.to_s + @course.term}_#{@bid.name}#{l(:excel_homework_list)}(#{l(:excel_not_rated)}).xls")
|
||||
:filename => filename_for_content_disposition("#{@course.teacher.lastname.to_s + @course.teacher.firstname}_#{@course.name}_#{@course.time.to_s + @course.term}_#{@bid.name}#{l(:excel_homework_list)}(#{l(:excel_not_rated)}).xls") )
|
||||
}
|
||||
end
|
||||
end
|
||||
|
@ -66,7 +66,7 @@ class HomeworkAttachController < ApplicationController
|
|||
format.js
|
||||
format.xls {
|
||||
send_data(homework_to_xls(all_homework_list), :type => "text/excel;charset=utf-8; header=present",
|
||||
:filename => "#{@course.teacher.lastname.to_s + @course.teacher.firstname}_#{@course.name}_#{@course.time.to_s + @course.term}_#{@bid.name}#{l(:excel_homework_list)}(#{l(:excel_been_rated)}).xls")
|
||||
:filename => filename_for_content_disposition("#{@course.teacher.lastname.to_s + @course.teacher.firstname}_#{@course.name}_#{@course.time.to_s + @course.term}_#{@bid.name}#{l(:excel_homework_list)}(#{l(:excel_been_rated)}).xls") )
|
||||
}
|
||||
end
|
||||
end
|
||||
|
@ -101,7 +101,7 @@ class HomeworkAttachController < ApplicationController
|
|||
format.js
|
||||
format.xls {
|
||||
send_data(homework_to_xls(all_homework_list), :type => "text/excel;charset=utf-8; header=present",
|
||||
:filename => "#{@course.teacher.lastname.to_s + @course.teacher.firstname}_#{@course.name}_#{@course.time.to_s + @course.term}_#{@bid.name}#{l(:excel_homework_list)}.xls")
|
||||
:filename => filename_for_content_disposition("#{@course.teacher.lastname.to_s + @course.teacher.firstname}_#{@course.name}_#{@course.time.to_s + @course.term}_#{@bid.name}#{l(:excel_homework_list)}.xls") )
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -151,7 +151,7 @@ class IssuesController < ApplicationController
|
|||
format.atom { render :template => 'journals/index', :layout => false, :content_type => 'application/atom+xml' }
|
||||
format.pdf {
|
||||
pdf = issue_to_pdf(@issue, :journals => @journals)
|
||||
send_data(pdf, :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf")
|
||||
send_data(pdf, :type => 'application/pdf', :filename => filename_for_content_disposition("#{@project.identifier}-#{@issue.id}.pdf") )
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -413,7 +413,7 @@ class PollController < ApplicationController
|
|||
respond_to do |format|
|
||||
format.xls {
|
||||
send_data(poll_to_xls(poll_questions), :type => "text/excel;charset=utf-8; header=present",
|
||||
:filename => "#{@poll.polls_name}.xls")
|
||||
:filename => filename_for_content_disposition("#{@poll.polls_name}.xls") )
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -29,12 +29,12 @@ class RepositoriesController < ApplicationController
|
|||
menu_item :repository
|
||||
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]
|
||||
before_filter :find_repository, :only => [:edit, :update, :destroy, :committers]
|
||||
before_filter :find_project_repository, :except => [:new, :create, :newcreate, :edit, :update, :destroy, :committers, :newrepo]
|
||||
before_filter :find_project_repository, :except => [:new, :create, :newcreate, :edit, :update, :destroy, :committers, :newrepo,:to_gitlab]
|
||||
before_filter :find_changeset, :only => [:revision, :add_related_issue, :remove_related_issue]
|
||||
before_filter :authorize , :except => [:newrepo,:newcreate,:fork]
|
||||
before_filter :authorize , :except => [:newrepo,:newcreate,:fork, :to_gitlab]
|
||||
accept_rss_auth :revisions
|
||||
# hidden repositories filter // 隐藏代码过滤器
|
||||
before_filter :check_hidden_repo, :only => [:show, :stats, :revisions, :revision, :diff ]
|
||||
|
@ -42,7 +42,7 @@ class RepositoriesController < ApplicationController
|
|||
include RepositoriesHelper
|
||||
helper :project_score
|
||||
#@root_path = RepositoriesHelper::ROOT_PATH
|
||||
|
||||
|
||||
|
||||
rescue_from Redmine::Scm::Adapters::CommandFailed, :with => :show_error_command_failed
|
||||
def new
|
||||
|
@ -62,8 +62,8 @@ class RepositoriesController < ApplicationController
|
|||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
def newrepo
|
||||
scm = params[:repository_scm] || (Redmine::Scm::Base.all & Setting.enabled_scm).first
|
||||
@repository = Repository.factory(scm)
|
||||
|
@ -76,23 +76,23 @@ class RepositoriesController < ApplicationController
|
|||
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
|
||||
# " "+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 "+
|
||||
# "<Limit PUT POST DELETE PROPPATCH MKCOL COPY MOVE LOCK UNLOCK> \n"+
|
||||
# "Require group "+params[:project_id]+"-"+params[:repository][:identifier]+"-write \n "+
|
||||
# "</Limit> \n ' >>"+
|
||||
# @project_path+"/.htaccess"
|
||||
# "<Limit PUT POST DELETE PROPPATCH MKCOL COPY MOVE LOCK UNLOCK> \n"+
|
||||
# "Require group "+params[:project_id]+"-"+params[:repository][:identifier]+"-write \n "+
|
||||
# "</Limit> \n ' >>"+
|
||||
# @project_path+"/.htaccess"
|
||||
flash[:notice] = l(:label_notice_fork_successed)
|
||||
@repositories = @project.repositories
|
||||
render :action => 'show', :layout => 'base_projects'
|
||||
|
@ -115,77 +115,36 @@ update
|
|||
}
|
||||
|
||||
def create
|
||||
if params[:repository_scm].to_s == 'Gitlab'
|
||||
# add by nwb
|
||||
# 增加对gitlab版本库的支持
|
||||
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
|
||||
if request.post? && @repository.save
|
||||
redirect_to settings_project_url(@project, :tab => 'repositories')
|
||||
else
|
||||
redirect_to settings_project_url(@project, :tab => 'repositories')
|
||||
end
|
||||
else # 原逻辑
|
||||
##xianbo
|
||||
@root_path=RepositoriesHelper::ROOT_PATH
|
||||
@repository_name=User.current.login.to_s+"/"+params[:repository][:identifier]+".git"
|
||||
@project_path=@root_path+"htdocs/"+@repository_name
|
||||
@repository_tag=params[:repository][:upassword] || params[:repository][:password]
|
||||
@repo_name=User.current.login.to_s+"_"+params[:repository][:identifier]
|
||||
logger.info "htpasswd -mb "+@root_path+"htdocs/user.passwd "+@repo_name+": "+@repository_tag
|
||||
logger.info "the value of create repository"+@root_path+": "+@repository_name+": "+@project_path+": "+@repo_name
|
||||
attrs = pickup_extra_info
|
||||
if((@repository_tag!="")&¶ms[:repository_scm]=="Git")
|
||||
params[:repository][:url]=@project_path
|
||||
end
|
||||
###xianbo
|
||||
@repository = Repository.factory(params[:repository_scm])
|
||||
@repository.safe_attributes = params[:repository]
|
||||
if attrs[:attrs_extra].keys.any?
|
||||
@repository.merge_extra_info(attrs[:attrs_extra])
|
||||
end
|
||||
|
||||
@repository.project = @project
|
||||
if request.post? && @repository.save
|
||||
if(params[:repository_scm]=="Git")
|
||||
system "htpasswd -mb "+@root_path+"htdocs/user.passwd "+@repo_name+" "+@repository_tag
|
||||
system "echo -e '"+@repo_name+"-write:"+
|
||||
" "+@repo_name+"' >> "+@root_path+"htdocs/group.passwd"
|
||||
system "mkdir "+@root_path+"htdocs/"+User.current.login.to_s
|
||||
system "git init --bare "+@project_path
|
||||
system "mv "+@project_path+"/hooks/post-update{.sample,}"
|
||||
system "chmod a+x "+@project_path+"/hooks/post-update"
|
||||
system "echo -e 'Allow from all \n Order Deny,Allow \n "+
|
||||
"<Limit PUT POST DELETE PROPPATCH MKCOL COPY MOVE LOCK UNLOCK> \n"+
|
||||
"Require group "+@repo_name+"-write \n "+
|
||||
"</Limit> \n ' >> "+
|
||||
@root_path+"htdocs/"+ @repository_name+"/.htaccess"
|
||||
system "cd "+@project_path+" ;git update-server-info"
|
||||
|
||||
File.open(@project_path+"/hooks/post-update", "w+") do |f|
|
||||
f.write(HOOK_TEMPLATE)
|
||||
end
|
||||
|
||||
@repository.update_attributes(:login => User.current.login.to_s)
|
||||
end
|
||||
redirect_to settings_project_url(@project, :tab => 'repositories',:repository_error_message=>@repository.errors.full_messages)
|
||||
else if(@repository_tag.blank?)
|
||||
#render :action => 'newrepo', :layout =>'base_projects'
|
||||
redirect_to settings_project_url(@project, :tab => 'repositories',:repository => "pswd_is_null",:repository_error_message=>@repository.errors.full_messages)
|
||||
else
|
||||
redirect_to settings_project_url(@project, :tab => 'repositories',:repository => @repository,:repository_error_message=>@repository.errors.full_messages)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
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.url = @repository.identifier
|
||||
if request.post? && @repository.save
|
||||
g = ::Gitlab.client
|
||||
gid = @project.owner.gid
|
||||
gproject = g.create_project(@repository.identifier,
|
||||
path: @repository.identifier,
|
||||
description: @project.description,
|
||||
wiki_enabled: false,
|
||||
wall_enabled: false,
|
||||
issues_enabled: false,
|
||||
snippets_enabled: false,
|
||||
public: false,
|
||||
user_id: gid
|
||||
)
|
||||
@project.gpid = gproject.id
|
||||
@project.save!
|
||||
redirect_to settings_project_url(@project, :tab => 'repositories')
|
||||
else
|
||||
redirect_to settings_project_url(@project, :tab => 'repositories',:repository_error_message=>@repository.errors.full_messages)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
|
@ -228,15 +187,17 @@ update
|
|||
# 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)
|
||||
redirect_to settings_project_url(@project, :tab => 'repositories')
|
||||
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
|
||||
|
||||
|
||||
respond_to do |format|
|
||||
format.html{
|
||||
render :layout => "base_projects"
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -247,6 +208,16 @@ update
|
|||
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
|
||||
## TODO: the below will move to filter, done.
|
||||
if !User.current.member_of?(@project)
|
||||
|
@ -256,19 +227,23 @@ update
|
|||
end
|
||||
end
|
||||
|
||||
if params[:to] == 'gitlab'
|
||||
g = Gitlab.client
|
||||
g.post('/session', body: {email: User.current.mail, password: User.current.hashed_password})
|
||||
redirect_to "http://192.168.41.130:3000/gitlab-org/gitlab-shell/tree/master"
|
||||
unless @repository.gitlab?
|
||||
# redirect_to to_gitlab_project_repository_path(@project, @repository)
|
||||
render :to_gitlab
|
||||
return
|
||||
end
|
||||
|
||||
#if( !User.current.member_of?(@project) || @project.hidden_repo)
|
||||
@repository.fetch_changesets if Setting.autofetch_changesets? && @path.empty?
|
||||
|
||||
# g = Gitlab.client
|
||||
# project = g.project(20)
|
||||
# rr = g.trees(project.id, @path)
|
||||
# r = g.get ("/projects/#{@project}/repository/tree")
|
||||
# :name, :path, :kind, :size, :lastrev, :changeset
|
||||
@entries = @repository.entries(@path, @rev)
|
||||
# @trees = g.trees(project, @path)
|
||||
@changeset = @repository.find_changeset_by_name(@rev)
|
||||
|
||||
#@project_path_cut = RepositoriesHelper::PROJECT_PATH_CUT
|
||||
#@ip = RepositoriesHelper::REPO_IP_ADDRESS
|
||||
|
||||
|
@ -276,15 +251,22 @@ update
|
|||
@entries ? render(:partial => 'dir_list_content') : render(:nothing => true)
|
||||
else
|
||||
#Modified by young
|
||||
# (show_error_not_found; return) unless @entries
|
||||
# (show_error_not_found; return) unless @entries
|
||||
@changesets = @repository.latest_changesets(@path, @rev)
|
||||
@changesets_count = @repository.latest_changesets(@path, @rev).count
|
||||
@changesets_latest_coimmit = @changesets.first
|
||||
@properties = @repository.properties(@path, @rev)
|
||||
@repositories = @project.repositories
|
||||
@course_tag = params[:course]
|
||||
project_path_cut = RepositoriesHelper::PROJECT_PATH_CUT
|
||||
ip = RepositoriesHelper::REPO_IP_ADDRESS
|
||||
@repos_url = "http://"+@repository.login.to_s+"_"+@repository.identifier.to_s+"@"+ip.to_s+
|
||||
@repository.url.slice(project_path_cut, @repository.url.length).to_s
|
||||
gitlab_address = RepositoriesHelper::REPO_GITLAB_ADDRESS
|
||||
if @repository.type.to_s=="Repository::Gitlab"
|
||||
@repos_url = "http://"+gitlab_address.to_s+"/"+@project.owner.to_s+"/"+@repository.identifier+"."+"git"
|
||||
else
|
||||
@repos_url = "http://"+@repository.login.to_s+"_"+@repository.identifier.to_s+"@"+ip.to_s+
|
||||
@repository.url.slice(project_path_cut, @repository.url.length).to_s
|
||||
end
|
||||
if @course_tag == 1
|
||||
render :action => 'show', :layout => 'base_courses'
|
||||
else
|
||||
|
@ -310,10 +292,10 @@ update
|
|||
per_page_option,
|
||||
params['page']
|
||||
@changesets = @repository.changesets.
|
||||
limit(@changeset_pages.per_page).
|
||||
offset(@changeset_pages.offset).
|
||||
includes(:user, :repository, :parents).
|
||||
all
|
||||
limit(@changeset_pages.per_page).
|
||||
offset(@changeset_pages.offset).
|
||||
includes(:user, :repository, :parents).
|
||||
all
|
||||
|
||||
respond_to do |format|
|
||||
format.html { render :layout => 'base_projects' }
|
||||
|
@ -327,6 +309,7 @@ update
|
|||
|
||||
def entry
|
||||
entry_and_raw(false)
|
||||
render :layout => 'base_projects'
|
||||
end
|
||||
|
||||
def entry_and_raw(is_raw)
|
||||
|
@ -339,8 +322,8 @@ update
|
|||
@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)
|
||||
(@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)
|
||||
|
@ -423,8 +406,8 @@ update
|
|||
filename = "changeset_r#{@rev}"
|
||||
filename << "_r#{@rev_to}" if @rev_to
|
||||
send_data @diff.join, :filename => "#{filename}.diff",
|
||||
:type => 'text/x-patch',
|
||||
:disposition => 'attachment'
|
||||
: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)
|
||||
|
@ -435,7 +418,7 @@ update
|
|||
User.current.preference.save
|
||||
end
|
||||
@cache_key = "repositories/diff/#{@repository.id}/" +
|
||||
Digest::MD5.hexdigest("#{@path}-#{@rev}-#{@rev_to}-#{@diff_type}-#{current_language}")
|
||||
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
|
||||
|
@ -462,16 +445,16 @@ update
|
|||
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)
|
||||
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"
|
||||
|
@ -551,14 +534,14 @@ update
|
|||
@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])
|
||||
: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])
|
||||
: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 }
|
||||
|
||||
|
@ -566,26 +549,26 @@ update
|
|||
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
|
||||
: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)
|
||||
: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)
|
||||
:data => changes_by_month[0..11].reverse,
|
||||
:title => l(:label_change_plural)
|
||||
)
|
||||
|
||||
graph.burn
|
||||
|
@ -610,23 +593,23 @@ update
|
|||
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
|
||||
: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)
|
||||
:data => commits_data,
|
||||
:title => l(:label_revision_plural)
|
||||
)
|
||||
graph.add_data(
|
||||
:data => changes_data,
|
||||
:title => l(:label_change_plural)
|
||||
:data => changes_data,
|
||||
:title => l(:label_change_plural)
|
||||
)
|
||||
graph.burn
|
||||
end
|
||||
|
@ -637,7 +620,7 @@ update
|
|||
@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])
|
||||
: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}
|
||||
|
|
|
@ -84,7 +84,7 @@ class StoresController < ApplicationController
|
|||
respond_to do |format|
|
||||
format.xls {
|
||||
send_data(homework_to_xls(attachments), :type => "text/excel;charset=utf-8; header=present",
|
||||
:filename => "#{l(:label_file_lost_list)}.xls")
|
||||
:filename => filename_for_content_disposition("#{l(:label_file_lost_list)}.xls") )
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -82,14 +82,14 @@ class WikiController < ApplicationController
|
|||
@content = @page.content_for_version(params[:version])
|
||||
if User.current.allowed_to?(:export_wiki_pages, @project)
|
||||
if params[:format] == 'pdf'
|
||||
send_data(wiki_page_to_pdf(@page, @project), :type => 'application/pdf', :filename => "#{@page.title}.pdf")
|
||||
send_data(wiki_page_to_pdf(@page, @project), :type => 'application/pdf', :filename => filename_for_content_disposition("#{@page.title}.pdf") )
|
||||
return
|
||||
elsif params[:format] == 'html'
|
||||
export = render_to_string :action => 'export', :layout => false
|
||||
send_data(export, :type => 'text/html', :filename => "#{@page.title}.html")
|
||||
send_data(export, :type => 'text/html', :filename => filename_for_content_disposition("#{@page.title}.html"))
|
||||
return
|
||||
elsif params[:format] == 'txt'
|
||||
send_data(@content.text, :type => 'text/plain', :filename => "#{@page.title}.txt")
|
||||
send_data(@content.text, :type => 'text/plain', :filename => filename_for_content_disposition("#{@page.title}.txt") )
|
||||
return
|
||||
end
|
||||
end
|
||||
|
@ -286,7 +286,7 @@ class WikiController < ApplicationController
|
|||
send_data(export, :type => 'text/html', :filename => "wiki.html")
|
||||
}
|
||||
format.pdf {
|
||||
send_data(wiki_pages_to_pdf(@pages, @project), :type => 'application/pdf', :filename => "#{@project.identifier}.pdf")
|
||||
send_data(wiki_pages_to_pdf(@pages, @project), :type => 'application/pdf', :filename => filename_for_content_disposition("#{@project.identifier}.pdf") )
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
module BlogCommentsHelper
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
module BlogsHelper
|
||||
end
|
|
@ -7,4 +7,5 @@ module OwnerTypeHelper
|
|||
BID = 6
|
||||
JOURNALSFORMESSAGE = 7
|
||||
HOMEWORKCOMMON = 8
|
||||
BLOGCOMMENT=9
|
||||
end
|
|
@ -25,6 +25,7 @@ module RepositoriesHelper
|
|||
end
|
||||
PROJECT_PATH_CUT = 40
|
||||
REPO_IP_ADDRESS = Setting.host_repository
|
||||
REPO_GITLAB_ADDRESS = "git.trustie.net"
|
||||
|
||||
def format_revision(revision)
|
||||
if revision.respond_to? :format_identifier
|
||||
|
@ -34,6 +35,10 @@ module RepositoriesHelper
|
|||
end
|
||||
end
|
||||
|
||||
def repository_creater rep
|
||||
repository_creater = User.find_by_login(rep.login) unless rep.login.nil?
|
||||
end
|
||||
|
||||
def truncate_at_line_break(text, length = 255)
|
||||
if text
|
||||
text.gsub(%r{^(.{#{length}}[^\n]*)\n.+$}m, '\\1...')
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
class Blog < ActiveRecord::Base
|
||||
# attr_accessible :title, :body
|
||||
include Redmine::SafeAttributes
|
||||
belongs_to :user
|
||||
has_many :articles, :class_name => 'BlogComment', :conditions => "#{BlogComment.table_name}.parent_id IS NULL ", :order => "#{BlogComment.table_name}.created_on DESC"
|
||||
has_many :blog_comments, :dependent => :destroy, :order => "#{BlogComment.table_name}.created_on DESC"
|
||||
belongs_to :last_comment, :class_name => 'BlogComment', :foreign_key => :last_comment_id
|
||||
acts_as_tree :dependent => :nullify
|
||||
#acts_as_list :scope => '(user_id = #{user_id} AND parent_id #{user_id ? = "#{parent_id}" : "IS NULL"})'
|
||||
acts_as_watchable
|
||||
|
||||
validates :name, presence: true, length: {maximum: 30}
|
||||
validates :description, length: {maximum: 255}
|
||||
|
||||
safe_attributes 'name', 'description'
|
||||
end
|
|
@ -0,0 +1,24 @@
|
|||
class BlogComment < ActiveRecord::Base
|
||||
# attr_accessible :title, :body
|
||||
include Redmine::SafeAttributes
|
||||
belongs_to :blog
|
||||
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
|
||||
|
||||
acts_as_tree :counter_cache => :comments_count, :order => "#{BlogComment.table_name}.sticky desc ,#{BlogComment.table_name}.created_on ASC"
|
||||
acts_as_attachable
|
||||
belongs_to :last_reply, :class_name => 'BlogComment', :foreign_key => 'last_comment_id'
|
||||
|
||||
acts_as_watchable
|
||||
|
||||
validates_presence_of :title, :content
|
||||
validates_length_of :title, :maximum => 255
|
||||
#validate :cannot_reply_to_locked_comment, :on => :create
|
||||
safe_attributes 'title', 'content',"sticky", "locked"
|
||||
|
||||
def deleted_attach_able_by? user
|
||||
(user && user.logged? && (self.author == user) ) || user.admin?
|
||||
end
|
||||
|
||||
def project
|
||||
end
|
||||
end
|
|
@ -34,6 +34,7 @@ class Member < ActiveRecord::Base
|
|||
after_destroy :delete_ivite_list
|
||||
|
||||
|
||||
|
||||
def role
|
||||
end
|
||||
|
||||
|
|
|
@ -35,8 +35,11 @@ class MemberRole < ActiveRecord::Base
|
|||
!inherited_from.nil?
|
||||
end
|
||||
|
||||
include Trustie::Gitlab::ManageMember
|
||||
|
||||
private
|
||||
|
||||
|
||||
def remove_member_if_empty
|
||||
if member.roles.empty?
|
||||
member.destroy
|
||||
|
|
|
@ -770,7 +770,8 @@ class Project < ActiveRecord::Base
|
|||
'project_type',
|
||||
'dts_test',
|
||||
'attachmenttype',
|
||||
'enterprise_name'
|
||||
'enterprise_name',
|
||||
'gpid'
|
||||
|
||||
|
||||
|
||||
|
@ -853,6 +854,10 @@ class Project < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def owner
|
||||
User.find(self.user_id)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def after_parent_changed(parent_was)
|
||||
|
@ -1167,5 +1172,7 @@ class Project < ActiveRecord::Base
|
|||
:forge_act_id => self.id,:forge_act_type => "ProjectCreateInfo")
|
||||
fa.save!
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -57,6 +57,11 @@ class Repository < ActiveRecord::Base
|
|||
safe_attributes 'url',
|
||||
:if => lambda {|repository, user| repository.new_record?}
|
||||
|
||||
|
||||
def gitlab?
|
||||
self.type == 'Repository::Gitlab'
|
||||
end
|
||||
|
||||
def repo_create_validation
|
||||
unless Setting.enabled_scm.include?(self.class.name.demodulize)
|
||||
errors.add(:type, :invalid)
|
||||
|
|
|
@ -0,0 +1,259 @@
|
|||
#coding=utf-8
|
||||
|
||||
require 'redmine/scm/adapters/git_adapter'
|
||||
|
||||
class Repository::Gitlab < Repository
|
||||
|
||||
attr_protected :root_url
|
||||
validates_presence_of :url
|
||||
|
||||
def self.human_attribute_name(attribute_key_name, *args)
|
||||
attr_name = attribute_key_name.to_s
|
||||
if attr_name == "url"
|
||||
attr_name = "path_to_repository"
|
||||
end
|
||||
super(attr_name, *args)
|
||||
end
|
||||
|
||||
def self.scm_adapter_class
|
||||
Redmine::Scm::Adapters::GitlabAdapter
|
||||
end
|
||||
|
||||
def self.scm_name
|
||||
'Gitlab'
|
||||
end
|
||||
|
||||
def commits(authors, start_date, end_date, branch='master')
|
||||
scm.commits(authors, start_date, end_date,branch).map {|commit|
|
||||
[commit[:author], commit[:num]]
|
||||
}
|
||||
end
|
||||
|
||||
def report_last_commit
|
||||
extra_report_last_commit
|
||||
end
|
||||
|
||||
def extra_report_last_commit
|
||||
return false if extra_info.nil?
|
||||
v = extra_info["extra_report_last_commit"]
|
||||
return false if v.nil?
|
||||
v.to_s != '0'
|
||||
end
|
||||
|
||||
def supports_directory_revisions?
|
||||
true
|
||||
end
|
||||
|
||||
def supports_revision_graph?
|
||||
true
|
||||
end
|
||||
|
||||
def repo_log_encoding
|
||||
'UTF-8'
|
||||
end
|
||||
|
||||
# Returns the identifier for the given git changeset
|
||||
def self.changeset_identifier(changeset)
|
||||
changeset.scmid
|
||||
end
|
||||
|
||||
# Returns the readable identifier for the given git changeset
|
||||
def self.format_changeset_identifier(changeset)
|
||||
changeset.revision[0, 8]
|
||||
end
|
||||
|
||||
def branches
|
||||
scm.branches
|
||||
end
|
||||
|
||||
def tags
|
||||
scm.tags
|
||||
end
|
||||
|
||||
def default_branch
|
||||
scm.default_branch
|
||||
rescue Exception => e
|
||||
logger.error "git: error during get default branch: #{e.message}"
|
||||
nil
|
||||
end
|
||||
|
||||
def find_changeset_by_name(name)
|
||||
if name.present?
|
||||
changesets.where(:revision => name.to_s).first ||
|
||||
changesets.where('scmid LIKE ?', "#{name}%").first
|
||||
end
|
||||
end
|
||||
|
||||
def entries(path=nil, identifier=nil)
|
||||
entries = scm.entries(path, identifier, :report_last_commit => extra_report_last_commit)
|
||||
load_entries_changesets(entries)
|
||||
entries
|
||||
end
|
||||
|
||||
# With SCMs that have a sequential commit numbering,
|
||||
# such as Subversion and Mercurial,
|
||||
# Redmine is able to be clever and only fetch changesets
|
||||
# going forward from the most recent one it knows about.
|
||||
#
|
||||
# However, Git does not have a sequential commit numbering.
|
||||
#
|
||||
# In order to fetch only new adding revisions,
|
||||
# Redmine needs to save "heads".
|
||||
#
|
||||
# In Git and Mercurial, revisions are not in date order.
|
||||
# Redmine Mercurial fixed issues.
|
||||
# * Redmine Takes Too Long On Large Mercurial Repository
|
||||
# http://www.redmine.org/issues/3449
|
||||
# * Sorting for changesets might go wrong on Mercurial repos
|
||||
# http://www.redmine.org/issues/3567
|
||||
#
|
||||
# Database revision column is text, so Redmine can not sort by revision.
|
||||
# Mercurial has revision number, and revision number guarantees revision order.
|
||||
# Redmine Mercurial model stored revisions ordered by database id to database.
|
||||
# So, Redmine Mercurial model can use correct ordering revisions.
|
||||
#
|
||||
# Redmine Mercurial adapter uses "hg log -r 0:tip --limit 10"
|
||||
# to get limited revisions from old to new.
|
||||
# But, Git 1.7.3.4 does not support --reverse with -n or --skip.
|
||||
#
|
||||
# The repository can still be fully reloaded by calling #clear_changesets
|
||||
# before fetching changesets (eg. for offline resync)
|
||||
def fetch_changesets
|
||||
scm_brs = branches
|
||||
return if scm_brs.nil? || scm_brs.empty?
|
||||
|
||||
h1 = extra_info || {}
|
||||
h = h1.dup
|
||||
repo_heads = scm_brs.map{ |br| br.scmid }
|
||||
h["heads"] ||= []
|
||||
prev_db_heads = h["heads"].dup
|
||||
if prev_db_heads.empty?
|
||||
prev_db_heads += heads_from_branches_hash
|
||||
end
|
||||
return if prev_db_heads.sort == repo_heads.sort
|
||||
|
||||
h["db_consistent"] ||= {}
|
||||
if changesets.count == 0
|
||||
h["db_consistent"]["ordering"] = 1
|
||||
merge_extra_info(h)
|
||||
self.save
|
||||
elsif ! h["db_consistent"].has_key?("ordering")
|
||||
h["db_consistent"]["ordering"] = 0
|
||||
merge_extra_info(h)
|
||||
self.save
|
||||
end
|
||||
save_revisions(prev_db_heads, repo_heads)
|
||||
end
|
||||
|
||||
def save_revisions(prev_db_heads, repo_heads)
|
||||
h = {}
|
||||
opts = {}
|
||||
opts[:reverse] = true
|
||||
opts[:excludes] = prev_db_heads
|
||||
opts[:includes] = repo_heads
|
||||
|
||||
revisions = scm.revisions('', nil, nil, opts)
|
||||
return if revisions.blank?
|
||||
|
||||
# Make the search for existing revisions in the database in a more sufficient manner
|
||||
#
|
||||
# Git branch is the reference to the specific revision.
|
||||
# Git can *delete* remote branch and *re-push* branch.
|
||||
#
|
||||
# $ git push remote :branch
|
||||
# $ git push remote branch
|
||||
#
|
||||
# After deleting branch, revisions remain in repository until "git gc".
|
||||
# On git 1.7.2.3, default pruning date is 2 weeks.
|
||||
# So, "git log --not deleted_branch_head_revision" return code is 0.
|
||||
#
|
||||
# After re-pushing branch, "git log" returns revisions which are saved in database.
|
||||
# So, Redmine needs to scan revisions and database every time.
|
||||
#
|
||||
# This is replacing the one-after-one queries.
|
||||
# Find all revisions, that are in the database, and then remove them from the revision array.
|
||||
# Then later we won't need any conditions for db existence.
|
||||
# Query for several revisions at once, and remove them from the revisions array, if they are there.
|
||||
# Do this in chunks, to avoid eventual memory problems (in case of tens of thousands of commits).
|
||||
# If there are no revisions (because the original code's algorithm filtered them),
|
||||
# then this part will be stepped over.
|
||||
# We make queries, just if there is any revision.
|
||||
limit = 100
|
||||
offset = 0
|
||||
revisions_copy = revisions.clone # revisions will change
|
||||
while offset < revisions_copy.size
|
||||
recent_changesets_slice = changesets.find(
|
||||
:all,
|
||||
:conditions => [
|
||||
'scmid IN (?)',
|
||||
revisions_copy.slice(offset, limit).map{|x| x.scmid}
|
||||
]
|
||||
)
|
||||
# Subtract revisions that redmine already knows about
|
||||
recent_revisions = recent_changesets_slice.map{|c| c.scmid}
|
||||
revisions.reject!{|r| recent_revisions.include?(r.scmid)}
|
||||
offset += limit
|
||||
end
|
||||
|
||||
revisions.each do |rev|
|
||||
transaction do
|
||||
# There is no search in the db for this revision, because above we ensured,
|
||||
# that it's not in the db.
|
||||
save_revision(rev)
|
||||
end
|
||||
end
|
||||
h["heads"] = repo_heads.dup
|
||||
merge_extra_info(h)
|
||||
self.save
|
||||
end
|
||||
private :save_revisions
|
||||
|
||||
def save_revision(rev)
|
||||
parents = (rev.parents || []).collect{|rp| find_changeset_by_name(rp)}.compact
|
||||
changeset = Changeset.create(
|
||||
:repository => self,
|
||||
:revision => rev.identifier,
|
||||
:scmid => rev.scmid,
|
||||
:committer => rev.author,
|
||||
:committed_on => rev.time,
|
||||
:comments => rev.message,
|
||||
:parents => parents
|
||||
)
|
||||
unless changeset.new_record?
|
||||
rev.paths.each { |change| changeset.create_change(change) }
|
||||
end
|
||||
changeset
|
||||
end
|
||||
private :save_revision
|
||||
|
||||
def heads_from_branches_hash
|
||||
h1 = extra_info || {}
|
||||
h = h1.dup
|
||||
h["branches"] ||= {}
|
||||
h['branches'].map{|br, hs| hs['last_scmid']}
|
||||
end
|
||||
|
||||
def latest_changesets(path,rev,limit=10)
|
||||
revisions = scm.revisions(path, nil, rev, :limit => limit, :all => false)
|
||||
return [] if revisions.nil? || revisions.empty?
|
||||
|
||||
changesets.find(
|
||||
:all,
|
||||
:conditions => [
|
||||
"scmid IN (?)",
|
||||
revisions.map!{|c| c.scmid}
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
def clear_extra_info_of_changesets
|
||||
return if extra_info.nil?
|
||||
v = extra_info["extra_report_last_commit"]
|
||||
write_attribute(:extra_info, nil)
|
||||
h = {}
|
||||
h["extra_report_last_commit"] = v
|
||||
merge_extra_info(h)
|
||||
self.save
|
||||
end
|
||||
private :clear_extra_info_of_changesets
|
||||
end
|
|
@ -77,6 +77,27 @@ class Role < ActiveRecord::Base
|
|||
self.givable[3..5]
|
||||
end
|
||||
|
||||
GUEST = 10
|
||||
REPORTER = 20
|
||||
DEVELOPER = 30
|
||||
MASTER = 40
|
||||
OWNER = 50
|
||||
def to_gitlab_role
|
||||
case self.position
|
||||
when 1,2
|
||||
GUEST
|
||||
when 5
|
||||
REPORTER
|
||||
when 4
|
||||
DEVELOPER
|
||||
when 3
|
||||
MASTER
|
||||
else
|
||||
GUEST
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Copies attributes from another role, arg can be an id or a Role
|
||||
def copy_from(arg, options={})
|
||||
return unless arg.present?
|
||||
|
|
|
@ -93,6 +93,7 @@ class User < Principal
|
|||
has_many :changesets, :dependent => :nullify
|
||||
has_one :preference, :dependent => :destroy, :class_name => 'UserPreference'
|
||||
has_one :rss_token, :class_name => 'Token', :conditions => "action='feeds'"
|
||||
has_one :blog, :class_name => 'Blog', :foreign_key => "author_id"
|
||||
has_one :api_token, :class_name => 'Token', :conditions => "action='api'"
|
||||
belongs_to :auth_source
|
||||
belongs_to :ucourse, :class_name => 'Course', :foreign_key => :id #huang
|
||||
|
@ -208,7 +209,7 @@ class User < Principal
|
|||
validates_inclusion_of :mail_notification, :in => MAIL_NOTIFICATION_OPTIONS.collect(&:first), :allow_blank => true
|
||||
validate :validate_password_length
|
||||
# validates_email_realness_of :mail
|
||||
before_create :set_mail_notification
|
||||
before_create :set_mail_notification, :sync_gitlab_user
|
||||
before_save :update_hashed_password
|
||||
before_destroy :remove_references_before_destroy
|
||||
# added by fq
|
||||
|
@ -255,6 +256,18 @@ class User < Principal
|
|||
# count = self.journals_for_messages(:conditions => ["status=? and is_readed = ? " ,1, 0]).count
|
||||
end
|
||||
|
||||
def blog
|
||||
@blog = Blog.where("author_id = #{self.id}").all[0]
|
||||
if @blog.nil?
|
||||
#如果某个user的blog不存在,那么就创建一条,并且跳转
|
||||
@blog = Blog.create(:name=>(User.find(self.id).realname),
|
||||
:description=>'',
|
||||
:author_id=>self.id)
|
||||
@blog.save
|
||||
end
|
||||
@blog
|
||||
end
|
||||
|
||||
# 查询指派给我的缺陷记录
|
||||
def count_new_issue_assign_to
|
||||
self.issue_assigns
|
||||
|
@ -345,7 +358,7 @@ class User < Principal
|
|||
name
|
||||
end
|
||||
## end
|
||||
|
||||
|
||||
#added by nie
|
||||
def count_new_journal_reply
|
||||
count = self.journal_reply.count
|
||||
|
@ -1066,6 +1079,17 @@ class User < Principal
|
|||
end
|
||||
|
||||
|
||||
private
|
||||
def sync_gitlab_user
|
||||
user = self
|
||||
g = Gitlab.client
|
||||
u = g.get("/users?search=#{user.mail}").first
|
||||
unless u
|
||||
u = g.create_user(user.mail, user.password, name: user.show_name, username: user.login, confirm: "true")
|
||||
self.gid = u.id
|
||||
puts "create user #{user.login}"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -326,26 +326,26 @@ class CoursesService
|
|||
@state = 1
|
||||
end
|
||||
else
|
||||
if params[:course_password] == course.password
|
||||
if params[:role] == "10"
|
||||
members = []
|
||||
members << Member.new(:role_ids => [10], :user_id => current_user.id)
|
||||
course.members << members
|
||||
StudentsForCourse.create(:student_id => current_user.id, :course_id => params[:object_id])
|
||||
@state = 0
|
||||
if params[:course_password] == course.password
|
||||
if params[:role] == "10"
|
||||
members = []
|
||||
members << Member.new(:role_ids => [10], :user_id => current_user.id)
|
||||
course.members << members
|
||||
StudentsForCourse.create(:student_id => current_user.id, :course_id => params[:object_id])
|
||||
@state = 0
|
||||
else
|
||||
#如果已经发送过消息了,那么就要给个提示
|
||||
if CourseMessage.where("course_message_type = 'JoinCourseRequest' and user_id = #{course.tea_id} and content = #{params[:role]} and course_message_id = #{User.current.id} and course_id = #{course.id} and status = 0").count != 0
|
||||
@state = 7
|
||||
else
|
||||
Mailer.run.join_course_request(course, User.current, params[:role])
|
||||
CourseMessage.create(:user_id => course.tea_id, :course_id => course.id, :viewed => false,:content=> params[:role],:course_message_id=>User.current.id,:course_message_type=>'JoinCourseRequest',:status=>0)
|
||||
@state = 6
|
||||
end
|
||||
end
|
||||
else
|
||||
#如果已经发送过消息了,那么就要给个提示
|
||||
if CourseMessage.where("course_message_type = 'JoinCourseRequest' and user_id = #{course.tea_id} and content = #{params[:role]} and course_message_id = #{User.current.id} and course_id = #{course.id} and status = 0").count != 0
|
||||
@state = 7
|
||||
else
|
||||
Mailer.run.join_course_request(course, User.current, params[:role])
|
||||
CourseMessage.create(:user_id => course.tea_id, :course_id => course.id, :viewed => false,:content=> params[:role],:course_message_id=>User.current.id,:course_message_type=>'JoinCourseRequest',:status=>0)
|
||||
@state = 6
|
||||
end
|
||||
@state = 1
|
||||
end
|
||||
else
|
||||
@state = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
<div class="mt10 fl" style="width: 600px">
|
||||
<% for attachment in attachments %>
|
||||
<!--<p style="width: 100%;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;">-->
|
||||
<!--<div style="max-width:55%;white-space: nowrap; overflow: hidden; text-overflow: ellipsis;float: left;">-->
|
||||
<!--<span title="<%#= attachment.filename%>" id = "attachment_">-->
|
||||
<% if options[:length] %>
|
||||
<span class="pic_files fl "></span>
|
||||
<%= link_to_short_attachment attachment, :class => 'fl FilesName02', :download => true,:length => options[:length] -%>
|
||||
<a class="fl FilesName02"> (<%= number_to_human_size attachment.filesize , :precision => 0 %>)</a>
|
||||
<% if options[:deletable] %>
|
||||
<%#= link_to image_tag('delete.png'), attachment_path(attachment),
|
||||
:data => {:confirm => l(:text_are_you_sure)},
|
||||
:method => :delete,
|
||||
:class => 'delete',
|
||||
#:remote => true,
|
||||
#:id => "attachments_" + attachment.id.to_s,
|
||||
:title => l(:button_delete) %>
|
||||
<span class="pic_del fl "> <a href="<%=attachment_path(attachment) %>" onclick="confirm(<%=l(:text_are_you_sure) %>)" data-method="delete"> </a></span>
|
||||
<% end %>
|
||||
<div class="cl"></div>
|
||||
<% else %>
|
||||
<span class="pic_files fl "></span>
|
||||
<%= link_to_short_attachment attachment, :class => 'fl FilesName02', :download => true, :length => 45 -%>
|
||||
<a href="javascript:void(0);" class="fl FilesName02"> (<%= number_to_human_size attachment.filesize , :precision => 0 %>)</a>
|
||||
<% if options[:deletable] %>
|
||||
<a href="<%=attachment_path(attachment) %>" onclick="confirm(<%=l(:text_are_you_sure) %>)" data-method="delete"> <span class="pic_del fl "></span> </a>
|
||||
<% end %>
|
||||
<div class="cl"></div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% if defined?(thumbnails) && thumbnails %>
|
||||
<% images = attachments.select(&:thumbnailable?) %>
|
||||
<% if images.any? %>
|
||||
<div class="pro_pic mb10" width="100" height="73">
|
||||
<% images.each do |attachment| %>
|
||||
<div><%= thumbnail_tag(attachment) %></div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
|
@ -0,0 +1,78 @@
|
|||
<style type="text/css">
|
||||
input.is_public,input.is_public_checkbox{height:12px;}
|
||||
input.is_public_checkbox{margin-left:4px;margin-right:4px;}
|
||||
</style>
|
||||
<div class="fl">
|
||||
<span id="attachments_fields" xmlns="http://www.w3.org/1999/html">
|
||||
<% if defined?(container) && container && container.saved_attachments %>
|
||||
<% container.attachments.each_with_index do |attachment, i| %>
|
||||
<span id="attachments_p<%= i %>" class="attachment">
|
||||
<%= text_field_tag("attachments[p#{i}][filename]", attachment.filename, :class => 'filename readonly', :readonly => 'readonly') %><%= text_field_tag("attachments[p#{i}][description]", attachment.description, :maxlength => 254, :placeholder => l(:label_optional_description), :class => 'description', :style => "display: inline-block;") %><span class="ispublic-label"><%= l(:field_is_public) %>:</span>
|
||||
<%= check_box_tag("attachments[p#{i}][is_public_checkbox]", attachment.is_public, attachment.is_public == 1 ? true : false, :class => 'is_public') %>
|
||||
<%= if attachment.id.nil?
|
||||
#待补充代码
|
||||
else
|
||||
link_to(' '.html_safe, attachment_path(attachment, :attachment_id => "p#{i}", :format => 'js'), :method => 'delete', :remote => true, :class => 'remove-upload')
|
||||
end
|
||||
%>
|
||||
<%#= render :partial => 'tags/tag', :locals => {:obj => attachment, :object_flag => "6"} %>
|
||||
|
||||
<%= hidden_field_tag "attachments[p#{i}][token]", "#{attachment.token}" %>
|
||||
</span>
|
||||
<div class="cl"></div>
|
||||
<% end %>
|
||||
<% container.saved_attachments.each_with_index do |attachment, i| %>
|
||||
<span id="attachments_p<%= i %>" class="attachment">
|
||||
<%= text_field_tag("attachments[p#{i}][filename]", attachment.filename, :class => 'filename readonly', :readonly => 'readonly') %>
|
||||
<%= text_field_tag("attachments[p#{i}][description]", attachment.description, :maxlength => 254, :placeholder => l(:label_optional_description), :class => 'description', :style => "display: inline-block;") %>
|
||||
<span class="ispublic-label"><%= l(:field_is_public) %>:</span>
|
||||
<%= check_box_tag("attachments[p#{i}][is_public_checkbox]", attachment.is_public, attachment.is_public == 1 ? true : false, :class => 'is_public') %>
|
||||
<%= if attachment.id.nil?
|
||||
#待补充代码
|
||||
else
|
||||
link_to(' '.html_safe, attachment_path(attachment, :attachment_id => "p#{i}", :format => 'js'), :method => 'delete', :remote => true, :class => 'remove-upload')
|
||||
end
|
||||
%>
|
||||
<%#= render :partial => 'tags/tag', :locals => {:obj => attachment, :object_flag => "6"} %>
|
||||
|
||||
<%= hidden_field_tag "attachments[p#{i}][token]", "#{attachment.token}" %>
|
||||
</span>
|
||||
<div class="cl"></div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</span>
|
||||
<div class="cl"></div>
|
||||
<span class="add_attachment" style="font-weight:normal;">
|
||||
<%#= button_tag "浏览", :type=>"button", :onclick=>"CompatibleSend();" %>
|
||||
<!--%= link_to image_tag(),"javascript:void(0)", :onclick => "_file.click()"%-->
|
||||
<%#= button_tag "文件浏览", :type=>"button", :onclick=>"$('#_file').click();",:onmouseover => 'this.focus()',:class => 'sub_btn' %>
|
||||
<a href="javascript:void(0);" onclick="_file.click();" class="AnnexBtn fl mr15">上传附件</a>
|
||||
<%= file_field_tag 'attachments[dummy][file]',
|
||||
:id => '_file',
|
||||
:class => 'file_selector',
|
||||
:multiple => true,
|
||||
:onchange => 'addInputFiles(this);',
|
||||
:style => ie8? ? '' : 'display:none',
|
||||
:data => {
|
||||
:max_file_size => Setting.attachment_max_size.to_i.kilobytes,
|
||||
:max_file_size_message => l(:error_attachment_too_big, :max_size => number_to_human_size(Setting.attachment_max_size.to_i.kilobytes)),
|
||||
:max_concurrent_uploads => Redmine::Configuration['max_concurrent_ajax_uploads'].to_i,
|
||||
:upload_path => uploads_path(:format => 'js', :project => container),
|
||||
:description_placeholder => l(:label_optional_description),
|
||||
:field_is_public => l(:field_is_public),
|
||||
:are_you_sure => l(:text_are_you_sure),
|
||||
:file_count => l(:label_file_count),
|
||||
:delete_all_files => l(:text_are_you_sure_all)
|
||||
} %>
|
||||
<span id="upload_file_count">
|
||||
<%= l(:label_no_file_uploaded) %>
|
||||
</span>
|
||||
(<%= l(:label_max_size) %>:
|
||||
<%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>)
|
||||
</span>
|
||||
|
||||
<% content_for :header_tags do %>
|
||||
<%= javascript_include_tag 'attachments' %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
<%= javascript_include_tag "/assets/kindeditor/kindeditor",'/assets/kindeditor/pasteimg' ,'blog' %>
|
||||
<div class="resources mt10">
|
||||
<div id="new_course_topic">
|
||||
<div class="homepagePostBrief c_grey">
|
||||
<div>
|
||||
<input type="text" value="<%= article.title%>" name="blog_comment[title]" id="message_subject" class="InputBox w713" style="width: 720px !important;" maxlength="255" onkeyup="regexTopicSubject();" placeholder="发布文章,请先输入文章标题" " />
|
||||
<p id="subjectmsg"></p>
|
||||
</div>
|
||||
<div id="topic_editor" style="display: block;">
|
||||
<%if User.current.id == user.id%>
|
||||
<div class="mt10">
|
||||
<%= f.check_box :sticky%>
|
||||
<%= label_tag 'message_sticky', l(:label_board_sticky) %>
|
||||
<%= f.check_box :locked%>
|
||||
<%= label_tag 'message_locked', l(:label_board_locked) %>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="mt10">
|
||||
<div id="message_quote" class="wiki" style="width: 92%;word-break: break-all;word-wrap: break-word;margin-left: 40px;"></div>
|
||||
<%= text_area :quote,:quote,:style => 'display:none' %>
|
||||
<%= hidden_field_tag :asset_id,params[:asset_id],:required => false,:style => 'display:none' %>
|
||||
|
||||
<%= f.kindeditor :content,:editor_id => 'message_content_editor',
|
||||
:owner_id => article.nil? ? 0: article.id,
|
||||
:owner_type => OwnerTypeHelper::BLOGCOMMENT,
|
||||
:width => '100%',
|
||||
:height => 300,
|
||||
:minHeight=>300,
|
||||
:class => 'talk_text fl',
|
||||
:input_html => { :id => 'message_content',
|
||||
:class => 'talk_text fl',
|
||||
:maxlength => 5000 }%>
|
||||
<div class="cl"></div>
|
||||
<p id="message_content_span"></p>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
<div class="mt10">
|
||||
<div class="fl" id="topic_attachments">
|
||||
<%= render :partial => 'blog_comments/blog_attachments', :locals => {:container => article} %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
<div class="mt5">
|
||||
<a href="javascript:void(0);" class="BlueCirBtnMini fr" onclick="submit_article();">确定</a>
|
||||
<span class="fr mr10 mt3">或</span>
|
||||
<a href="<%= user_blog_blog_comment_path(:user_id=>article.author.id,:blog_id=>article.blog_id,:id=>article.id)%>" class="fr mr10 mt3" >取消</a>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,62 @@
|
|||
<%= javascript_include_tag "/assets/kindeditor/kindeditor",'/assets/kindeditor/pasteimg' ,'blog' %>
|
||||
<div class="resources mt10">
|
||||
<div id="new_course_topic">
|
||||
<div class="homepagePostBrief c_grey">
|
||||
<div>
|
||||
<input type="text" name="blog_comment[title]" id="message_subject" class="InputBox w713" style="width: 720px !important;" maxlength="255" onfocus="$('#topic_editor').show()" onkeyup="regexTopicSubject();" placeholder="发布文章,请先输入文章标题" " >
|
||||
<p id="subjectmsg"></p>
|
||||
</div>
|
||||
<div id="topic_editor" style="display: none;">
|
||||
<%if User.current.id == user.id%>
|
||||
<div class="mt10">
|
||||
<%= f.check_box :sticky%>
|
||||
<%= label_tag 'message_sticky', l(:label_board_sticky) %>
|
||||
<%= f.check_box :locked%>
|
||||
<%= label_tag 'message_locked', l(:label_board_locked) %>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="mt10">
|
||||
<div id="message_quote" class="wiki" style="width: 92%;word-break: break-all;word-wrap: break-word;margin-left: 40px;"></div>
|
||||
<%= text_area :quote,:quote,:style => 'display:none' %>
|
||||
<%= hidden_field_tag :asset_id,params[:asset_id],:required => false,:style => 'display:none' %>
|
||||
|
||||
<%= f.kindeditor :content, :editor_id => 'message_content_editor',
|
||||
:owner_id => article.nil? ? 0: article.id,
|
||||
:owner_type => OwnerTypeHelper::BLOGCOMMENT,
|
||||
:width => '100%',
|
||||
:height => 300,
|
||||
:minHeight=>300,
|
||||
:class => 'talk_text fl',
|
||||
:input_html => { :id => 'message_content',
|
||||
:class => 'talk_text fl',
|
||||
:maxlength => 5000 }%>
|
||||
<div class="cl"></div>
|
||||
<p id="message_content_span"></p>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
<div class="mt10">
|
||||
<div class="fl" id="topic_attachments">
|
||||
<%= render :partial => 'blog_comments/blog_attachments', :locals => {:container => article} %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
<div class="mt5">
|
||||
<a href="javascript:void(0);" class="BlueCirBtnMini fr" onclick="submit_article();">确定</a>
|
||||
<span class="fr mr10 mt3">或</span>
|
||||
<a href="javascript:void(0);" class="fr mr10 mt3" onclick="reset_article();">取消</a>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
</div>
|
||||
<%#= render :partial => 'course_new_topic', :locals => {:f => f, :topic => @message} %>
|
||||
<!--<li>
|
||||
<div class="ml55 fl" nhname="toolbar_container"></div>
|
||||
<a href="javascript:void(0);" nhname="cancelbtn" class="grey_btn fr ml10"><%#= l(:button_cancel) %></a>
|
||||
<a href="javascript:void(0);" nhname="submitbtn" class="blue_btn fr " style="margin-left: 55px">
|
||||
<%#= l(:button_submit)%>
|
||||
</a>
|
||||
<div class="cl"></div>
|
||||
</li>-->
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,35 @@
|
|||
<%= javascript_include_tag "/assets/kindeditor/kindeditor",'/assets/kindeditor/pasteimg' %>
|
||||
<li>
|
||||
<div style="display: none ;" class="fl"><label><span class="c_red">*</span> <%= l(:field_subject) %> :</label></div>
|
||||
<div style="display: none;"><%= f.text_field :title, { size: 60, id: "message_subject",:class=>"talk_input w585 fl" }.merge({ hidden: "hidden"}) %></div>
|
||||
|
||||
<div class="cl"></div>
|
||||
</li>
|
||||
<li class="ml60 mb5">
|
||||
<div class="cl"></div>
|
||||
</li>
|
||||
<li>
|
||||
<div id="message_quote" class="wiki" style="width: 92%;word-break: break-all;word-wrap: break-word;margin-left: 40px;"></div>
|
||||
<!--<label class="fl" >
|
||||
<span class="c_red">*</span>
|
||||
<%#= l(:field_description) %> :
|
||||
</label>-->
|
||||
<%= text_area :quote,:quote,:style => 'display:none' %>
|
||||
<%= hidden_field_tag :asset_id,params[:asset_id],:required => false,:style => 'display:none' %>
|
||||
<input type="hidden" name="blog_comment[title]" value="RE:<%= article.title%>">
|
||||
<input type="hidden" name="blog_comment[sticky]" value="0">
|
||||
<input type="hidden" name="blog_comment[locked]" value="0">
|
||||
<%= f.kindeditor :content, :editor_id => 'message_content_editor',
|
||||
:width => '99%',
|
||||
:height => 100,
|
||||
:minHeight=>100,
|
||||
:input_html => { :id => 'message_content',
|
||||
:class => 'talk_text fl',
|
||||
:maxlength => 5000 }%>
|
||||
<div class="cl"></div>
|
||||
<p id="message_content_span"></p>
|
||||
</li>
|
||||
<div class="cl"></div>
|
||||
<li >
|
||||
<div class="cl"></div>
|
||||
</li>
|
|
@ -0,0 +1,31 @@
|
|||
<style type="text/css">
|
||||
/*回复框*/
|
||||
.ReplyToMessageInputContainer .ke-toolbar{display:none;width:400px;border:none;background:none;padding:0px 0px;}
|
||||
.ReplyToMessageInputContainer .ke-toolbar-icon{line-height:26px;font-size:14px;padding-left:26px;}
|
||||
.ReplyToMessageInputContainer .ke-toolbar-icon-url{background-image:url( /images/public_icon.png )}
|
||||
.ReplyToMessageInputContainer .ke-outline{padding:0px 0px;line-height:26px;font-size:14px;}
|
||||
.ReplyToMessageInputContainer .ke-icon-emoticons{background-position:0px -671px;width:50px;height:26px;}
|
||||
.ReplyToMessageInputContainer .ke-icon-emoticons:hover{background-position:-79px -671px;width:50px;height:26px;}
|
||||
.ReplyToMessageInputContainer .ke-outline{border:none;}
|
||||
.ReplyToMessageInputContainer .ke-inline-block{display: none;}
|
||||
.ReplyToMessageInputContainer .ke-container{float:left;}
|
||||
</style>
|
||||
|
||||
<div class="ReplyToMessageContainer borderBottomNone"id="reply_to_message_<%= reply.id%>">
|
||||
<div class="homepagePostReplyPortrait mr15 imageFuzzy" id="reply_image_<%= reply.id%>"><%= link_to image_tag(url_to_avatar(User.current), :width => "33", :height => "33"), user_path(User.current), :alt => "用户头像" %></div>
|
||||
<div class="ReplyToMessageInputContainer mb10">
|
||||
<div nhname='new_message_<%= reply.id%>'>
|
||||
<%= form_for @blog_comment, :as => :reply, :url => {:controller => 'blog_comments',:action => 'reply', :id => @blogComment.id}, :html => {:multipart => true, :id => 'new_form'} do |f| %>
|
||||
<input type="hidden" name="quote[quote]" id="quote_quote">
|
||||
<input type="hidden" name="blog_comment[title]" id="reply_subject">
|
||||
<textarea placeholder="有问题或有建议,请直接给我留言吧!" style="display: none" nhname='new_message_textarea_<%= reply.id%>' name="blog_comment[content]"></textarea>
|
||||
<div nhname='toolbar_container_<%= reply.id%>' style="float:left; margin-left: 5px; padding-top:3px;"></div>
|
||||
<a id="new_message_submit_btn_<%= reply.id%>" href="javascript:void(0)" class="blue_n_btn fr" style="display:none;margin-top:6px;">发送</a>
|
||||
<div class="cl"></div>
|
||||
<p nhname='contentmsg_<%= reply.id%>'></p>
|
||||
<% end%>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
|
@ -0,0 +1,6 @@
|
|||
<% if User.current.logged? && User.current.id == @user.id %>
|
||||
<%= form_for @article, :url =>{:controller=>'blog_comments',:action => 'update',:user_id=>@user.id , :blog_id => @article.id},:method=>'PUT',
|
||||
:html => {:nhname=>'form',:multipart => true, :id => 'message-form'} do |f| %>
|
||||
<%= render :partial => 'blog_comments/edit', :locals => {:f => f, :article => @article, :edit_mode => true, :user => @user} %>
|
||||
<% end %>
|
||||
<% end %>
|
|
@ -0,0 +1,10 @@
|
|||
if($("#reply_message_<%= @blogComment.id%>").length > 0) {
|
||||
$("#reply_message_<%= @blogComment.id%>").replaceWith("<%= escape_javascript(render :partial => 'simple_ke_reply_form', :locals => {:reply => @blogComment,:temp =>@temp,:subject =>@subject}) %>");
|
||||
$(function(){
|
||||
$('#reply_subject').val("<%= raw escape_javascript(@subject) %>");
|
||||
$('#quote_quote').val("<%= raw escape_javascript(@temp.content.html_safe) %>");
|
||||
init_activity_KindEditor_data(<%= @blogComment.id%>,null,"85%");
|
||||
});
|
||||
}else if($("#reply_to_message_<%= @blogComment.id%>").length >0) {
|
||||
$("#reply_to_message_<%= @blogComment.id%>").replaceWith("<p id='reply_message_<%= @blogComment.id%>'></p>");
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
$("#user_activity_<%= @user_activity_id%>").replaceWith("<%= escape_javascript(render :partial => 'blogs/article', :locals => {:activity => @article,:user_activity_id =>@user_activity_id,:first_user_activity =>@first_user_activity,:page => @page}) %>");
|
||||
init_activity_KindEditor_data(<%= @user_activity_id%>,"","87%");
|
|
@ -0,0 +1,175 @@
|
|||
<%= javascript_include_tag "/assets/kindeditor/kindeditor",'/assets/kindeditor/pasteimg',"init_activity_KindEditor",'blog' %>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function(){
|
||||
$("#RSide").removeAttr("id");
|
||||
$("#Container").css("width","1000px");
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
function expand_reply(container,btnid){
|
||||
var target = $(container).children();
|
||||
var btn = $(btnid);
|
||||
if(btn.data('init')=='0'){
|
||||
btn.data('init',1);
|
||||
btn.html('收起回复');
|
||||
target.show();
|
||||
}else{
|
||||
btn.data('init',0);
|
||||
btn.html('展开更多');
|
||||
target.hide();
|
||||
target.eq(0).show();
|
||||
target.eq(1).show();
|
||||
target.eq(2).show();
|
||||
}
|
||||
}
|
||||
$(function() {
|
||||
init_activity_KindEditor_data(<%= @article.id%>,null,"85%");
|
||||
showNormalImage('message_description_<%= @article.id %>');
|
||||
});
|
||||
</script>
|
||||
<div class="postRightContainer ml10" onmouseover="$('#message_setting_<%= @article.id%>').show();" onmouseout="$('#message_setting_<%= @article.id%>').hide();">
|
||||
<div class="postThemeContainer">
|
||||
<div class="postDetailPortrait">
|
||||
<%= link_to image_tag(url_to_avatar(@article.author),:width=>50,:height => 50,:alt=>'图像' ),user_path(@article.author) %>
|
||||
</div>
|
||||
<div class="postThemeWrap">
|
||||
<% if @article.author.id == User.current.id%>
|
||||
<div class="homepagePostSetting" id="message_setting_<%= @article.id%>" style="display: none">
|
||||
<ul>
|
||||
<li class="homepagePostSettingIcon">
|
||||
<ul class="homepagePostSettiongText">
|
||||
<li>
|
||||
<%= link_to(
|
||||
l(:button_edit),
|
||||
{:action => 'edit', :id => @article.id},
|
||||
:class => 'postOptionLink'
|
||||
) if User.current && User.current.id == @article.author.id %>
|
||||
</li>
|
||||
<li>
|
||||
<%= link_to(
|
||||
l(:button_delete),
|
||||
{:action => 'destroy', :id => @article.id},
|
||||
:method => :delete,
|
||||
:data => {:confirm => l(:text_are_you_sure)},
|
||||
:class => 'postOptionLink'
|
||||
) if User.current && User.current.id == @article.author.id %>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<%end%>
|
||||
<div class="postDetailTitle fl">
|
||||
<a href="javascript:void(0);" class="f14 linkGrey4 fb" style="overflow:hidden;">主题: <%= @article.title%></a>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
|
||||
<div class="postDetailCreater">
|
||||
<% if @article.try(:author).try(:realname) == ' ' %>
|
||||
<%= link_to @article.try(:author), user_path(@article.author,:host=>Setting.host_user), :class => "linkBlue2", :target=> "_blank" %>
|
||||
<% else %>
|
||||
<%= link_to @article.try(:author).try(:realname), user_path(@article.author,:host=>Setting.host_user), :class => "linkBlue2", :target=> "_blank" %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="postDetailDate mb5"><%= format_time( @article.created_on)%></div>
|
||||
<div class="cl"></div>
|
||||
<div class="memo-content upload_img break_word" id="message_description_<%= @article.id %>" style="word-break: break-all; word-wrap:break-word;margin-bottom: 0px !important;" >
|
||||
<%= @article.content.html_safe%>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
<div class=" fl" style="width: 600px">
|
||||
<%#= link_to_attachments_course @topic, :author => false %>
|
||||
<% if @article.attachments.any?%>
|
||||
<% options = {:author => true, :deletable => false} %>
|
||||
<%= render :partial => 'blog_comments/attachments_links', :locals => {:attachments => @article.attachments, :options => options, :is_float => true} %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
<% count=0 %>
|
||||
<% if @article.parent %>
|
||||
<% count=@article.parent.children.count%>
|
||||
<% else %>
|
||||
<% count=@article.children.count%>
|
||||
<% end %>
|
||||
<div class="homepagePostReply">
|
||||
<% unless count == 0 %>
|
||||
<div class="homepagePostReplyBanner">
|
||||
<div class="homepagePostReplyBannerCount">回复(<%=count %>)</div>
|
||||
<div class="homepagePostReplyBannerTime"></div>
|
||||
<!-- <div class="homepagePostReplyBannerMore">
|
||||
<%# if @reply_count > 2%>
|
||||
<a href="javascript:void(0);" class="replyGrey" id="reply_btn_<%#= @topic.id%>" onclick="expand_reply('#reply_div_<%#= @topic.id %>','#reply_btn_<%#= @topic.id%>')" data-count="<%#= @reply_count %>" data-init="0" >点击展开更多回复</a>
|
||||
<%# end %>
|
||||
</div>-->
|
||||
</div>
|
||||
<div class="" id="reply_div_<%= @article.id %>">
|
||||
<%@article.children.reorder('created_on desc').each_with_index do |reply,i| %>
|
||||
<script type="text/javascript">
|
||||
$(function(){
|
||||
showNormalImage('reply_message_description_<%= reply.id %>');
|
||||
});
|
||||
</script>
|
||||
<div class="homepagePostReplyContainer" onmouseover="$('#reply_edit_menu_<%= reply.id%>').show();" onmouseout="$('#reply_edit_menu_<%= reply.id%>').hide();">
|
||||
<div class="homepagePostReplyPortrait">
|
||||
<%= link_to image_tag(url_to_avatar(reply.author), :width => 33,:height => 33), user_path(reply.author) %>
|
||||
</div>
|
||||
<div class="homepagePostReplyDes">
|
||||
<div class="homepagePostReplyPublisher">
|
||||
<% if reply.try(:author).try(:realname) == ' ' %>
|
||||
<%= link_to reply.try(:author), user_path(reply.author_id,:host=>Setting.host_user), :class => "newsBlue mr10 f14" %>
|
||||
<% else %>
|
||||
<%= link_to reply.try(:author).try(:realname), user_path(reply.author_id,:host=>Setting.host_user), :class => "newsBlue mr10 f14" %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="homepagePostReplyContent upload_img break_word" id="reply_message_description_<%= reply.id %>">
|
||||
<%= reply.content.html_safe%>
|
||||
</div>
|
||||
<div style="margin-top: -7px; margin-bottom: 5px">
|
||||
<%= format_time(reply.created_on) %>
|
||||
<div class="fr" id="reply_edit_menu_<%= reply.id%>" style="display: none">
|
||||
<%= link_to(
|
||||
l(:button_reply),
|
||||
{:controller => 'blog_comments',:action => 'quote',:user_id=>reply.author_id,:blog_id=>reply.blog_id, :id => reply.id},
|
||||
:remote => true,
|
||||
:method => 'get',
|
||||
:class => 'fr newsBlue',
|
||||
:title => l(:button_reply)) if !@article.locked? && User.current.logged? %>
|
||||
<%= link_to(
|
||||
l(:button_delete),
|
||||
{:controller => 'blog_comments',:action => 'destroy', :id => reply.id},
|
||||
:method => :delete,
|
||||
:class => 'fr newsGrey mr10',
|
||||
:data => {:confirm => l(:text_are_you_sure)},
|
||||
:title => l(:button_delete)
|
||||
) if reply.author.id == User.current.id %>
|
||||
</div>
|
||||
</div>
|
||||
<p id="reply_message_<%= reply.id%>"></p>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% end %>
|
||||
<div class="cl"></div>
|
||||
<% if !@article.locked? && User.current.logged?%>
|
||||
<div class="talkWrapMsg" nhname="about_talk_reply">
|
||||
<em class="talkWrapArrow"></em>
|
||||
<div class="cl"></div>
|
||||
<div class="talkConIpt ml5 mb10" id="reply<%= @article.id %>">
|
||||
<%= form_for :blog_comment, :url => {:action => 'reply',:controller => 'blog_comments',:user_id=>@article.author.id,:blog_id=>@article.blog_id, :id => @article.id}, :html => {:multipart => true, :id => 'message_form'} do |f| %>
|
||||
<%= render :partial => 'blog_comments/reply_form', :locals => {:f => f,:user=>@user,:article=>@article} %>
|
||||
<%= link_to l(:button_cancel), "javascript:void(0)", :onclick => 'canel_message_replay();', :class => " grey_btn fr c_white mt10 mr5" %>
|
||||
<%= link_to l(:button_submit), "javascript:void(0)", :onclick => 'submit_message_replay();', :class => "blue_btn fr c_white mt10", :style => "margin-right: 5px;" %>
|
||||
<% end %>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,145 @@
|
|||
<div class="resources mt10" id="user_activity_<%= user_activity_id%>">
|
||||
<div class="homepagePostBrief">
|
||||
<div class="homepagePostPortrait">
|
||||
<%= link_to image_tag(url_to_avatar(activity.author), :width => "50", :height => "50"), user_path(activity.author_id,:host=>Setting.host_user), :alt => "用户头像" %>
|
||||
</div>
|
||||
<div class="homepagePostDes">
|
||||
<div class="homepagePostTo break_word mt-4">
|
||||
<% if activity.try(:author).try(:realname) == ' ' %>
|
||||
<%= link_to activity.try(:author), user_path(activity.author_id,:host=>Setting.host_user), :class => "newsBlue mr15" %>
|
||||
<% else %>
|
||||
<%= link_to activity.try(:author).try(:realname), user_path(activity.author_id,:host=>Setting.host_user), :class => "newsBlue mr15" %>
|
||||
<% end %>
|
||||
TO
|
||||
<%= link_to activity.blog.name+" | 博客", user_blogs_path(:user_id=>activity.author_id,:host=>Setting.host_user), :class => "newsBlue ml15 mr5"%>
|
||||
</div>
|
||||
<div class="homepagePostTitle hidden m_w530 fl">
|
||||
<% if activity.parent_id.nil? %> <!--+"(帖子标题)"-->
|
||||
<%= link_to activity.title.to_s.html_safe, user_blog_blog_comment_path(:user_id=>activity.author_id, :blog_id=>activity.blog.id,:id=>activity), :class=> "postGrey" %>
|
||||
<% else %>
|
||||
<%= link_to activity.title.subject.to_s.html_safe, user_blog_blog_comment_path(:user_id=>activity.author_id, :blog_id=>activity.blog.id,:id=>activity), :class=> "postGrey"%>
|
||||
<% end %>
|
||||
</div>
|
||||
<% if activity.sticky == 1%>
|
||||
<span class="sticky_btn_cir ml10">置顶</span>
|
||||
<% end%>
|
||||
<% if activity.locked%>
|
||||
<span class="locked_btn_cir ml10 fl" title="已锁定"> </span>
|
||||
<% end%>
|
||||
<div class="cl"></div>
|
||||
<div class="homepagePostDate">
|
||||
发帖时间:<%= format_time(activity.created_on) %>
|
||||
</div>
|
||||
|
||||
<div class="homepagePostIntro break_word upload_img list_style" id="activity_description_<%= user_activity_id%>">
|
||||
<% if activity.parent_id.nil? %>
|
||||
<%= activity.content.to_s.html_safe%>
|
||||
<% else %>
|
||||
<%= activity.parent.content.to_s.html_safe%>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
<div class=" fl" style="width: 600px">
|
||||
<% if activity.attachments.any?%>
|
||||
<% options = {:author => true, :deletable => false } %>
|
||||
<%= render :partial => 'blog_comments/attachments_links', :locals => {:attachments => activity.attachments, :options => options, :is_float => true} %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="homepagePostSetting" id="act-<%= user_activity_id %>" style="visibility: hidden">
|
||||
<ul>
|
||||
<li class="homepagePostSettingIcon">
|
||||
<ul class="homepagePostSettiongText">
|
||||
<li><a href="javascript:void(0);" class="postOptionLink">编辑</a></li>
|
||||
<li><a href="javascript:void(0);" class="postOptionLink">复制</a></li>
|
||||
<li><a href="javascript:void(0);" class="postOptionLink">删除</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
<% count=0 %>
|
||||
<% if activity.parent %>
|
||||
<% count=activity.parent.children.count%>
|
||||
<% else %>
|
||||
<% count=activity.children.count%>
|
||||
<% end %>
|
||||
<div class="homepagePostReply">
|
||||
<div class="topBorder" style="display: <%= count<=0 && !activity.locked ? '': 'none' %>"></div>
|
||||
<div class="homepagePostReplyBanner" style="display: <%= count>0 ? '': 'none' %>">
|
||||
<div class="homepagePostReplyBannerCount" onclick="expand_reply_input('#reply_input_<%= user_activity_id %>');">回复(
|
||||
<%= count %>
|
||||
)</div>
|
||||
<div class="homepagePostReplyBannerTime"><%#=format_date(activity.updated_on)%></div>
|
||||
<%if count > 3 %>
|
||||
<div class="homepagePostReplyBannerMore">
|
||||
<a id="reply_btn_<%=user_activity_id%>" onclick="expand_reply('#reply_div_<%= user_activity_id %> li','#reply_btn_<%=user_activity_id%>')" data-count="<%= count %>" data-init="0" class=" replyGrey" href="javascript:void(0)" value="show_help" >
|
||||
展开更多
|
||||
</a>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% activity= activity.parent ? activity.parent : activity%>
|
||||
<% replies_all_i = 0 %>
|
||||
<% if count > 0 %>
|
||||
<div class="" id="reply_div_<%= user_activity_id %>">
|
||||
<ul>
|
||||
<% activity.children.reorder("created_on desc").each do |reply|%>
|
||||
<script type="text/javascript">
|
||||
$(function(){
|
||||
showNormalImage('reply_content_<%= reply.id %>');
|
||||
});
|
||||
</script>
|
||||
<% replies_all_i=replies_all_i+1 %>
|
||||
<li class="homepagePostReplyContainer" nhname="reply_rec" style="display:<%= replies_all_i>3 ? 'none' : '' %>">
|
||||
<div class="homepagePostReplyPortrait">
|
||||
<%= link_to image_tag(url_to_avatar(reply.author), :width => "33", :height => "33"), user_path(reply.author_id,:host=>Setting.host_user), :alt => "用户头像" %>
|
||||
</div>
|
||||
<div class="homepagePostReplyDes">
|
||||
<div class="homepagePostReplyPublisher mt-4">
|
||||
<% if reply.try(:author).try(:realname) == ' ' %>
|
||||
<%= link_to reply.try(:author), user_path(reply.author_id,:host=>Setting.host_user), :class => "newsBlue mr10 f14" %>
|
||||
<% else %>
|
||||
<%= link_to reply.try(:author).try(:realname), user_path(reply.author_id,:host=>Setting.host_user), :class => "newsBlue mr10 f14" %>
|
||||
<% end %>
|
||||
<%= format_time(reply.created_on) %>
|
||||
</div>
|
||||
<div class="homepagePostReplyContent break_word list_style upload_img" id="reply_content_<%= reply.id %>">
|
||||
<%= reply.content.html_safe %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if !activity.locked? %>
|
||||
<div class="homepagePostReplyContainer borderBottomNone minHeight48">
|
||||
<div class="homepagePostReplyPortrait mr15 imageFuzzy" id="reply_image_<%= user_activity_id%>"><%= link_to image_tag(url_to_avatar(User.current), :width => "33", :height => "33"), user_path(activity.author_id), :alt => "用户头像" %></div>
|
||||
<div class="homepagePostReplyInputContainer mb10">
|
||||
<div nhname='new_message_<%= user_activity_id%>' style="display:none;">
|
||||
<%= form_for('new_form',:url => {:controller=>'blog_comments',:action => 'reply', :id => activity.id, :blog_id => activity.blog.id, :user_id => activity.author_id},:method => "post",:remote=>true) do |f|%>
|
||||
<input type="hidden" name="quote[quote]" value="">
|
||||
<input type="hidden" name="blog_comment[sticky]" value="0">
|
||||
<input type="hidden" name="blog_comment[locked]" value="0">
|
||||
<input type="hidden" name="blog_comment[title]" value="RE:<%= activity.title%>">
|
||||
<input type="hidden" name="user_activity_id" value="<%=user_activity_id%>">
|
||||
<textarea placeholder="有问题或有建议,请直接给我留言吧!" style="display: none" nhname='new_message_textarea_<%= user_activity_id%>' name="blog_comment[content]"></textarea>
|
||||
<div nhname='toolbar_container_<%= user_activity_id%>' style="float:left; margin-left: 5px; padding-top:3px;"></div>
|
||||
<a id="new_message_submit_btn_<%= user_activity_id%>" href="javascript:void(0)" class="blue_n_btn fr" style="display:none;margin-top:6px;">发送</a>
|
||||
<div class="cl"></div>
|
||||
<p nhname='contentmsg_<%= user_activity_id%>'></p>
|
||||
<% end%>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,101 @@
|
|||
<%= javascript_include_tag "/assets/kindeditor/kindeditor", '/assets/kindeditor/pasteimg', "init_activity_KindEditor" %>
|
||||
<style type="text/css">
|
||||
/*回复框*/
|
||||
.homepagePostReplyInputContainer .ke-toolbar {display: none; width: 400px; border: none; background: none; padding: 0px 0px;}
|
||||
.homepagePostReplyInputContainer .ke-toolbar-icon {line-height: 26px; font-size: 14px; padding-left: 26px;}
|
||||
.homepagePostReplyInputContainer .ke-toolbar-icon-url {background-image: url(/images/public_icon.png)}
|
||||
.homepagePostReplyInputContainer .ke-outline {padding: 0px 0px; line-height: 26px; font-size: 14px;}
|
||||
.homepagePostReplyInputContainer .ke-icon-emoticons {background-position: 0px -671px; width: 50px; height: 26px;}
|
||||
.homepagePostReplyInputContainer .ke-icon-emoticons:hover {background-position: -79px -671px; width: 50px; height: 26px;}
|
||||
.homepagePostReplyInputContainer .ke-outline {border: none;}
|
||||
.homepagePostReplyInputContainer .ke-inline-block {display: none;}
|
||||
.homepagePostReplyInputContainer .ke-container {float: left;}
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
$(function(){
|
||||
$("#RSide").removeAttr("id");
|
||||
$("#Container").css("width","1000px");
|
||||
});
|
||||
function reset_article(){
|
||||
$("#message_subject").val("");
|
||||
$("#subjectmsg").text("");
|
||||
document.getElementById("blog_comment_sticky").checked=false;
|
||||
document.getElementById("blog_comment_locked").checked=false;
|
||||
$("#topic_attachments").html("<%= escape_javascript(render :partial => 'blog_comments/blog_attachments', :locals => {:container => BlogComment.new})%>");
|
||||
message_content_editor.html("");
|
||||
$("#topic_editor").slideToggle();
|
||||
}
|
||||
<%# if @is_new%>
|
||||
// $(function(){
|
||||
// $("#message_subject").focus();
|
||||
// });
|
||||
<%#end%>
|
||||
</script>
|
||||
|
||||
<div class="homepageRight mt0 ml10">
|
||||
<div class="homepageRightBanner">
|
||||
<div class="NewsBannerName">
|
||||
<%= @user.name%>的博客
|
||||
</div>
|
||||
</div>
|
||||
<% if User.current.logged? && User.current.id == @user.id %>
|
||||
<%= labelled_form_for @article, :url =>{:controller=>'blog_comments',:action => 'create',:user_id=>user.id , :blog_id => blog.id},
|
||||
:html => {:nhname=>'form',:multipart => true, :id => 'message-form'} do |f| %>
|
||||
<%= render :partial => 'blog_comments/new', :locals => {:f => f, :article => @article, :edit_mode => false, :user => @user} %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% if topics%>
|
||||
<% topics.each do |topic| %>
|
||||
<script>
|
||||
function expand_reply(container, btnid) {
|
||||
var target = $(container);
|
||||
var btn = $(btnid);
|
||||
if (btn.data('init') == '0') {
|
||||
btn.data('init', 1);
|
||||
btn.html('收起回复');
|
||||
target.show();
|
||||
} else {
|
||||
btn.data('init', 0);
|
||||
btn.html('展开更多');
|
||||
target.hide();
|
||||
target.eq(0).show();
|
||||
target.eq(1).show();
|
||||
target.eq(2).show();
|
||||
}
|
||||
}
|
||||
|
||||
function expand_reply_input(id) {
|
||||
$(id).toggle();
|
||||
}
|
||||
|
||||
$(function () {
|
||||
init_activity_KindEditor_data(<%= topic.id%>, null, "87%");
|
||||
showNormalImage('activity_description_<%= topic.id %>');
|
||||
/*var description_images=$("div#activity_description_<%#= topic.id %>").find("img");
|
||||
if (description_images.length>0) {
|
||||
for (var i=0; i<description_images.length; i++){
|
||||
var image=$(description_images[i]);
|
||||
var element=$("<a></a>").attr("href",image.attr('src'));
|
||||
image.wrap(element);
|
||||
}
|
||||
}
|
||||
$('#activity_description_<%#= topic.id %> a').colorbox({rel:'nofollow', close: "关闭", returnFocus: false});*/
|
||||
});
|
||||
</script>
|
||||
<% if topic %>
|
||||
<%= render :partial => 'blogs/article', :locals => {:activity => topic, :user_activity_id => topic.id} %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<%# if topics.count == 10 %>
|
||||
<!--<div id="show_more_course_topic" class="loadMore mt10 f_grey">展开更多<%#= link_to "", boards_topic_path(@board, :course_id => @board.course.id ,:page => page), :id => "more_topic_link", :remote => "true", :class => "none" %></div>-->
|
||||
<%# end %>
|
||||
<% end%>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$("#show_more_course_topic").mouseover(function () {
|
||||
$("#more_topic_link").click();
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,187 @@
|
|||
<style type="text/css">
|
||||
div.talk_new .ke-container{margin-left:2px;}
|
||||
.break_word {width:100%;}
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
//头部导航
|
||||
var menuids=["TopUserNav"] //Enter id(s) of SuckerTree UL menus, separated by commas
|
||||
function buildsubmenus(){
|
||||
for (var i=0; i<menuids.length; i++){
|
||||
var div = document.getElementById(menuids[i]);
|
||||
if(div == undefined)continue;
|
||||
var ultags=div.getElementsByTagName("ul");
|
||||
for (var t=0; t<ultags.length; t++){
|
||||
ultags[t].parentNode.getElementsByTagName("a")[0].className="subfolderstyle";
|
||||
ultags[t].parentNode.onmouseover=function(){
|
||||
this.getElementsByTagName("ul")[0].style.display="block";
|
||||
}
|
||||
ultags[t].parentNode.onmouseout=function(){
|
||||
this.getElementsByTagName("ul")[0].style.display="none";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (window.addEventListener)
|
||||
window.addEventListener("load", buildsubmenus, false)
|
||||
else if (window.attachEvent)
|
||||
window.attachEvent("onload", buildsubmenus)
|
||||
</script>
|
||||
<%= javascript_include_tag "/assets/kindeditor/kindeditor",'/assets/kindeditor/pasteimg' %>
|
||||
<%#= javascript_include_tag "/assets/kindeditor/kindeditor-min" %>
|
||||
|
||||
|
||||
<%= render :partial => 'blogs/article_list', :locals => {:blog=>@user.blog,:topics => @user.blog.articles.reorder("#{BlogComment.table_name}.sticky desc,#{BlogComment.table_name}.created_on desc"), :page => 0, :user => @user} %>
|
||||
|
||||
|
||||
<script type="text/javascript">//侧导航
|
||||
|
||||
function nh_check_field(params){
|
||||
var result=true;
|
||||
if(params.subject!=undefined){
|
||||
if($.trim(params.subject.val()) == ""){
|
||||
params.subjectmsg.html('主题不能为空');
|
||||
params.subjectmsg.css({color:'#ff0000'});
|
||||
result=false;
|
||||
}else{
|
||||
params.subjectmsg.html('填写正确');
|
||||
params.subjectmsg.css({color:'#008000'});
|
||||
}
|
||||
params.subjectmsg.show();
|
||||
}
|
||||
|
||||
if(params.content!=undefined){
|
||||
if(params.content.isEmpty()){
|
||||
result=false;
|
||||
}
|
||||
if(params.content.html()!=params.textarea.html() || params.issubmit==true){
|
||||
params.textarea.html(params.content.html());
|
||||
params.content.sync(); //用上面那句ie11提交到服务器居然木有值
|
||||
if(params.content.isEmpty()){
|
||||
params.contentmsg.html('内容不能为空');
|
||||
params.contentmsg.css({color:'#ff0000'});
|
||||
}else{
|
||||
params.contentmsg.html('填写正确');
|
||||
params.contentmsg.css({color:'#008000'});
|
||||
}
|
||||
params.contentmsg.show();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
function nh_init_board(params){
|
||||
//发帖/编辑/回复按钮的click
|
||||
params.showbtn.click(function(){
|
||||
params.textarea.removeAttr('placeholder');
|
||||
if(params.textarea.data('init') == undefined){
|
||||
//初始化编辑器
|
||||
var editor = params.kindutil.create(params.textarea, {
|
||||
// allowPreviewEmoticons : false,
|
||||
// allowImageUpload : false,
|
||||
autoHeightMode : true,
|
||||
resizeType : 1,minWidth:"1px",width:"560px",height:"150px",
|
||||
allowFileManager:true,uploadJson:"/kindeditor/upload",
|
||||
fileManagerJson:"/kindeditor/filemanager",
|
||||
afterChange:function(){//按键事件
|
||||
nh_check_field({content:this,contentmsg:params.contentmsg,textarea:params.textarea});
|
||||
// var edit = this.edit;
|
||||
// var body = edit.doc.body;
|
||||
// edit.iframe.height(minHeight);
|
||||
// this.resize(null, Math.max((params.kindutil.IE ? body.scrollHeight : body.offsetHeight) + 30, minHeight));
|
||||
},
|
||||
afterCreate:function(){
|
||||
this.loadPlugin("autoheight");
|
||||
var userAgent = navigator.userAgent.toLowerCase();
|
||||
if(/trident/.test(userAgent)){
|
||||
$("div.talk_new .ke-container").css({'margin-left':'0px'});
|
||||
}
|
||||
// var toolbar = $("div[class='ke-toolbar']",params.about_talk);
|
||||
// $(".ke-outline>.ke-toolbar-icon",toolbar).append('表情');
|
||||
// params.toolbar_container.append(toolbar);
|
||||
}
|
||||
}).loadPlugin('paste');
|
||||
|
||||
//主题输入框按键事件
|
||||
params.inputsubject.keyup(function(){
|
||||
nh_check_field({subject:params.inputsubject,subjectmsg:params.subjectmsg});
|
||||
})
|
||||
//表单提交
|
||||
params.form.submit(function(){
|
||||
var is_checked = nh_check_field({
|
||||
issubmit:true,
|
||||
subject:params.inputsubject,
|
||||
subjectmsg:params.subjectmsg,
|
||||
content:editor,
|
||||
contentmsg:params.contentmsg,
|
||||
textarea:params.textarea
|
||||
});
|
||||
if(is_checked){
|
||||
//return true 居然不提交 fuck your sister
|
||||
$(this)[0].submit();
|
||||
// return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
//提交按钮click
|
||||
params.submitbtn.click(function(){
|
||||
params.form.submit();
|
||||
});
|
||||
//取消按钮click
|
||||
params.cancelbtn.click(function(){
|
||||
params.about_talk.toggle();//显示/隐藏编辑区
|
||||
if(params.about_talk.is(':hidden')){//隐藏时reset表单数据
|
||||
params.form[0].reset();
|
||||
if(params.type=='reply'){
|
||||
params.textarea.empty();
|
||||
}else{
|
||||
params.textarea.html(params.init_content_val.val());
|
||||
}
|
||||
var str = params.textarea.html();
|
||||
str=str.replace(new RegExp(/</g),'<');
|
||||
str=str.replace(new RegExp(/>/g),'>');
|
||||
editor.html(str);
|
||||
params.subjectmsg.hide();
|
||||
params.contentmsg.hide();
|
||||
if(params.quote_show!=undefined)params.quote_show.empty();
|
||||
if(params.quote_input!=undefined)params.quote_input.empty();
|
||||
}else{
|
||||
if(params.type=='reply'){
|
||||
params.textarea.show();
|
||||
params.textarea.focus();
|
||||
params.textarea.hide();
|
||||
//params.jumphref.attr('href','#'+params.form.attr('id'));
|
||||
//params.jumphref[0].click();
|
||||
}else{
|
||||
params.textarea.show();
|
||||
params.textarea.focus();
|
||||
params.textarea.hide();
|
||||
// params.inputsubject.focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
params.textarea.data('init','1');//标记为已经初始化
|
||||
}
|
||||
params.cancelbtn.click();//显示/隐藏编辑区
|
||||
});
|
||||
if(params.type == 'reply'){
|
||||
params.showbtn_child.click(function(){
|
||||
if(params.textarea.data('init') == undefined){
|
||||
params.showbtn.click();
|
||||
}else{
|
||||
params.cancelbtn.click();
|
||||
if(params.about_talk.is(':hidden')){
|
||||
params.cancelbtn.click();
|
||||
}
|
||||
}
|
||||
var parent_topic_id = $(this).data('topic-id');
|
||||
if(parent_topic_id!=undefined)$("input[name='parent_topic']",params.form).val(parent_topic_id);
|
||||
var ref_str = params.get_ref_str_call($(this));
|
||||
params.quote_show.html(ref_str);
|
||||
params.quote_input.html(ref_str);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</script>
|
|
@ -8,7 +8,7 @@
|
|||
<a href="#L<%= line_num %>" style="padding-top: 0px;"><%= line_num %></a>
|
||||
</th>
|
||||
<td class="line-code">
|
||||
<pre style="width:880px;word-wrap: break-word; word-break: normal; "><%= line.html_safe %></pre>
|
||||
<pre style="width:auto;white-space: nowrap; "><%= line.html_safe %></pre>
|
||||
</td>
|
||||
</tr>
|
||||
<% line_num += 1 %>
|
||||
|
|
|
@ -62,13 +62,13 @@
|
|||
<li>
|
||||
<input type="text" style="display: none"/> <!--阻止表单自动填充 -->
|
||||
<input type="password" style="display: none"/> <!--阻止表单自动填充 -->
|
||||
<span class="tips" style="width: 72px; display: inline-block;">课 程 ID:</span>
|
||||
<span class="tips" style="width: 68px; display: inline-block;">课 程 ID:</span>
|
||||
<input class=" width190" name="object_id" id="object_id" type="text" value="" >
|
||||
<input type="text" style="display: none"/>
|
||||
</li>
|
||||
<li class="mB5">课程ID是所在课程网址中显示的序号</li>
|
||||
<li>
|
||||
<span class="tips">密 码:</span>
|
||||
<span class="tips" style="width: 68px; display: inline-block;">密 码:</span>
|
||||
<input class=" width190" type="password" name="course_password" id="course_password" value="" >
|
||||
</li>
|
||||
<li style="margin-top: 30px;">
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<%= favicon %>
|
||||
<%= javascript_heads %>
|
||||
<%= heads_for_theme %>
|
||||
<%= stylesheet_link_tag 'public', 'pleft', 'project','prettify','jquery/jquery-ui-1.9.2','header' %>
|
||||
<%= stylesheet_link_tag 'public', 'pleft', 'project','prettify','jquery/jquery-ui-1.9.2','header','repository' %>
|
||||
<%= javascript_include_tag 'cookie','project', 'header','prettify','select_list_move' %>
|
||||
<%= call_hook :view_layouts_base_html_head %>
|
||||
<!-- page specific tags -->
|
||||
|
|
|
@ -71,27 +71,38 @@
|
|||
<textarea class="homepageSignatureTextarea none" placeholder="请编辑签名" id="user_brief_introduction_edit" onblur="edit_user_introduction('<%= edit_brief_introduction_user_path(@user.id)%>');"><%= @user.user_extensions.brief_introduction %></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div class="homepageImageBlock">
|
||||
<div>
|
||||
<%= link_to(@user.blog.blog_comments.where("#{BlogComment.table_name}.parent_id is null").count,
|
||||
{:controller => 'blogs', :action => 'index', :user_id => @user.id }, :class => 'homepageImageNumber',:id => 'user_score') %>
|
||||
</div>
|
||||
<div class="homepageImageText">
|
||||
|
||||
<%= link_to('博客',
|
||||
{:controller => 'blogs', :action => 'index', :user_id => @user.id }, :class => 'homepageImageNumber',:id => 'user_score') %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="homepageVerDiv"></div>
|
||||
<div class="homepageImageBlock">
|
||||
<div id="watch_user_number_div">
|
||||
<%= link_to User.watched_by(@user.id).count.to_s, {:controller=>"users", :action=>"user_watchlist",:id=>@user.id},:class=>"homepageImageNumber" %>
|
||||
</div>
|
||||
<div class="homepageImageText">关注</div>
|
||||
<div class="homepageImageText">
|
||||
<%= link_to '关注', {:controller=>"users", :action=>"user_watchlist",:id=>@user.id},:class=>"homepageImageNumber" %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="homepageVerDiv"></div>
|
||||
<div class="homepageImageBlock">
|
||||
<div id="fans_user_number_div">
|
||||
<%= link_to @user.watcher_users.count.to_s, {:controller=>"users", :action=>"user_fanslist",:id=>@user.id},:class=>"homepageImageNumber", :id => "user_fans_number"%>
|
||||
</div>
|
||||
<div class="homepageImageText">粉丝</div>
|
||||
</div>
|
||||
<div class="homepageVerDiv"></div>
|
||||
<div class="homepageImageBlock">
|
||||
<div>
|
||||
<%= link_to(format("%.2f" ,get_option_number(@user,1).total_score ).to_i,
|
||||
{:controller => 'users', :action => 'show_new_score', :remote => true, :id => @user.id }, :class => 'homepageImageNumber',:id => 'user_score') %>
|
||||
<div class="homepageImageText">
|
||||
|
||||
<%= link_to '粉丝', {:controller=>"users", :action=>"user_fanslist",:id=>@user.id},:class=>"homepageImageNumber", :id => "user_fans_number"%>
|
||||
</div>
|
||||
<div class="homepageImageText">积分</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,14 @@
|
|||
<p>
|
||||
<%= @user.show_name %>申请成为课程<%= @course.name %>的<%= @role.eql?('9') ? '老师': '教辅' %>
|
||||
<%=link_to user_message_url(@receive),user_message_url(@receive)%>
|
||||
</p>
|
||||
<div class="mail_box" style="border:1px solid #c8c8c8; width:570px; height: auto; padding:15px; margin-top:10px; margin-bottom:10px;">
|
||||
<ul style="list-style-type:none; margin:0; padding:0;">
|
||||
|
||||
<li style="list-style-type:none; margin:0; padding:0;"><span style="float: left;"><strong><%= l(:mail_issue_content)%></strong></span>
|
||||
<span style="float: left; width: 526px">
|
||||
<p><span style="color:#1b55a7; font-weight:bold;"><%= @user.show_name %></span> 请求成为课程:<span style="color:#1b55a7; font-weight:bold;"><%=link_to @course.name, course_url(@course) %></span>的<%= @role.eql?('9') ? '老师': '教辅' %> </p>
|
||||
<p><%=link_to user_message_url(@receive),user_message_url(@receive)%></p>
|
||||
</span>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<div class="cl" style="margin-top: 30px; clear:both; overflow:hidden;"></div>
|
||||
</div>
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
<%# --版本库被设置成私有、module中设置不显示、没有创建版本库 三种情况不显示-- %>
|
||||
<% if visible_repository?(@project) %>
|
||||
<div class="subNav">
|
||||
<%= link_to l(:project_module_repository), {:controller => 'repositories', :action => 'show', :id => @project.id}, :class => "f14 c_blue02" %>
|
||||
<%= link_to l(:project_module_repository), {:controller => 'repositories', :action => 'show', :id => @project.id, to: 'gitlab'}, :class => "f14 c_blue02" %>
|
||||
<a class="subnav_num">(<%= @project.repositories.count %>)</a>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
|
@ -18,6 +18,13 @@
|
|||
|
||||
<script type="text/javascript">
|
||||
function clickCanel(){hideModal("#popbox02");}
|
||||
function clickSure()
|
||||
{
|
||||
if ($('#new_join_course').submit())
|
||||
{
|
||||
hideModal("#popbox02");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
|
@ -33,7 +40,7 @@
|
|||
<label>请输入课程密码:</label>
|
||||
<%= text_field_tag 'course_password', nil, :style=>'width:300px;'%>
|
||||
<div class="ni_btn">
|
||||
<a href="javascript:" class="tijiao" onclick="$('#new_join_course').submit();" >
|
||||
<a href="javascript:" class="tijiao" onclick="clickSure();" >
|
||||
确 定
|
||||
</a>
|
||||
<a href="javascript:" class="tijiao" onclick="clickCanel();">
|
||||
|
|
|
@ -73,13 +73,6 @@
|
|||
<span class="c_grey"><%= l(:text_scm_command_not_available) %></span>
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
<% unless judge_main_repository(@project) %>
|
||||
<li>
|
||||
<label class="label02"><%=l(:field_repository_is_default)%>:</label>
|
||||
<%= f.check_box :is_default, :label => "", :no_label => true %></p>
|
||||
</li>
|
||||
<% end %>
|
||||
<li >
|
||||
<input type="text" style="display: none"/> <!--阻止表单自动填充 -->
|
||||
<input type="password" style="display: none"/> <!--阻止表单自动填充 -->
|
||||
|
@ -89,11 +82,6 @@
|
|||
<span class="c_grey"><%=l(:text_length_between,:min=>1,:max=>254)<<l(:text_project_identifier_info) %></span>
|
||||
<% end %>
|
||||
</li>
|
||||
<li >
|
||||
<label class="label02"><span class="c_red">*</span><%=l(:label_password)%></label>
|
||||
<%= f.password_field :upassword, :label=> "", :no_label => true%>
|
||||
<span class="c_grey"><%= l(:label_upassword_info)%></span>
|
||||
</li>
|
||||
<div class="cl"></div>
|
||||
</ul>
|
||||
<a href="#" onclick="$('#repository-form').submit();" class="blue_btn fl ml110"><%=l(:button_save)%></a>
|
||||
|
|
|
@ -1,32 +1,13 @@
|
|||
<%= link_to @repository.identifier.present? ? h(@repository.identifier) : 'root',
|
||||
{:action => 'show', :id => @project,
|
||||
:repository_id => @repository.identifier_param,
|
||||
:path => nil, :rev => @rev },
|
||||
:class=>"fl c_blue f14 fb" %>
|
||||
<%
|
||||
dirs = path.split('/')
|
||||
if 'file' == kind
|
||||
filename = dirs.pop
|
||||
end
|
||||
link_path = ''
|
||||
dirs.each do |dir|
|
||||
next if dir.blank?
|
||||
link_path << '/' unless link_path.empty?
|
||||
link_path << "#{dir}"
|
||||
%>
|
||||
/ <%= link_to h(dir), :action => 'show', :id => @project, :repository_id => @repository.identifier_param,
|
||||
:path => to_path_param(link_path), :rev => @rev %>
|
||||
<% end %>
|
||||
<% if filename %>
|
||||
/ <%= link_to h(filename),
|
||||
:action => 'changes', :id => @project, :repository_id => @repository.identifier_param,
|
||||
:path => to_path_param("#{link_path}/#{filename}"), :rev => @rev %>
|
||||
<% end %>
|
||||
<%
|
||||
# @rev is revsion or Git and Mercurial branch or tag.
|
||||
# For Mercurial *tip*, @rev and @changeset are nil.
|
||||
rev_text = @changeset.nil? ? @rev : format_revision(@changeset)
|
||||
%>
|
||||
<p class="fl f14 fb c_grey02"><%= "@ #{h rev_text}" unless rev_text.blank? %></p>
|
||||
<div class="git_usr_title">
|
||||
<span><%= link_to @repository.identifier.present? ? h(@repository.identifier) : 'root',
|
||||
{:action => 'show', :id => @project,
|
||||
:repository_id => @repository.identifier_param,
|
||||
:path => nil, :rev => @rev },
|
||||
:class => "repository-title-dec"
|
||||
%>
|
||||
/
|
||||
<%=link_to @project.owner, user_path(@project.owner), :class => "repository-title-dec" %>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<% html_title(with_leading_slash(path)) -%>
|
||||
|
|
|
@ -1,17 +1,6 @@
|
|||
<div class="autoscroll">
|
||||
<table class="list entries" id="browser">
|
||||
<thead>
|
||||
<tr id="root">
|
||||
<th><%= l(:field_name) %></th>
|
||||
<th><%= l(:field_filesize) %></th>
|
||||
<% if @repository.report_last_commit %>
|
||||
<th><%= l(:label_revision) %></th>
|
||||
<th><%= l(:label_age) %></th>
|
||||
<th><%= l(:field_author) %></th>
|
||||
<th><%= l(:field_comments) %></th>
|
||||
<% end %>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<%= render :partial => 'dir_list_content' %>
|
||||
</tbody>
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
<td style="padding-left: <%=18 * depth%>px;" class="<%=
|
||||
@repository.report_last_commit ? "filename" : "filename_no_report" %>">
|
||||
<% if entry.is_dir? %>
|
||||
<%# 展开文件目录 %>
|
||||
<span class="expander" onclick="scmEntryClick('<%= tr_id %>', '<%= escape_javascript(url_for(
|
||||
:action => 'show',
|
||||
:id => @project,
|
||||
|
@ -17,10 +18,11 @@
|
|||
:parent_id => tr_id)) %>');"> </span>
|
||||
<% end %>
|
||||
<%= link_to h(ent_name),
|
||||
{:action => (entry.is_dir? ? 'show' : 'changes'), :id => @project, :repository_id => @repository.identifier_param, :path => to_path_param(ent_path), :rev => @rev},
|
||||
{:action => (entry.is_dir? ? 'show' : 'entry'), :id => @project, :repository_id => @repository.identifier_param, :path => to_path_param(ent_path), :rev => @rev},
|
||||
:class => (entry.is_dir? ? 'icon icon-folder' : "icon icon-file #{Redmine::MimeType.css_class_of(ent_name)}")%>
|
||||
</td>
|
||||
<td class="size"><%= (entry.size ? number_to_human_size(entry.size) : "?") unless entry.is_dir? %></td>
|
||||
<!--<td class="size"><%#= (entry.size ? number_to_human_size(entry.size) : "?") unless entry.is_dir? %></td>-->
|
||||
<% if @repository.report_last_commit %>
|
||||
<td class="revision"><%= link_to_revision(entry.changeset, @repository) if entry.changeset %></td>
|
||||
<td class="age"><%= distance_of_time_in_words(entry.lastrev.time, Time.now) if entry.lastrev && entry.lastrev.time %></td>
|
||||
|
|
|
@ -31,12 +31,7 @@
|
|||
<%= f.text_field :login, :size => 30 %>
|
||||
<input type="text" hidden="hidden">
|
||||
</p>
|
||||
<p>
|
||||
<%= f.password_field :password, :size => 30, :name => 'ignore',
|
||||
:value => ((@repository.new_record? || @repository.password.blank?) ? '' : ('x'*15)),
|
||||
:onfocus => "this.value=''; this.name='repository[password]';",
|
||||
:onchange => "this.name='repository[password]';" %>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
<!--Ended by tanxianbo-->
|
||||
<p>
|
||||
|
|
|
@ -26,7 +26,6 @@ border:none
|
|||
<em class="info error"><%= l(:text_scm_command_not_available) %></em>
|
||||
<% end %>
|
||||
</p>
|
||||
<p><%= f.check_box :is_default, :label => :field_repository_is_default %></p>
|
||||
|
||||
<p>
|
||||
<input id="googleinputcache" size="30" type="text">
|
||||
|
@ -36,8 +35,6 @@ border:none
|
|||
<%= l(:text_repository_identifier_info).html_safe %></em>
|
||||
<% end %></p>
|
||||
<!-- <p><%#= f.text_field :url, :size => 60, :required => true,:readonly=>true, :class=>'textbg'%></p> -->
|
||||
<p><%= f.password_field :upassword, :required =>true, :label=> :field_password %>
|
||||
<em class="info"><%= l(:label_upassword_info)%></em></p>
|
||||
</div>
|
||||
<p>
|
||||
<%= submit_tag(@repository.new_record? ? l(:button_create) : l(:button_save)) %>
|
||||
|
|
|
@ -1,34 +1,33 @@
|
|||
<% content_for :header_tags do %>
|
||||
<%= javascript_include_tag 'repository_navigation' %>
|
||||
<% end %>
|
||||
<a href="javascript:void(0);" class="pic_stats fl ml20 mt3"></a>
|
||||
<%= link_to l(:label_statistics),
|
||||
<!--<a href="javascript:void(0);" class="pic_stats fl ml20 mt3"></a>-->
|
||||
<%#= link_to l(:label_statistics),
|
||||
{:action => 'stats', :id => @project, :repository_id => @repository.identifier_param},
|
||||
:class => 'mt3 c_blue fl' if @repository.supports_all_revisions? %>
|
||||
<div class="repositorytitle mr15">
|
||||
<% content_for :header_tags do %>
|
||||
<%= javascript_include_tag 'repository_navigation' %>
|
||||
<% end %>
|
||||
|
||||
<%= form_tag({:action => controller.action_name,
|
||||
:id => @project,
|
||||
:repository_id => @repository.identifier_param,
|
||||
:path => to_path_param(@path),
|
||||
:rev => nil},
|
||||
{:method => :get, :id => 'revision_selector', :class => "fl c_grey02 ml5"}) do -%>
|
||||
<!-- Branches Dropdown -->
|
||||
<% if !@repository.branches.nil? && @repository.branches.length > 0 -%>
|
||||
| <%= l(:label_branch) %>:
|
||||
<%= select_tag :branch,
|
||||
options_for_select([''] + @repository.branches, @rev),
|
||||
:id => 'branch' %>
|
||||
<% end -%>
|
||||
|
||||
<% if !@repository.tags.nil? && @repository.tags.length > 0 -%>
|
||||
| <%= l(:label_tag) %>:
|
||||
<%= select_tag :tag,
|
||||
options_for_select([''] + @repository.tags, @rev),
|
||||
:id => 'tag' %>
|
||||
<% end -%>
|
||||
|
||||
<% if @repository.supports_all_revisions? %>
|
||||
| <%= l(:label_revision) %>:
|
||||
<%= text_field_tag 'rev', @rev, :size => 8 %>
|
||||
<% end %>
|
||||
<% end -%>
|
||||
<%= form_tag({:action => controller.action_name,
|
||||
:id => @project,
|
||||
:repository_id => @repository.identifier_param,
|
||||
:path => to_path_param(@path),
|
||||
:rev => nil},
|
||||
{:method => :get, :id => 'revision_selector'}) do -%>
|
||||
<!-- Branches Dropdown -->
|
||||
<% if !@repository.branches.nil? && @repository.branches.length > 0 -%>
|
||||
<%= l(:label_branch) %>:
|
||||
<%= select_tag :branch, options_for_select([''] + @repository.branches, @rev), :id => 'branch' %>
|
||||
<% end -%>
|
||||
|
||||
<% if !@repository.tags.nil? && @repository.tags.length > 0 -%>
|
||||
<%= select_tag :tag, options_for_select([''] + @repository.tags, @rev), :id => 'tag', :style=>" display:none" %>
|
||||
<% end -%>
|
||||
|
||||
<% if @repository.supports_all_revisions? %>
|
||||
<%= hidden_field_tag 'rev', @rev, :size => 8 %>
|
||||
<% end %>
|
||||
<% end -%>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
<div class="overall-summary overall-summary-bottomless">
|
||||
|
||||
<div class="stats-switcher-viewport js-stats-switcher-viewport">
|
||||
<div class="stats-switcher-wrapper">
|
||||
<ul class="numbers-summary">
|
||||
<li class="commits">
|
||||
<a data-pjax="" href="/redmine/redmine/commits/0.6-stable">
|
||||
<span class="octicon octicon-history"></span>
|
||||
<span class="num text-emphasized">
|
||||
<%=link_to @changesets.count, {:action => 'changes', :path => to_path_param(@path), :id => @project, :repository_id => @repository.identifier_param, :rev => @rev}, :class => "num text-emphasized c_blue" %>
|
||||
</span>
|
||||
commits
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<span class="octicon image-type"></span>
|
||||
<span class="num text-emphasized" style="color: #269AC9">
|
||||
<%= @repository.branches.count %>
|
||||
</span>
|
||||
branches
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<span class="octicon octicon-organization"></span>
|
||||
<span class="num text-emphasized">
|
||||
<%=link_to @repository.committers.count, committers_repository_path(@repository), :class => "c_blue" %>
|
||||
</span>
|
||||
contributors
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
|
@ -1,18 +1,20 @@
|
|||
<%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %>
|
||||
|
||||
<div class="contextual">
|
||||
<%= render :partial => 'navigation' %>
|
||||
<div class="project_r_h">
|
||||
<div class="fl"><h2 class="project_h2_repository"><%= render :partial => 'breadcrumbs', :locals => {:path => @path, :kind => 'dir', :revision => @rev} %></h2></div>
|
||||
</div>
|
||||
|
||||
<h3><%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => (@entry ? @entry.kind : nil), :revision => @rev } %></h3>
|
||||
<div class="repository_con " style="line-height:1.9;">
|
||||
<%= render :partial => 'navigation' %>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
|
||||
<%= render :partial => 'link_to_functions' %>
|
||||
|
||||
<%= render_properties(@properties) %>
|
||||
|
||||
<div class="mt40">
|
||||
<%= render(:partial => 'revisions',
|
||||
:locals => {:project => @project, :path => @path, :revisions => @changesets, :entry => @entry }) unless @changesets.empty? %>
|
||||
<div class="mt10">
|
||||
<%= render(:partial => 'revisions', :locals => {:project => @project, :path => @path, :revisions => @changesets, :entry => @entry }) unless @changesets.empty? %>
|
||||
</div>
|
||||
<% content_for :header_tags do %>
|
||||
<%= stylesheet_link_tag "scm" %>
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
<h3><%= l(:label_repository) %></h3>
|
||||
<div class="project_r_h">
|
||||
<div class="fl">
|
||||
<h2 class="project_h2_repository"><%= render :partial => 'breadcrumbs', :locals => {:path => @path, :kind => 'dir', :revision => @rev} %></h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= simple_format(l(:text_repository_usernames_mapping)) %>
|
||||
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
<h3><%= l(:label_revision) %> <%= @diff_format_revisions %> <%=h @path %></h3>
|
||||
<div class="project_r_h">
|
||||
<div class="fl"><h2 class="project_h2_repository"><%= render :partial => 'breadcrumbs', :locals => {:path => @path, :kind => 'dir', :revision => @rev} %></h2></div>
|
||||
</div>
|
||||
<h3><%= l(:label_revision_path) %> :<%=h @path %></h3>
|
||||
|
||||
<!-- Choose view type -->
|
||||
<%= form_tag({:action => 'diff', :id => @project,
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
<%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %>
|
||||
<div style="padding-left: 8px; padding-top: 10px;">
|
||||
<div class="contextual">
|
||||
<%= render :partial => 'navigation' %>
|
||||
</div>
|
||||
|
||||
<div class="contextual">
|
||||
<%= render :partial => 'navigation' %>
|
||||
<h3><%= l(:label_revision_path) %> :<%= @path %></h3>
|
||||
|
||||
<%= render :partial => 'link_to_functions' %>
|
||||
|
||||
<%= render :partial => 'common/file', :locals => {:filename => @path, :content => @content} %>
|
||||
|
||||
<% content_for :header_tags do %>
|
||||
<%= stylesheet_link_tag "scm" %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<h3><%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => 'file', :revision => @rev } %></h3>
|
||||
|
||||
<%= render :partial => 'link_to_functions' %>
|
||||
|
||||
<%= render :partial => 'common/file', :locals => {:filename => @path, :content => @content} %>
|
||||
|
||||
<% content_for :header_tags do %>
|
||||
<%= stylesheet_link_tag "scm" %>
|
||||
<% end %>
|
||||
|
|
|
@ -1,83 +1,74 @@
|
|||
<%= call_hook(:view_repositories_show_contextual, {:repository => @repository, :project => @project}) %>
|
||||
<div class="project_r_h">
|
||||
<h2 class="project_h2">版本库</h2>
|
||||
<div class="fl"><h2 class="project_h2_repository"><%= render :partial => 'breadcrumbs', :locals => {:path => @path, :kind => 'dir', :revision => @rev} %></h2></div>
|
||||
</div>
|
||||
<div class="repository_con" style="line-height:1.9;">
|
||||
<div class="repositorytitle" style="float:left;">
|
||||
<%= render :partial => 'breadcrumbs',
|
||||
:locals => {:path => @path, :kind => 'dir', :revision => @rev} %>
|
||||
<%= render :partial => 'navigation' %>
|
||||
</div>
|
||||
<!--contextual end-->
|
||||
<div class="cl"></div>
|
||||
<div class=" c_dark f14">
|
||||
<p>
|
||||
<% if @repository.type.to_s=="Repository::Git" %>
|
||||
<%= @repos_url %>
|
||||
<% else %>
|
||||
<%= h @repository.url %>
|
||||
<% end %>
|
||||
</p>
|
||||
<% if @entries.nil? %>
|
||||
<%# 未提交代码提示 %>
|
||||
<div class=" repository-url light-well">
|
||||
<% if @entries.nil? && authorize_for('repositories', 'browse') %>
|
||||
<div class="page-title">
|
||||
该版本库还没有上传代码!
|
||||
</div>
|
||||
<% end %>
|
||||
<% if @repository.type.to_s=="Repository::Gitlab" %>
|
||||
版本库地址:<%= @repos_url %>
|
||||
<% else %>
|
||||
版本库地址:<%= h @repository.url %>
|
||||
<% end %>
|
||||
<!-- added by bai -->
|
||||
<div class="fb"><a href="http://<%=Setting.host_name %>/forums/1/memos/1232" class=" c_blue ">点击查看如何提交代码</a></div>
|
||||
<div class="cl"></div>
|
||||
</div>
|
||||
<% else %>
|
||||
<%= render :partial => 'navigation' %>
|
||||
<div class="fl c_grey02 mt5 mr5">克隆网址:</div>
|
||||
<textarea id="copy_rep_content" class="cloneUrl mt5 fl" type="input" placeholder="http://xianbo_trustie2@repository.trustie.net/xianbo/trustie2.git"><%=@repository.type.to_s=="Repository::Gitlab" ? @repos_url.to_s.lstrip : @repository.url %></textarea>
|
||||
<a href="javascript:void(0);" class="clone_btn mt5" onclick="jsCopy()"><span class="vl_copy" title="点击复制版本库地址"></span></a>
|
||||
<div class="fl mt5 ml15"><a href="javascript:void(0);" class="vl_btn fb" onclick="zip()"><span class="vl_zip"></span>ZIP</a> </div>
|
||||
<div class="fr mt5"><a href="javascript:void(0);" class="vl_btn fb" onclick="zip()"><span class="vl_fork"></span>Fork</a> <span href="javascript:void(0);" class="vl_btn_2 fb">0</span> </div>
|
||||
<div class="cl"></div>
|
||||
<div class="recordBanner mt10">
|
||||
<% if @changesets && !@changesets.empty? %>
|
||||
<%= image_tag(url_to_avatar(@changesets_latest_coimmit.user), :width => "25", :height => "25", :class => "fl portraitRadius mt2 ml4 mr5") %>
|
||||
<span class="fl"><div class="fb fontGrey3 mr5 fl"><%=link_to @changesets_latest_coimmit.user, user_path(@changesets_latest_coimmit.user) %></div>
|
||||
<div class="fl">提交于<%= time_tag(@changesets_latest_coimmit.committed_on) %>:</div>
|
||||
<div class="commit_content_dec fl" title="<%= @changesets_latest_coimmit.comments %>"><%= @changesets_latest_coimmit.comments %></div>
|
||||
</span>
|
||||
<% end %>
|
||||
<span class="fr mr5 "><font class="fb ml2 mr2 vl_branch mt2">
|
||||
<%= @repository.branches.count %></font> 个分支
|
||||
</span>
|
||||
|
||||
<p class="mb10 break_word">
|
||||
(<%= l(:label_all_revisions) %><%= @repositories.sort.collect { |repo|
|
||||
link_to h(repo.name),
|
||||
{:controller => 'repositories', :action => 'show',
|
||||
:id => @project, :repository_id => repo.identifier_param, :rev => nil, :path => nil},
|
||||
:class => 'repository' + (repo == @repository ? ' selected' : ''),
|
||||
:class => "mb10 break_word c_orange" }.join(' | ').html_safe %>)
|
||||
</p>
|
||||
</div>
|
||||
<span class="fr mr5"><font class="fb ml2 mr2 vl_commit">
|
||||
<%=link_to @changesets_count, {:action => 'changes', :path => to_path_param(@path), :id => @project, :repository_id => @repository.identifier_param, :rev => @rev} %></font> 提交
|
||||
</span>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<!--contextual end-->
|
||||
|
||||
<% if !@entries.nil? && authorize_for('repositories', 'browse') %>
|
||||
<%# 数据统计 %>
|
||||
<%#= render :partial => 'summary' %>
|
||||
<%# end %>
|
||||
<%= render :partial => 'dir_list' %>
|
||||
<% end %>
|
||||
<%= render_properties(@properties) %>
|
||||
|
||||
<!-- 代码修订 -->
|
||||
<% if authorize_for('repositories', 'revisions') %>
|
||||
<%# if @changesets && !@changesets.empty? %>
|
||||
<h3>
|
||||
<%= l(:label_latest_revision_plural) %>
|
||||
</h3>
|
||||
<%= render :partial => 'revisions',
|
||||
:locals => {:project => @project, :path => @path,
|
||||
:revisions => @changesets, :entry => nil} %>
|
||||
<%# end %>
|
||||
<%= render_properties(@properties) %>
|
||||
|
||||
<p style="padding-top: 10px;">
|
||||
<% if authorize_for('repositories', 'revisions') %>
|
||||
<% if @changesets && !@changesets.empty? %>
|
||||
<% has_branches = (!@repository.branches.nil? && @repository.branches.length > 0)
|
||||
sep = '' %>
|
||||
<% if @repository.supports_all_revisions? && @path.blank? %>
|
||||
<%= link_to l(:label_view_all_revisions), {:action => 'revisions', :id => @project,
|
||||
:repository_id => @repository.identifier_param},
|
||||
:class => "orange_u_btn" %>
|
||||
<% sep = '|' %>
|
||||
<% end %>
|
||||
<% if @repository.supports_directory_revisions? && (has_branches || !@path.blank? || !@rev.blank?) %>
|
||||
<%= sep %>
|
||||
<%= link_to l(:label_view_revisions),
|
||||
{:action => 'changes',
|
||||
:path => to_path_param(@path),
|
||||
:id => @project,
|
||||
:repository_id => @repository.identifier_param,
|
||||
:rev => @rev},
|
||||
:class => "orange_u_btn" %>
|
||||
<% end %>
|
||||
</p>
|
||||
<% if @repository.supports_all_revisions? %>
|
||||
<% content_for :header_tags do %>
|
||||
<%= auto_discovery_link_tag(
|
||||
:atom, params.merge(
|
||||
{:format => 'atom', :action => 'revisions',
|
||||
:id => @project, :page => nil, :key => User.current.rss_key})) %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% if @repository.supports_all_revisions? && @path.blank? %>
|
||||
<%= link_to l(:label_view_all_revisions_commits), :action => 'revisions', :id => @project, :repository_id => @repository.identifier_param %>
|
||||
<% end %> |
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<!-- added by bai -->
|
||||
<p class="fb mt10"><a href="http://<%=Setting.host_name %>/forums/1/memos/1232" class=" c_blue ">点击查看如何提交代码</a></p>
|
||||
<div class="cl"></div>
|
||||
<a href="https://<%=Setting.host_name %>/forums/1/memos/1232" >如何提交代码</a>
|
||||
|
||||
<% content_for :header_tags do %>
|
||||
<%= stylesheet_link_tag "scm" %>
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<div class="repository-update-dec">
|
||||
<p class="c_orange">
|
||||
<%= l(:label_repository_migrate_dec) %>
|
||||
</p>
|
||||
<%= form_for(@repository, url: to_gitlab_project_repository_path(@project, @repository)) do |f| %>
|
||||
<input type="text" name="repo_name"/>
|
||||
<button type="submit">转换到新版本</button>
|
||||
<% end %>
|
||||
<span class="c_grey">
|
||||
<%= l(:label_repository_name_dec) %>
|
||||
</span>
|
||||
</div>
|
|
@ -69,6 +69,12 @@ module RedmineApp
|
|||
|
||||
config.action_view.sanitized_allowed_tags = 'div', 'p', 'span', 'img', 'embed'
|
||||
|
||||
config.before_initialize do
|
||||
end
|
||||
|
||||
config.after_initialize do
|
||||
end
|
||||
|
||||
if File.exists?(File.join(File.dirname(__FILE__), 'additional_environment.rb'))
|
||||
instance_eval File.read(File.join(File.dirname(__FILE__), 'additional_environment.rb'))
|
||||
end
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
Gitlab.configure do |config|
|
||||
# config.endpoint = 'http://192.168.41.130:3000/trustie/api/v3' # API endpoint URL, default: ENV['GITLAB_API_ENDPOINT']
|
||||
# config.private_token = 'cK15gUDwvt8EEkzwQ_63' # user's private token, default: ENV['GITLAB_API_PRIVATE_TOKEN']
|
||||
config.endpoint = 'http://git.trustie.net/trustie/api/v3' # API endpoint URL, default: ENV['GITLAB_API_ENDPOINT']
|
||||
config.private_token = 'fPc_gBmEiSANve8TCfxW' # user's private token, default: ENV['GITLAB_API_PRIVATE_TOKEN']
|
||||
# Optional
|
||||
# config.user_agent = 'Custom User Agent' # user agent, default: 'Gitlab Ruby Gem [version]'
|
||||
# config.sudo = 'user' # username for sudo mode, default: nil
|
||||
end
|
|
@ -481,6 +481,7 @@ en:
|
|||
label_attribute_plural: Attributes
|
||||
label_change_status: Change status
|
||||
label_history: History
|
||||
label_commit_history: Commit History
|
||||
label_attachment: Files
|
||||
label_attachment_delete: Delete file
|
||||
|
||||
|
|
|
@ -322,6 +322,7 @@ zh:
|
|||
label_latest_revision_plural: 最近的修订版本
|
||||
label_view_revisions: 查看修订
|
||||
label_view_all_revisions: 查看所有修订
|
||||
label_view_all_revisions_commits: 查看所有提交记录
|
||||
#
|
||||
# 项目托管平台
|
||||
#
|
||||
|
@ -440,4 +441,8 @@ zh:
|
|||
#
|
||||
field_sharing: 共享
|
||||
label_title_code_review: 代码评审
|
||||
label_home_non_project: 您还没有创建项目,您可以查看系统的其它项目!
|
||||
label_home_non_project: 您还没有创建项目,您可以查看系统的其它项目!
|
||||
|
||||
# 版本库迁移
|
||||
label_repository_migrate_dec: 注意:Trustie版本库近期进行了一次大的改造,历史版本需要转换成新的版本,输入新的版本库名,即可完成转换。 转换过程可能需要等待一段时间。
|
||||
label_repository_name_dec: 版本库名仅小写字母(a-z)、数字、破折号(-)和下划线(_)可以使用,长度必须在 1 到 254 个字符之间,一旦保存,标识无法修改。
|
|
@ -580,6 +580,7 @@ zh:
|
|||
|
||||
label_change_status: 变更状态
|
||||
label_history: 历史记录
|
||||
label_commit_history: 历史变更记录
|
||||
label_attachment: 文件
|
||||
|
||||
label_file_upload: 上传资料
|
||||
|
@ -674,6 +675,7 @@ zh:
|
|||
label_branch: 分支
|
||||
label_tag: 标签
|
||||
label_revision: 修订
|
||||
label_revision_path: 当前路径
|
||||
label_revision_plural: 修订
|
||||
lable_revision_code_count: 代码量
|
||||
label_revision_commit_count: 提交次数
|
||||
|
@ -924,7 +926,7 @@ zh:
|
|||
button_change_password: 修改密码
|
||||
button_copy: 复制
|
||||
button_copy_and_follow: 复制并转到新问题
|
||||
button_annotate: 追溯
|
||||
button_annotate: 代码定位
|
||||
|
||||
button_configure: 配置
|
||||
button_quote: 引用
|
||||
|
@ -987,7 +989,7 @@ zh:
|
|||
text_enumeration_destroy_question: "%{count} 个对象被关联到了这个枚举值。"
|
||||
text_enumeration_category_reassign_to: '将它们关联到新的枚举值:'
|
||||
text_email_delivery_not_configured: "邮件参数尚未配置,因此邮件通知功能已被禁用。\n请在config/configuration.yml中配置您的SMTP服务器信息并重新启动以使其生效。"
|
||||
text_repository_usernames_mapping: "选择或更新与版本库中的用户名对应的Trustie用户。\n版本库中与Trustie中的同名用户将被自动对应。"
|
||||
text_repository_usernames_mapping: "选择或更新与版本库中的用户名对应的Trustie用户,版本库中与Trustie中的同名用户将被自动对应。"
|
||||
text_diff_truncated: '... 差别内容超过了可显示的最大行数并已被截断'
|
||||
text_custom_field_possible_values_info: '每项数值一行'
|
||||
text_wiki_page_destroy_question: 此页面有 %{descendants} 个子页面和下级页面。您想进行那种操作?
|
||||
|
|
|
@ -392,6 +392,15 @@ RedmineApp::Application.routes.draw do
|
|||
get 'store_selected_resource'
|
||||
# end
|
||||
end
|
||||
#resources :blogs
|
||||
resources :blogs do
|
||||
resources :blog_comments do
|
||||
member do
|
||||
post 'reply'
|
||||
get 'quote'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
match 'users/:id/user_newfeedback', :to => 'users#user_newfeedback', :via => :get, :as => "feedback"
|
||||
match 'users/:id/user_projects', :to => 'users#user_projects', :via => :get
|
||||
|
@ -535,6 +544,7 @@ RedmineApp::Application.routes.draw do
|
|||
resources :repositories, :except => [:index, :show] do
|
||||
member do
|
||||
get 'newrepo', :via => [:get, :post]
|
||||
put 'to_gitlab'
|
||||
# get 'create', :via=>[:get, :post]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
class AddGitlabUserIdToUsers < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :users, :gid, :integer
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
class AddGpidToProject < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :projects, :gpid, :integer
|
||||
end
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
class CreateBlogs < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :blogs do |t|
|
||||
t.string "name", :default => "", :null => false
|
||||
t.text "description"
|
||||
t.integer "position", :default => 1
|
||||
t.integer "article_count", :default => 0, :null => false
|
||||
t.integer "comments_count", :default => 0, :null => false
|
||||
t.integer "last_comments_id"
|
||||
t.integer "parent_id"
|
||||
t.integer "author_id"
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
class CreateBlogComments < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :blog_comments do |t|
|
||||
t.integer "blog_id", :null => false
|
||||
t.integer "parent_id"
|
||||
t.string "title", :default => "", :null => false
|
||||
t.text "content"
|
||||
t.integer "author_id"
|
||||
t.integer "comments_count", :default => 0, :null => false
|
||||
t.integer "last_comment_id"
|
||||
t.datetime "created_on", :null => false
|
||||
t.datetime "updated_on", :null => false
|
||||
t.boolean "locked", :default => false
|
||||
t.integer "sticky", :default => 0
|
||||
t.integer "reply_id"
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
3476
db/schema.rb
3476
db/schema.rb
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,4 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
# Specify your gem's dependencies in gitlab.gemspec
|
||||
gemspec
|
|
@ -0,0 +1,24 @@
|
|||
Copyright (c) 2012-2014 Nihad Abbasov <mail@narkoz.me>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,121 @@
|
|||
# Gitlab
|
||||
|
||||
[![Build Status](https://travis-ci.org/NARKOZ/gitlab.png)](http://travis-ci.org/NARKOZ/gitlab)
|
||||
|
||||
[website](http://narkoz.github.io/gitlab) |
|
||||
[documentation](http://rubydoc.info/gems/gitlab/frames)
|
||||
|
||||
Gitlab is a Ruby wrapper and CLI for the [GitLab API](https://github.com/gitlabhq/gitlabhq/tree/master/doc/api#gitlab-api).
|
||||
|
||||
## Installation
|
||||
|
||||
Install it from rubygems:
|
||||
|
||||
```sh
|
||||
gem install gitlab
|
||||
```
|
||||
|
||||
Or add to a Gemfile:
|
||||
|
||||
```ruby
|
||||
gem 'gitlab'
|
||||
# gem 'gitlab', :git => 'git://github.com/NARKOZ/gitlab.git'
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Configuration example:
|
||||
|
||||
```ruby
|
||||
Gitlab.configure do |config|
|
||||
config.endpoint = 'https://example.net/api/v3' # API endpoint URL, default: ENV['GITLAB_API_ENDPOINT']
|
||||
config.private_token = 'qEsq1pt6HJPaNciie3MG' # user's private token, default: ENV['GITLAB_API_PRIVATE_TOKEN']
|
||||
# Optional
|
||||
# config.user_agent = 'Custom User Agent' # user agent, default: 'Gitlab Ruby Gem [version]'
|
||||
# config.sudo = 'user' # username for sudo mode, default: nil
|
||||
end
|
||||
```
|
||||
|
||||
(Note: If you are using Gitlab.com's hosted service, your endpoint will be `https://gitlab.com/api/v3`)
|
||||
|
||||
Usage examples:
|
||||
|
||||
```ruby
|
||||
# set an API endpoint
|
||||
Gitlab.endpoint = 'http://example.net/api/v3'
|
||||
# => "http://example.net/api/v3"
|
||||
|
||||
# set a user private token
|
||||
Gitlab.private_token = 'qEsq1pt6HJPaNciie3MG'
|
||||
# => "qEsq1pt6HJPaNciie3MG"
|
||||
|
||||
# list projects
|
||||
Gitlab.projects(:per_page => 5)
|
||||
# => [#<Gitlab::ObjectifiedHash:0x000000023326e0 @data={"id"=>1, "code"=>"brute", "name"=>"Brute", "description"=>nil, "path"=>"brute", "default_branch"=>nil, "owner"=>#<Gitlab::ObjectifiedHash:0x00000002331600 @data={"id"=>1, "email"=>"john@example.com", "name"=>"John Smith", "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}>, "private"=>true, "issues_enabled"=>true, "merge_requests_enabled"=>true, "wall_enabled"=>true, "wiki_enabled"=>true, "created_at"=>"2012-09-17T09:41:56Z"}>, #<Gitlab::ObjectifiedHash:0x000000023450d8 @data={"id"=>2, "code"=>"mozart", "name"=>"Mozart", "description"=>nil, "path"=>"mozart", "default_branch"=>nil, "owner"=>#<Gitlab::ObjectifiedHash:0x00000002344ca0 @data={"id"=>1, "email"=>"john@example.com", "name"=>"John Smith", "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}>, "private"=>true, "issues_enabled"=>true, "merge_requests_enabled"=>true, "wall_enabled"=>true, "wiki_enabled"=>true, "created_at"=>"2012-09-17T09:41:57Z"}>, #<Gitlab::ObjectifiedHash:0x00000002344958 @data={"id"=>3, "code"=>"gitlab", "name"=>"Gitlab", "description"=>nil, "path"=>"gitlab", "default_branch"=>nil, "owner"=>#<Gitlab::ObjectifiedHash:0x000000023447a0 @data={"id"=>1, "email"=>"john@example.com", "name"=>"John Smith", "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}>, "private"=>true, "issues_enabled"=>true, "merge_requests_enabled"=>true, "wall_enabled"=>true, "wiki_enabled"=>true, "created_at"=>"2012-09-17T09:41:58Z"}>]
|
||||
|
||||
# initialize a new client
|
||||
g = Gitlab.client(:endpoint => 'https://api.example.com', :private_token => 'qEsq1pt6HJPaNciie3MG')
|
||||
# => #<Gitlab::Client:0x00000001e62408 @endpoint="https://api.example.com", @private_token="qEsq1pt6HJPaNciie3MG", @user_agent="Gitlab Ruby Gem 2.0.0">
|
||||
|
||||
# get a user
|
||||
user = g.user
|
||||
# => #<Gitlab::ObjectifiedHash:0x00000002217990 @data={"id"=>1, "email"=>"john@example.com", "name"=>"John Smith", "bio"=>nil, "skype"=>"", "linkedin"=>"", "twitter"=>"john", "dark_scheme"=>false, "theme_id"=>1, "blocked"=>false, "created_at"=>"2012-09-17T09:41:56Z"}>
|
||||
|
||||
# get a user's email
|
||||
user.email
|
||||
# => "john@example.com"
|
||||
|
||||
# set a sudo mode to perform API calls as another user
|
||||
Gitlab.sudo = 'other_user'
|
||||
# => "other_user"
|
||||
|
||||
# disable a sudo mode
|
||||
Gitlab.sudo = nil
|
||||
# => nil
|
||||
```
|
||||
|
||||
For more information, refer to [documentation](http://rubydoc.info/gems/gitlab/frames).
|
||||
|
||||
## CLI
|
||||
|
||||
Usage examples:
|
||||
|
||||
```sh
|
||||
# list users
|
||||
gitlab users
|
||||
|
||||
# get current user
|
||||
gitlab user
|
||||
|
||||
# get a user
|
||||
gitlab user 2
|
||||
|
||||
# filter output
|
||||
gitlab user --only=id,username
|
||||
|
||||
gitlab user --except=email,bio
|
||||
```
|
||||
|
||||
## CLI Shell
|
||||
|
||||
Usage examples:
|
||||
|
||||
```sh
|
||||
# start shell session
|
||||
gitlab shell
|
||||
|
||||
# list available commands
|
||||
gitlab> help
|
||||
|
||||
# list groups
|
||||
gitlab> groups
|
||||
|
||||
# protect a branch
|
||||
gitlab> protect_branch 1 master
|
||||
```
|
||||
|
||||
For more information, refer to [website](http://narkoz.github.io/gitlab).
|
||||
|
||||
## License
|
||||
|
||||
Released under the BSD 2-clause license. See LICENSE.txt for details.
|
|
@ -0,0 +1,9 @@
|
|||
require "bundler/gem_tasks"
|
||||
|
||||
require 'rspec/core/rake_task'
|
||||
RSpec::Core::RakeTask.new(:spec) do |spec|
|
||||
spec.pattern = FileList['spec/**/*_spec.rb']
|
||||
spec.rspec_opts = ['--color', '--format d']
|
||||
end
|
||||
|
||||
task :default => :spec
|
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
$:.unshift File.expand_path('../../lib', __FILE__)
|
||||
|
||||
require 'gitlab/cli'
|
||||
|
||||
Gitlab::CLI.start(ARGV)
|
|
@ -0,0 +1,26 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
lib = File.expand_path('../lib', __FILE__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
require 'gitlab/version'
|
||||
|
||||
Gem::Specification.new do |gem|
|
||||
gem.name = "gitlab"
|
||||
gem.version = Gitlab::VERSION
|
||||
gem.authors = ["Nihad Abbasov"]
|
||||
gem.email = ["mail@narkoz.me"]
|
||||
gem.description = %q{Ruby client and CLI for GitLab API}
|
||||
gem.summary = %q{A Ruby wrapper and CLI for the GitLab API}
|
||||
gem.homepage = "https://github.com/narkoz/gitlab"
|
||||
|
||||
gem.files = `git ls-files`.split($/)
|
||||
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
||||
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
||||
gem.require_paths = ["lib"]
|
||||
|
||||
gem.add_runtime_dependency 'httparty'
|
||||
gem.add_runtime_dependency 'terminal-table'
|
||||
|
||||
gem.add_development_dependency 'rake'
|
||||
gem.add_development_dependency 'rspec'
|
||||
gem.add_development_dependency 'webmock'
|
||||
end
|
|
@ -0,0 +1,37 @@
|
|||
require 'gitlab/version'
|
||||
require 'gitlab/objectified_hash'
|
||||
require 'gitlab/configuration'
|
||||
require 'gitlab/error'
|
||||
require 'gitlab/request'
|
||||
require 'gitlab/api'
|
||||
require 'gitlab/client'
|
||||
|
||||
module Gitlab
|
||||
extend Configuration
|
||||
|
||||
# Alias for Gitlab::Client.new
|
||||
#
|
||||
# @return [Gitlab::Client]
|
||||
def self.client(options={})
|
||||
Gitlab::Client.new(options)
|
||||
end
|
||||
|
||||
# Delegate to Gitlab::Client
|
||||
def self.method_missing(method, *args, &block)
|
||||
return super unless client.respond_to?(method)
|
||||
client.send(method, *args, &block)
|
||||
end
|
||||
|
||||
# Delegate to Gitlab::Client
|
||||
def self.respond_to?(method)
|
||||
return client.respond_to?(method) || super
|
||||
end
|
||||
|
||||
# Returns an unsorted array of available client methods.
|
||||
#
|
||||
# @return [Array<Symbol>]
|
||||
def self.actions
|
||||
hidden = /endpoint|private_token|user_agent|sudo|get|post|put|\Adelete\z|validate|set_request_defaults/
|
||||
(Gitlab::Client.instance_methods - Object.methods).reject {|e| e[hidden]}
|
||||
end
|
||||
end
|
|
@ -0,0 +1,17 @@
|
|||
module Gitlab
|
||||
# @private
|
||||
class API < Request
|
||||
# @private
|
||||
attr_accessor(*Configuration::VALID_OPTIONS_KEYS)
|
||||
|
||||
# Creates a new API.
|
||||
# @raise [Error:MissingCredentials]
|
||||
def initialize(options={})
|
||||
options = Gitlab.options.merge(options)
|
||||
Configuration::VALID_OPTIONS_KEYS.each do |key|
|
||||
send("#{key}=", options[key])
|
||||
end
|
||||
set_request_defaults @endpoint, @private_token, @sudo
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,47 @@
|
|||
require 'gitlab'
|
||||
require 'terminal-table/import'
|
||||
require_relative 'cli_helpers'
|
||||
require_relative 'shell'
|
||||
|
||||
class Gitlab::CLI
|
||||
extend Helpers
|
||||
|
||||
def self.start(args)
|
||||
command = args.shift.strip rescue 'help'
|
||||
run(command, args)
|
||||
end
|
||||
|
||||
def self.run(cmd, args=[])
|
||||
case cmd
|
||||
when 'help'
|
||||
puts actions_table
|
||||
when 'info'
|
||||
endpoint = Gitlab.endpoint ? Gitlab.endpoint : 'not set'
|
||||
private_token = Gitlab.private_token ? Gitlab.private_token : 'not set'
|
||||
puts "Gitlab endpoint is #{endpoint}"
|
||||
puts "Gitlab private token is #{private_token}"
|
||||
puts "Ruby Version is #{RUBY_VERSION}"
|
||||
puts "Gitlab Ruby Gem #{Gitlab::VERSION}"
|
||||
when '-v', '--version'
|
||||
puts "Gitlab Ruby Gem #{Gitlab::VERSION}"
|
||||
when 'shell'
|
||||
Gitlab::Shell.start
|
||||
else
|
||||
unless valid_command?(cmd)
|
||||
puts "Unknown command. Run `gitlab help` for a list of available commands."
|
||||
exit(1)
|
||||
end
|
||||
|
||||
if args.any? && (args.last.start_with?('--only=') || args.last.start_with?('--except='))
|
||||
command_args = args[0..-2]
|
||||
else
|
||||
command_args = args
|
||||
end
|
||||
|
||||
confirm_command(cmd)
|
||||
|
||||
data = gitlab_helper(cmd, command_args) { exit(1) }
|
||||
output_table(cmd, args, data)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,175 @@
|
|||
class Gitlab::CLI
|
||||
# Defines methods related to CLI output and formatting.
|
||||
module Helpers
|
||||
extend self
|
||||
|
||||
# Returns filtered required fields.
|
||||
#
|
||||
# @return [Array]
|
||||
def required_fields(args)
|
||||
if args.any? && args.last.start_with?('--only=')
|
||||
args.last.gsub('--only=', '').split(',')
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
# Returns filtered excluded fields.
|
||||
#
|
||||
# @return [Array]
|
||||
def excluded_fields(args)
|
||||
if args.any? && args.last.start_with?('--except=')
|
||||
args.last.gsub('--except=', '').split(',')
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
# Confirms command is valid.
|
||||
#
|
||||
# @return [Boolean]
|
||||
def valid_command?(cmd)
|
||||
command = cmd.is_a?(Symbol) ? cmd : cmd.to_sym
|
||||
Gitlab.actions.include?(command)
|
||||
end
|
||||
|
||||
# Confirms command with a desctructive action.
|
||||
#
|
||||
# @return [String]
|
||||
def confirm_command(cmd)
|
||||
if cmd.start_with?('remove_') || cmd.start_with?('delete_')
|
||||
puts "Are you sure? (y/n)"
|
||||
if %w(y yes).include?($stdin.gets.to_s.strip.downcase)
|
||||
puts 'Proceeding..'
|
||||
else
|
||||
puts 'Command aborted.'
|
||||
exit(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Table with available commands.
|
||||
#
|
||||
# @return [String]
|
||||
def actions_table
|
||||
client = Gitlab::Client.new(endpoint: '')
|
||||
actions = Gitlab.actions
|
||||
methods = []
|
||||
|
||||
actions.each do |action|
|
||||
methods << {
|
||||
name: action,
|
||||
owner: client.method(action).owner.to_s.gsub('Gitlab::Client::', '')
|
||||
}
|
||||
end
|
||||
|
||||
owners = methods.map {|m| m[:owner]}.uniq.sort
|
||||
methods_c = methods.group_by {|m| m[:owner]}
|
||||
methods_c = methods_c.map {|_, v| [_, v.sort_by {|hv| hv[:name]}] }
|
||||
methods_c = Hash[methods_c.sort_by(&:first).map {|k, v| [k, v]}]
|
||||
max_column_length = methods_c.values.max_by(&:size).size
|
||||
|
||||
rows = max_column_length.times.map do |i|
|
||||
methods_c.keys.map do |key|
|
||||
methods_c[key][i] ? methods_c[key][i][:name] : ''
|
||||
end
|
||||
end
|
||||
|
||||
table do |t|
|
||||
t.title = "Available commands (#{actions.size} total)"
|
||||
t.headings = owners
|
||||
|
||||
rows.each do |row|
|
||||
t.add_row row
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Decides which table to use.
|
||||
#
|
||||
# @return [String]
|
||||
def output_table(cmd, args, data)
|
||||
case data
|
||||
when Gitlab::ObjectifiedHash
|
||||
puts single_record_table(data, cmd, args)
|
||||
when Array
|
||||
puts multiple_record_table(data, cmd, args)
|
||||
else
|
||||
puts data.inspect
|
||||
end
|
||||
end
|
||||
|
||||
# Table for a single record.
|
||||
#
|
||||
# @return [String]
|
||||
def single_record_table(data, cmd, args)
|
||||
hash = data.to_h
|
||||
keys = hash.keys.sort {|x, y| x.to_s <=> y.to_s }
|
||||
keys = keys & required_fields(args) if required_fields(args).any?
|
||||
keys = keys - excluded_fields(args)
|
||||
|
||||
table do |t|
|
||||
t.title = "Gitlab.#{cmd} #{args.join(', ')}"
|
||||
|
||||
keys.each_with_index do |key, index|
|
||||
case value = hash[key]
|
||||
when Hash
|
||||
value = 'Hash'
|
||||
when nil
|
||||
value = 'null'
|
||||
end
|
||||
|
||||
t.add_row [key, value]
|
||||
t.add_separator unless keys.size - 1 == index
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Table for multiple records.
|
||||
#
|
||||
# @return [String]
|
||||
def multiple_record_table(data, cmd, args)
|
||||
return 'No data' if data.empty?
|
||||
|
||||
arr = data.map(&:to_h)
|
||||
keys = arr.first.keys.sort {|x, y| x.to_s <=> y.to_s }
|
||||
keys = keys & required_fields(args) if required_fields(args).any?
|
||||
keys = keys - excluded_fields(args)
|
||||
|
||||
table do |t|
|
||||
t.title = "Gitlab.#{cmd} #{args.join(', ')}"
|
||||
t.headings = keys
|
||||
|
||||
arr.each_with_index do |hash, index|
|
||||
values = []
|
||||
|
||||
keys.each do |key|
|
||||
case value = hash[key]
|
||||
when Hash
|
||||
value = 'Hash'
|
||||
when nil
|
||||
value = 'null'
|
||||
end
|
||||
|
||||
values << value
|
||||
end
|
||||
|
||||
t.add_row values
|
||||
t.add_separator unless arr.size - 1 == index
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Helper function to call Gitlab commands with args.
|
||||
def gitlab_helper(cmd, args=[])
|
||||
begin
|
||||
data = args.any? ? Gitlab.send(cmd, *args) : Gitlab.send(cmd)
|
||||
rescue => e
|
||||
puts e.message
|
||||
yield if block_given?
|
||||
end
|
||||
|
||||
data
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,18 @@
|
|||
module Gitlab
|
||||
# Wrapper for the Gitlab REST API.
|
||||
class Client < API
|
||||
Dir[File.expand_path('../client/*.rb', __FILE__)].each {|f| require f}
|
||||
|
||||
include Branches
|
||||
include Groups
|
||||
include Issues
|
||||
include MergeRequests
|
||||
include Milestones
|
||||
include Notes
|
||||
include Projects
|
||||
include Repositories
|
||||
include Snippets
|
||||
include SystemHooks
|
||||
include Users
|
||||
end
|
||||
end
|
|
@ -0,0 +1,79 @@
|
|||
class Gitlab::Client
|
||||
# Defines methods related to repositories.
|
||||
module Branches
|
||||
# Gets a list of project repositiory branches.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.branches(42)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def branches(project, options={})
|
||||
get("/projects/#{project}/repository/branches", :query => options)
|
||||
end
|
||||
alias_method :repo_branches, :branches
|
||||
|
||||
# Gets information about a repository branch.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.branch(3, 'api')
|
||||
# Gitlab.repo_branch(5, 'master')
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [String] branch The name of the branch.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def branch(project, branch)
|
||||
get("/projects/#{project}/repository/branches/#{branch}")
|
||||
end
|
||||
|
||||
alias_method :repo_branch, :branch
|
||||
|
||||
# Protects a repository branch.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.protect_branch(3, 'api')
|
||||
# Gitlab.repo_protect_branch(5, 'master')
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [String] branch The name of the branch.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def protect_branch(project, branch)
|
||||
put("/projects/#{project}/repository/branches/#{branch}/protect")
|
||||
end
|
||||
alias_method :repo_protect_branch, :protect_branch
|
||||
|
||||
# Unprotects a repository branch.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.unprotect_branch(3, 'api')
|
||||
# Gitlab.repo_unprotect_branch(5, 'master')
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [String] branch The name of the branch.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def unprotect_branch(project, branch)
|
||||
put("/projects/#{project}/repository/branches/#{branch}/unprotect")
|
||||
end
|
||||
alias_method :repo_unprotect_branch, :unprotect_branch
|
||||
|
||||
# Creates a repository branch. Requires Gitlab >= 6.8.x
|
||||
#
|
||||
# @example
|
||||
# Gitlab.create_branch(3, 'api')
|
||||
# Gitlab.repo_create_branch(5, 'master')
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [String] branch The name of the new branch.
|
||||
# @param [String] ref Create branch from commit sha or existing branch
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def create_branch(project, branch, ref)
|
||||
post("/projects/#{project}/repository/branches",:body => {:branch_name => branch, :ref => ref})
|
||||
end
|
||||
alias_method :repo_create_branch, :create_branch
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
class Gitlab::Client
|
||||
# Defines methods related to groups.
|
||||
module Groups
|
||||
# Gets a list of groups.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.groups
|
||||
# Gitlab.groups(:per_page => 40)
|
||||
#
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def groups(options={})
|
||||
get("/groups", :query => options)
|
||||
end
|
||||
|
||||
# Gets a single group.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.group(42)
|
||||
#
|
||||
# @param [Integer] id The ID of a group.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def group(id)
|
||||
get("/groups/#{id}")
|
||||
end
|
||||
|
||||
# Creates a new group.
|
||||
#
|
||||
# @param [String] name The name of a group.
|
||||
# @param [String] path The path of a group.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created group.
|
||||
def create_group(name, path)
|
||||
body = {:name => name, :path => path}
|
||||
post("/groups", :body => body)
|
||||
end
|
||||
|
||||
# Get a list of group members.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.group_members(1)
|
||||
# Gitlab.group_members(1, :per_page => 40)
|
||||
#
|
||||
# @param [Integer] id The ID of a group.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def group_members(id, options={})
|
||||
get("/groups/#{id}/members", :query => options)
|
||||
end
|
||||
|
||||
# Adds a user to group.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.add_group_member(1, 2, 40)
|
||||
#
|
||||
# @param [Integer] team_id The group id to add a member to.
|
||||
# @param [Integer] user_id The user id of the user to add to the team.
|
||||
# @param [Integer] access_level Project access level.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about added team member.
|
||||
def add_group_member(team_id, user_id, access_level)
|
||||
post("/groups/#{team_id}/members", :body => {:user_id => user_id, :access_level => access_level})
|
||||
end
|
||||
|
||||
# Removes user from user group.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.remove_group_member(1, 2)
|
||||
#
|
||||
# @param [Integer] team_id The group ID.
|
||||
# @param [Integer] user_id The ID of a user.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about removed team member.
|
||||
def remove_group_member(team_id, user_id)
|
||||
delete("/groups/#{team_id}/members/#{user_id}")
|
||||
end
|
||||
|
||||
# Transfers a project to a group
|
||||
#
|
||||
# @param [Integer] id The ID of a group.
|
||||
# @param [Integer] project_id The ID of a project.
|
||||
def transfer_project_to_group(id, project_id)
|
||||
body = {:id => id, :project_id => project_id}
|
||||
post("/groups/#{id}/projects/#{project_id}", :body => body)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,92 @@
|
|||
class Gitlab::Client
|
||||
# Defines methods related to issues.
|
||||
module Issues
|
||||
# Gets a list of user's issues.
|
||||
# Will return a list of project's issues if project ID passed.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.issues
|
||||
# Gitlab.issues(5)
|
||||
# Gitlab.issues(:per_page => 40)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def issues(project=nil, options={})
|
||||
if project.to_i.zero?
|
||||
get("/issues", :query => options)
|
||||
else
|
||||
get("/projects/#{project}/issues", :query => options)
|
||||
end
|
||||
end
|
||||
|
||||
# Gets a single issue.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.issue(5, 42)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of an issue.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def issue(project, id)
|
||||
get("/projects/#{project}/issues/#{id}")
|
||||
end
|
||||
|
||||
# Creates a new issue.
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [String] title The title of an issue.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [String] :description The description of an issue.
|
||||
# @option options [Integer] :assignee_id The ID of a user to assign issue.
|
||||
# @option options [Integer] :milestone_id The ID of a milestone to assign issue.
|
||||
# @option options [String] :labels Comma-separated label names for an issue.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created issue.
|
||||
def create_issue(project, title, options={})
|
||||
body = {:title => title}.merge(options)
|
||||
post("/projects/#{project}/issues", :body => body)
|
||||
end
|
||||
|
||||
# Updates an issue.
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of an issue.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [String] :title The title of an issue.
|
||||
# @option options [String] :description The description of an issue.
|
||||
# @option options [Integer] :assignee_id The ID of a user to assign issue.
|
||||
# @option options [Integer] :milestone_id The ID of a milestone to assign issue.
|
||||
# @option options [String] :labels Comma-separated label names for an issue.
|
||||
# @option options [String] :state_event The state event of an issue ('close' or 'reopen').
|
||||
# @return [Gitlab::ObjectifiedHash] Information about updated issue.
|
||||
def edit_issue(project, id, options={})
|
||||
put("/projects/#{project}/issues/#{id}", :body => options)
|
||||
end
|
||||
|
||||
# Closes an issue.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.close_issue(3, 42)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of an issue.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about closed issue.
|
||||
def close_issue(project, id)
|
||||
put("/projects/#{project}/issues/#{id}", :body => {:state_event => 'close'})
|
||||
end
|
||||
|
||||
# Reopens an issue.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.reopen_issue(3, 42)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of an issue.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about reopened issue.
|
||||
def reopen_issue(project, id)
|
||||
put("/projects/#{project}/issues/#{id}", :body => {:state_event => 'reopen'})
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,107 @@
|
|||
class Gitlab::Client
|
||||
# Defines methods related to merge requests.
|
||||
module MergeRequests
|
||||
# Gets a list of project merge requests.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.merge_requests(5)
|
||||
# Gitlab.merge_requests(:per_page => 40)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def merge_requests(project, options={})
|
||||
get("/projects/#{project}/merge_requests", :query => options)
|
||||
end
|
||||
|
||||
# Gets a single merge request.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.merge_request(5, 36)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of a merge request.
|
||||
# @return <Gitlab::ObjectifiedHash]
|
||||
def merge_request(project, id)
|
||||
get("/projects/#{project}/merge_request/#{id}")
|
||||
end
|
||||
|
||||
# Creates a merge request.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.create_merge_request(5, 'New merge request',
|
||||
# :source_branch => 'source_branch', :target_branch => 'target_branch')
|
||||
# Gitlab.create_merge_request(5, 'New merge request',
|
||||
# :source_branch => 'source_branch', :target_branch => 'target_branch', :assignee_id => 42)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [String] title The title of a merge request.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [String] :source_branch (required) The source branch name.
|
||||
# @option options [String] :target_branch (required) The target branch name.
|
||||
# @option options [Integer] :assignee_id (optional) The ID of a user to assign merge request.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created merge request.
|
||||
def create_merge_request(project, title, options={})
|
||||
check_attributes!(options, [:source_branch, :target_branch])
|
||||
|
||||
body = {:title => title}.merge(options)
|
||||
post("/projects/#{project}/merge_requests", :body => body)
|
||||
end
|
||||
|
||||
# Updates a merge request.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.update_merge_request(5, 42, :title => 'New title')
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of a merge request.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [String] :title The title of a merge request.
|
||||
# @option options [String] :source_branch The source branch name.
|
||||
# @option options [String] :target_branch The target branch name.
|
||||
# @option options [Integer] :assignee_id The ID of a user to assign merge request.
|
||||
# @option options [String] :state_event New state (close|reopen|merge).
|
||||
# @return [Gitlab::ObjectifiedHash] Information about updated merge request.
|
||||
def update_merge_request(project, id, options={})
|
||||
put("/projects/#{project}/merge_request/#{id}", :body => options)
|
||||
end
|
||||
|
||||
# Adds a comment to a merge request.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.create_merge_request_comment(5, 1, "Awesome merge!")
|
||||
# Gitlab.create_merge_request_comment('gitlab', 1, "Awesome merge!")
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of a merge request.
|
||||
# @param [String] note The content of a comment.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created merge request comment.
|
||||
def create_merge_request_comment(project, id, note)
|
||||
post("/projects/#{project}/merge_request/#{id}/comments", :body => {:note => note})
|
||||
end
|
||||
|
||||
# Gets the comments on a merge request.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.merge_request_comments(5, 1)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of a merge request.
|
||||
# @return [Gitlab::ObjectifiedHash] The merge request's comments.
|
||||
def merge_request_comments(project, id)
|
||||
get("/projects/#{project}/merge_request/#{id}/comments")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_attributes!(options, attrs)
|
||||
attrs.each do |attr|
|
||||
unless options.has_key?(attr) || options.has_key?(attr.to_s)
|
||||
raise Gitlab::Error::MissingAttributes.new("Missing '#{attr}' parameter")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,57 @@
|
|||
class Gitlab::Client
|
||||
# Defines methods related to milestones.
|
||||
module Milestones
|
||||
# Gets a list of project's milestones.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.milestones(5)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def milestones(project, options={})
|
||||
get("/projects/#{project}/milestones", :query => options)
|
||||
end
|
||||
|
||||
# Gets a single milestone.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.milestone(5, 36)
|
||||
#
|
||||
# @param [Integer, String] project The ID of a project.
|
||||
# @param [Integer] id The ID of a milestone.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def milestone(project, id)
|
||||
get("/projects/#{project}/milestones/#{id}")
|
||||
end
|
||||
|
||||
# Creates a new milestone.
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [String] title The title of a milestone.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [String] :description The description of a milestone.
|
||||
# @option options [String] :due_date The due date of a milestone.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created milestone.
|
||||
def create_milestone(project, title, options={})
|
||||
body = {:title => title}.merge(options)
|
||||
post("/projects/#{project}/milestones", :body => body)
|
||||
end
|
||||
|
||||
# Updates a milestone.
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of a milestone.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [String] :title The title of a milestone.
|
||||
# @option options [String] :description The description of a milestone.
|
||||
# @option options [String] :due_date The due date of a milestone.
|
||||
# @option options [String] :state_event The state of a milestone ('close' or 'activate').
|
||||
# @return [Gitlab::ObjectifiedHash] Information about updated milestone.
|
||||
def edit_milestone(project, id, options={})
|
||||
put("/projects/#{project}/milestones/#{id}", :body => options)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,106 @@
|
|||
class Gitlab::Client
|
||||
# Defines methods related to notes.
|
||||
module Notes
|
||||
# Gets a list of projects notes.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.notes(5)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def notes(project)
|
||||
get("/projects/#{project}/notes")
|
||||
end
|
||||
|
||||
# Gets a list of notes for a issue.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.issue_notes(5, 10)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] issue The ID of an issue.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def issue_notes(project, issue)
|
||||
get("/projects/#{project}/issues/#{issue}/notes")
|
||||
end
|
||||
|
||||
# Gets a list of notes for a snippet.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.snippet_notes(5, 1)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] snippet The ID of a snippet.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def snippet_notes(project, snippet)
|
||||
get("/projects/#{project}/snippets/#{snippet}/notes")
|
||||
end
|
||||
|
||||
# Gets a single wall note.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.note(5, 15)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of a note.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def note(project, id)
|
||||
get("/projects/#{project}/notes/#{id}")
|
||||
end
|
||||
|
||||
# Gets a single issue note.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.issue_note(5, 10, 1)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] issue The ID of an issue.
|
||||
# @param [Integer] id The ID of a note.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def issue_note(project, issue, id)
|
||||
get("/projects/#{project}/issues/#{issue}/notes/#{id}")
|
||||
end
|
||||
|
||||
# Gets a single snippet note.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.snippet_note(5, 11, 3)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] snippet The ID of a snippet.
|
||||
# @param [Integer] id The ID of an note.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def snippet_note(project, snippet, id)
|
||||
get("/projects/#{project}/snippets/#{snippet}/notes/#{id}")
|
||||
end
|
||||
|
||||
# Creates a new wall note.
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [String] body The body of a note.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created note.
|
||||
def create_note(project, body)
|
||||
post("/projects/#{project}/notes", :body => {:body => body})
|
||||
end
|
||||
|
||||
# Creates a new issue note.
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] issue The ID of an issue.
|
||||
# @param [String] body The body of a note.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created note.
|
||||
def create_issue_note(project, issue, body)
|
||||
post("/projects/#{project}/issues/#{issue}/notes", :body => {:body => body})
|
||||
end
|
||||
|
||||
# Creates a new snippet note.
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] snippet The ID of a snippet.
|
||||
# @param [String] body The body of a note.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created note.
|
||||
def create_snippet_note(project, snippet, body)
|
||||
post("/projects/#{project}/snippets/#{snippet}/notes", :body => {:body => body})
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,300 @@
|
|||
class Gitlab::Client
|
||||
# Defines methods related to projects.
|
||||
module Projects
|
||||
# Gets a list of projects owned by the authenticated user.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.projects
|
||||
#
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @option options [String] :scope Scope of projects. 'owned' for list of projects owned by the authenticated user, 'all' to get all projects (admin only)
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def projects(options={})
|
||||
if (options[:scope])
|
||||
get("/projects/#{options[:scope]}", :query => options)
|
||||
else
|
||||
get("/projects", :query => options)
|
||||
end
|
||||
end
|
||||
|
||||
# Gets information about a project.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.project(3)
|
||||
# Gitlab.project('gitlab')
|
||||
#
|
||||
# @param [Integer, String] id The ID or name of a project.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def project(id)
|
||||
get("/projects/#{id}")
|
||||
end
|
||||
|
||||
# Gets a list of project events.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.project_events(42)
|
||||
# Gitlab.project_events('gitlab')
|
||||
#
|
||||
# @param [Integer, String] project The ID or name of a project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def project_events(project, options={})
|
||||
get("/projects/#{project}/events", :query => options)
|
||||
end
|
||||
|
||||
# Creates a new project.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.create_project('gitlab')
|
||||
# Gitlab.create_project('viking', :description => 'Awesome project')
|
||||
# Gitlab.create_project('Red', :wall_enabled => false)
|
||||
#
|
||||
# @param [String] name The name of a project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [String] :description The description of a project.
|
||||
# @option options [String] :default_branch The default branch of a project.
|
||||
# @option options [String] :group_id The group in which to create a project.
|
||||
# @option options [String] :namespace_id The namespace in which to create a project.
|
||||
# @option options [Boolean] :wiki_enabled The wiki integration for a project (0 = false, 1 = true).
|
||||
# @option options [Boolean] :wall_enabled The wall functionality for a project (0 = false, 1 = true).
|
||||
# @option options [Boolean] :issues_enabled The issues integration for a project (0 = false, 1 = true).
|
||||
# @option options [Boolean] :snippets_enabled The snippets integration for a project (0 = false, 1 = true).
|
||||
# @option options [Boolean] :merge_requests_enabled The merge requests functionality for a project (0 = false, 1 = true).
|
||||
# @option options [Boolean] :public The setting for making a project public (0 = false, 1 = true).
|
||||
# @option options [Integer] :user_id The user/owner id of a project.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created project.
|
||||
def create_project(name, options={})
|
||||
url = options[:user_id] ? "/projects/user/#{options[:user_id]}" : "/projects"
|
||||
post(url, :body => {:name => name}.merge(options))
|
||||
end
|
||||
|
||||
# Deletes a project.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.delete_project(4)
|
||||
#
|
||||
# @param [Integer, String] id The ID or name of a project.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about deleted project.
|
||||
def delete_project(id)
|
||||
delete("/projects/#{id}")
|
||||
end
|
||||
|
||||
# Gets a list of project team members.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.team_members(42)
|
||||
# Gitlab.team_members('gitlab')
|
||||
#
|
||||
# @param [Integer, String] project The ID or name of a project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [String] :query The search query.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def team_members(project, options={})
|
||||
get("/projects/#{project}/members", :query => options)
|
||||
end
|
||||
|
||||
# Gets a project team member.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.team_member('gitlab', 2)
|
||||
#
|
||||
# @param [Integer, String] project The ID or name of a project.
|
||||
# @param [Integer] id The ID of a project team member.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def team_member(project, id)
|
||||
get("/projects/#{project}/members/#{id}")
|
||||
end
|
||||
|
||||
# Adds a user to project team.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.add_team_member('gitlab', 2, 40)
|
||||
#
|
||||
# @param [Integer, String] project The ID or name of a project.
|
||||
# @param [Integer] id The ID of a user.
|
||||
# @param [Integer] access_level The access level to project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about added team member.
|
||||
def add_team_member(project, id, access_level)
|
||||
post("/projects/#{project}/members", :body => {:user_id => id, :access_level => access_level})
|
||||
end
|
||||
|
||||
# Updates a team member's project access level.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.edit_team_member('gitlab', 3, 20)
|
||||
#
|
||||
# @param [Integer, String] project The ID or name of a project.
|
||||
# @param [Integer] id The ID of a user.
|
||||
# @param [Integer] access_level The access level to project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>] Information about updated team member.
|
||||
def edit_team_member(project, id, access_level)
|
||||
put("/projects/#{project}/members/#{id}", :body => {:access_level => access_level})
|
||||
end
|
||||
|
||||
# Removes a user from project team.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.remove_team_member('gitlab', 2)
|
||||
#
|
||||
# @param [Integer, String] project The ID or name of a project.
|
||||
# @param [Integer] id The ID of a user.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about removed team member.
|
||||
def remove_team_member(project, id)
|
||||
delete("/projects/#{project}/members/#{id}")
|
||||
end
|
||||
|
||||
# Gets a list of project hooks.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.project_hooks(42)
|
||||
# Gitlab.project_hooks('gitlab')
|
||||
#
|
||||
# @param [Integer, String] project The ID or name of a project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def project_hooks(project, options={})
|
||||
get("/projects/#{project}/hooks", :query => options)
|
||||
end
|
||||
|
||||
# Gets a project hook.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.project_hook(42, 5)
|
||||
# Gitlab.project_hook('gitlab', 5)
|
||||
#
|
||||
# @param [Integer, String] project The ID or name of a project.
|
||||
# @param [Integer] id The ID of a hook.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def project_hook(project, id)
|
||||
get("/projects/#{project}/hooks/#{id}")
|
||||
end
|
||||
|
||||
# Adds a new hook to the project.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.add_project_hook(42, 'https://api.example.net/v1/webhooks/ci')
|
||||
#
|
||||
# @param [Integer, String] project The ID or name of a project.
|
||||
# @param [String] url The hook URL.
|
||||
# @param [Hash] options Events list (`{push_events: true, merge_requests_events: false}`).
|
||||
# @return [Gitlab::ObjectifiedHash] Information about added hook.
|
||||
def add_project_hook(project, url, options = {})
|
||||
available_events = [:push_events, :merge_requests_events, :issues_events]
|
||||
passed_events = available_events.select { |event| options[event] }
|
||||
events = Hash[passed_events.map { |event| [event, options[event]] }]
|
||||
|
||||
post("/projects/#{project}/hooks", :body => {:url => url}.merge(events))
|
||||
end
|
||||
|
||||
# Updates a project hook URL.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.edit_project_hook(42, 1, 'https://api.example.net/v1/webhooks/ci')
|
||||
#
|
||||
# @param [Integer, String] project The ID or name of a project.
|
||||
# @param [Integer] id The ID of the hook.
|
||||
# @param [String] url The hook URL.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about updated hook.
|
||||
def edit_project_hook(project, id, url)
|
||||
put("/projects/#{project}/hooks/#{id}", :body => {:url => url})
|
||||
end
|
||||
|
||||
# Deletes a hook from project.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.delete_project_hook('gitlab', 4)
|
||||
#
|
||||
# @param [Integer, String] project The ID or name of a project.
|
||||
# @param [String] id The ID of the hook.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about deleted hook.
|
||||
def delete_project_hook(project, id)
|
||||
delete("/projects/#{project}/hooks/#{id}")
|
||||
end
|
||||
|
||||
# Mark this project as forked from the other
|
||||
#
|
||||
# @example
|
||||
# Gitlab.make_forked(42, 24)
|
||||
#
|
||||
# @param [Integer, String] project The ID or name of a project.
|
||||
# @param [Integer] id The ID of the project it is forked from.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about the forked project.
|
||||
def make_forked_from(project, id)
|
||||
post("/projects/#{project}/fork/#{id}")
|
||||
end
|
||||
|
||||
# Remove a forked_from relationship for a project.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.remove_forked(42)
|
||||
#
|
||||
# @param [Integer, String] project The ID or name of a project.
|
||||
# @param [Integer] project The ID of the project it is forked from
|
||||
# @return [Gitlab::ObjectifiedHash] Information about the forked project.
|
||||
def remove_forked(project)
|
||||
delete("/projects/#{project}/fork")
|
||||
end
|
||||
|
||||
# Gets a project deploy keys.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.deploy_keys(42)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def deploy_keys(project, options={})
|
||||
get("/projects/#{project}/keys", :query => options)
|
||||
end
|
||||
|
||||
# Gets a single project deploy key.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.deploy_key(42, 1)
|
||||
#
|
||||
# @param [Integer, String] project The ID of a project.
|
||||
# @param [Integer] id The ID of a deploy key.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def deploy_key(project, id)
|
||||
get("/projects/#{project}/keys/#{id}")
|
||||
end
|
||||
|
||||
# Creates a new deploy key.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.create_deploy_key(42, 'My Key', 'Key contents')
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [String] title The title of a deploy key.
|
||||
# @param [String] key The content of a deploy key.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created deploy key.
|
||||
def create_deploy_key(project, title, key)
|
||||
post("/projects/#{project}/keys", body: {title: title, key: key})
|
||||
end
|
||||
|
||||
# Deletes a deploy key from project.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.delete_deploy_key(42, 1)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of a deploy key.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about deleted deploy key.
|
||||
def delete_deploy_key(project, id)
|
||||
delete("/projects/#{project}/keys/#{id}")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,89 @@
|
|||
class Gitlab::Client
|
||||
# Defines methods related to repositories.
|
||||
module Repositories
|
||||
|
||||
def trees(project, options={})
|
||||
get "/projects/#{project}/repository/tree", query: options
|
||||
end
|
||||
alias_method :repo_trees, :trees
|
||||
|
||||
def files(project, file_path, ref)
|
||||
get "/projects/#{project}/repository/files", query: {file_path: file_path, ref: ref}
|
||||
end
|
||||
alias_method :repo_files, :files
|
||||
|
||||
# Gets a list of project repository tags.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.tags(42)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def tags(project, options={})
|
||||
get("/projects/#{project}/repository/tags", :query => options)
|
||||
end
|
||||
alias_method :repo_tags, :tags
|
||||
|
||||
# Creates a new project repository tag.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.create_tag(42,'new_tag','master')
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [String] tag_name The name of the new tag.
|
||||
# @param [String] ref The ref (commit sha, branch name, or another tag) the tag will point to.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def create_tag(project, tag_name, ref)
|
||||
post("/projects/#{project}/repository/tags", body: {tag_name: tag_name, ref: ref})
|
||||
end
|
||||
alias_method :repo_create_tag, :create_tag
|
||||
|
||||
# Gets a list of project commits.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.commits('viking')
|
||||
# Gitlab.repo_commits('gitlab', :ref_name => 'api')
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [String] :ref_name The branch or tag name of a project repository.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def commits(project, options={})
|
||||
get("/projects/#{project}/repository/commits", :query => options)
|
||||
end
|
||||
alias_method :repo_commits, :commits
|
||||
|
||||
# Gets a specific commit identified by the commit hash or name of a branch or tag.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.commit(42, '6104942438c14ec7bd21c6cd5bd995272b3faff6')
|
||||
# Gitlab.repo_commit(3, 'ed899a2f4b50b4370feeea94676502b42383c746')
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [String] sha The commit hash or name of a repository branch or tag
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def commit(project, sha)
|
||||
get("/projects/#{project}/repository/commits/#{sha}")
|
||||
end
|
||||
alias_method :repo_commit, :commit
|
||||
|
||||
# Get the diff of a commit in a project.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.commit_diff(42, '6104942438c14ec7bd21c6cd5bd995272b3faff6')
|
||||
# Gitlab.repo_commit_diff(3, 'ed899a2f4b50b4370feeea94676502b42383c746')
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [String] sha The name of a repository branch or tag or if not given the default branch.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def commit_diff(project, sha)
|
||||
get("/projects/#{project}/repository/commits/#{sha}/diff")
|
||||
end
|
||||
alias_method :repo_commit_diff, :commit_diff
|
||||
end
|
||||
end
|
|
@ -0,0 +1,86 @@
|
|||
class Gitlab::Client
|
||||
# Defines methods related to snippets.
|
||||
module Snippets
|
||||
# Gets a list of project's snippets.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.snippets(42)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def snippets(project, options={})
|
||||
get("/projects/#{project}/snippets", :query => options)
|
||||
end
|
||||
|
||||
# Gets information about a snippet.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.snippet(2, 14)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of a snippet.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def snippet(project, id)
|
||||
get("/projects/#{project}/snippets/#{id}")
|
||||
end
|
||||
|
||||
# Creates a new snippet.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.create_snippet(42, {:title => 'REST', :file_name => 'api.rb', :code => 'some code'})
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [String] :title (required) The title of a snippet.
|
||||
# @option options [String] :file_name (required) The name of a snippet file.
|
||||
# @option options [String] :code (required) The content of a snippet.
|
||||
# @option options [String] :lifetime (optional) The expiration date of a snippet.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created snippet.
|
||||
def create_snippet(project, options={})
|
||||
check_attributes!(options, [:title, :file_name, :code])
|
||||
post("/projects/#{project}/snippets", :body => options)
|
||||
end
|
||||
|
||||
# Updates a snippet.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.edit_snippet(42, 34, :file_name => 'README.txt')
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of a snippet.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [String] :title The title of a snippet.
|
||||
# @option options [String] :file_name The name of a snippet file.
|
||||
# @option options [String] :code The content of a snippet.
|
||||
# @option options [String] :lifetime The expiration date of a snippet.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about updated snippet.
|
||||
def edit_snippet(project, id, options={})
|
||||
put("/projects/#{project}/snippets/#{id}", :body => options)
|
||||
end
|
||||
|
||||
# Deletes a snippet.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.delete_snippet(2, 14)
|
||||
#
|
||||
# @param [Integer] project The ID of a project.
|
||||
# @param [Integer] id The ID of a snippet.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about deleted snippet.
|
||||
def delete_snippet(project, id)
|
||||
delete("/projects/#{project}/snippets/#{id}")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_attributes!(options, attrs)
|
||||
attrs.each do |attr|
|
||||
unless options.has_key?(attr) || options.has_key?(attr.to_s)
|
||||
raise Gitlab::Error::MissingAttributes.new("Missing '#{attr}' parameter")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,58 @@
|
|||
class Gitlab::Client
|
||||
# Defines methods related to system hooks.
|
||||
module SystemHooks
|
||||
# Gets a list of system hooks.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.hooks
|
||||
# Gitlab.system_hooks
|
||||
#
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def hooks(options={})
|
||||
get("/hooks", query: options)
|
||||
end
|
||||
alias_method :system_hooks, :hooks
|
||||
|
||||
# Adds a new system hook.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.add_hook('http://example.com/hook')
|
||||
# Gitlab.add_system_hook('https://api.example.net/v1/hook')
|
||||
#
|
||||
# @param [String] url The hook URL.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def add_hook(url)
|
||||
post("/hooks", :body => {:url => url})
|
||||
end
|
||||
alias_method :add_system_hook, :add_hook
|
||||
|
||||
# Tests a system hook.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.hook(3)
|
||||
# Gitlab.system_hook(12)
|
||||
#
|
||||
# @param [Integer] id The ID of a system hook.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def hook(id)
|
||||
get("/hooks/#{id}")
|
||||
end
|
||||
alias_method :system_hook, :hook
|
||||
|
||||
# Deletes a new system hook.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.delete_hook(3)
|
||||
# Gitlab.delete_system_hook(12)
|
||||
#
|
||||
# @param [Integer] id The ID of a system hook.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def delete_hook(id)
|
||||
delete("/hooks/#{id}")
|
||||
end
|
||||
alias_method :delete_system_hook, :delete_hook
|
||||
end
|
||||
end
|
|
@ -0,0 +1,123 @@
|
|||
class Gitlab::Client
|
||||
# Defines methods related to users.
|
||||
module Users
|
||||
# Gets a list of users.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.users
|
||||
#
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def users(options={})
|
||||
get("/users", :query => options)
|
||||
end
|
||||
|
||||
# Gets information about a user.
|
||||
# Will return information about an authorized user if no ID passed.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.user
|
||||
# Gitlab.user(2)
|
||||
#
|
||||
# @param [Integer] id The ID of a user.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def user(id=nil)
|
||||
id.to_i.zero? ? get("/user") : get("/users/#{id}")
|
||||
end
|
||||
|
||||
# Creates a new user.
|
||||
# Requires authentication from an admin account.
|
||||
#
|
||||
# @param [String] email The email of a user.
|
||||
# @param [String] password The password of a user.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [String] :name The name of a user. Defaults to email.
|
||||
# @option options [String] :skype The skype of a user.
|
||||
# @option options [String] :linkedin The linkedin of a user.
|
||||
# @option options [String] :twitter The twitter of a user.
|
||||
# @option options [Integer] :projects_limit The limit of projects for a user.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created user.
|
||||
def create_user(email, password, options={})
|
||||
body = {:email => email, :password => password, :name => email}.merge(options)
|
||||
post("/users", :body => body)
|
||||
end
|
||||
|
||||
# Updates a user.
|
||||
#
|
||||
# @param [Integer] id The ID of a user.
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [String] email The email of a user.
|
||||
# @option options [String] password The password of a user.
|
||||
# @option options [String] :name The name of a user. Defaults to email.
|
||||
# @option options [String] :skype The skype of a user.
|
||||
# @option options [String] :linkedin The linkedin of a user.
|
||||
# @option options [String] :twitter The twitter of a user.
|
||||
# @option options [Integer] :projects_limit The limit of projects for a user.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created user.
|
||||
def edit_user(user_id, options={})
|
||||
put("/users/#{user_id}", :body => options)
|
||||
end
|
||||
|
||||
# Creates a new user session.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.session('jack@example.com', 'secret12345')
|
||||
#
|
||||
# @param [String] email The email of a user.
|
||||
# @param [String] password The password of a user.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
# @note This method doesn't require private_token to be set.
|
||||
def session(email, password)
|
||||
post("/session", :body => {:email => email, :password => password})
|
||||
end
|
||||
|
||||
# Gets a list of user's SSH keys.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.ssh_keys
|
||||
#
|
||||
# @param [Hash] options A customizable set of options.
|
||||
# @option options [Integer] :page The page number.
|
||||
# @option options [Integer] :per_page The number of results per page.
|
||||
# @return [Array<Gitlab::ObjectifiedHash>]
|
||||
def ssh_keys(options={})
|
||||
get("/user/keys", :query => options)
|
||||
end
|
||||
|
||||
# Gets information about SSH key.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.ssh_key(1)
|
||||
#
|
||||
# @param [Integer] id The ID of a user's SSH key.
|
||||
# @return [Gitlab::ObjectifiedHash]
|
||||
def ssh_key(id)
|
||||
get("/user/keys/#{id}")
|
||||
end
|
||||
|
||||
# Creates a new SSH key.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.create_ssh_key('key title', 'key body')
|
||||
#
|
||||
# @param [String] title The title of an SSH key.
|
||||
# @param [String] key The SSH key body.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about created SSH key.
|
||||
def create_ssh_key(title, key)
|
||||
post("/user/keys", :body => {:title => title, :key => key})
|
||||
end
|
||||
|
||||
# Deletes an SSH key.
|
||||
#
|
||||
# @example
|
||||
# Gitlab.delete_ssh_key(1)
|
||||
#
|
||||
# @param [Integer] id The ID of a user's SSH key.
|
||||
# @return [Gitlab::ObjectifiedHash] Information about deleted SSH key.
|
||||
def delete_ssh_key(id)
|
||||
delete("/user/keys/#{id}")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,39 @@
|
|||
module Gitlab
|
||||
# Defines constants and methods related to configuration.
|
||||
module Configuration
|
||||
# An array of valid keys in the options hash when configuring a Gitlab::API.
|
||||
VALID_OPTIONS_KEYS = [:endpoint, :private_token, :user_agent, :sudo, :httparty].freeze
|
||||
|
||||
# The user agent that will be sent to the API endpoint if none is set.
|
||||
DEFAULT_USER_AGENT = "Gitlab Ruby Gem #{Gitlab::VERSION}".freeze
|
||||
|
||||
# @private
|
||||
attr_accessor(*VALID_OPTIONS_KEYS)
|
||||
|
||||
# Sets all configuration options to their default values
|
||||
# when this module is extended.
|
||||
def self.extended(base)
|
||||
base.reset
|
||||
end
|
||||
|
||||
# Convenience method to allow configuration options to be set in a block.
|
||||
def configure
|
||||
yield self
|
||||
end
|
||||
|
||||
# Creates a hash of options and their values.
|
||||
def options
|
||||
VALID_OPTIONS_KEYS.inject({}) do |option, key|
|
||||
option.merge!(key => send(key))
|
||||
end
|
||||
end
|
||||
|
||||
# Resets all configuration options to the defaults.
|
||||
def reset
|
||||
self.endpoint = ENV['GITLAB_API_ENDPOINT']
|
||||
self.private_token = ENV['GITLAB_API_PRIVATE_TOKEN']
|
||||
self.sudo = nil
|
||||
self.user_agent = DEFAULT_USER_AGENT
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,42 @@
|
|||
module Gitlab
|
||||
module Error
|
||||
# Custom error class for rescuing from all Gitlab errors.
|
||||
class Error < StandardError; end
|
||||
|
||||
# Raise when attributes are missing.
|
||||
class MissingAttributes < Error; end
|
||||
|
||||
# Raised when API endpoint credentials not configured.
|
||||
class MissingCredentials < Error; end
|
||||
|
||||
# Raised when impossible to parse response body.
|
||||
class Parsing < Error; end
|
||||
|
||||
# Raised when API endpoint returns the HTTP status code 400.
|
||||
class BadRequest < Error; end
|
||||
|
||||
# Raised when API endpoint returns the HTTP status code 401.
|
||||
class Unauthorized < Error; end
|
||||
|
||||
# Raised when API endpoint returns the HTTP status code 403.
|
||||
class Forbidden < Error; end
|
||||
|
||||
# Raised when API endpoint returns the HTTP status code 404.
|
||||
class NotFound < Error; end
|
||||
|
||||
# Raised when API endpoint returns the HTTP status code 405.
|
||||
class MethodNotAllowed < Error; end
|
||||
|
||||
# Raised when API endpoint returns the HTTP status code 409.
|
||||
class Conflict < Error; end
|
||||
|
||||
# Raised when API endpoint returns the HTTP status code 500.
|
||||
class InternalServerError < Error; end
|
||||
|
||||
# Raised when API endpoint returns the HTTP status code 502.
|
||||
class BadGateway < Error; end
|
||||
|
||||
# Raised when API endpoint returns the HTTP status code 503.
|
||||
class ServiceUnavailable < Error; end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,44 @@
|
|||
require 'gitlab'
|
||||
require 'gitlab/cli_helpers'
|
||||
|
||||
module Gitlab::Help
|
||||
extend Gitlab::CLI::Helpers
|
||||
|
||||
def self.get_help(methods,cmd=nil)
|
||||
help = ''
|
||||
|
||||
if cmd.nil? || cmd == 'help'
|
||||
help = actions_table
|
||||
else
|
||||
ri_cmd = `which ri`.chomp
|
||||
|
||||
if $? == 0
|
||||
namespace = methods.select {|m| m[:name] === cmd }.map {|m| m[:owner]+'.'+m[:name] }.shift
|
||||
|
||||
if namespace
|
||||
begin
|
||||
ri_output = `#{ri_cmd} -T #{namespace} 2>&1`.chomp
|
||||
|
||||
if $? == 0
|
||||
ri_output.gsub!(/#{cmd}\((.*?)\)/, cmd+' \1')
|
||||
ri_output.gsub!(/Gitlab\./, 'gitlab> ')
|
||||
ri_output.gsub!(/Gitlab\..+$/, '')
|
||||
ri_output.gsub!(/\,\s?/, ' ')
|
||||
help = ri_output
|
||||
else
|
||||
help = "Ri docs not found for #{namespace}, please install the docs to use 'help'"
|
||||
end
|
||||
rescue => e
|
||||
puts e.message
|
||||
end
|
||||
else
|
||||
help = "Unknown command: #{cmd}"
|
||||
end
|
||||
else
|
||||
help = "'ri' tool not found in your PATH, please install it to use the help."
|
||||
end
|
||||
end
|
||||
|
||||
puts help
|
||||
end
|
||||
end
|
|
@ -0,0 +1,24 @@
|
|||
module Gitlab
|
||||
# Converts hashes to the objects.
|
||||
class ObjectifiedHash
|
||||
# Creates a new ObjectifiedHash object.
|
||||
def initialize(hash)
|
||||
@hash = hash
|
||||
@data = hash.inject({}) do |data, (key,value)|
|
||||
value = ObjectifiedHash.new(value) if value.is_a? Hash
|
||||
data[key.to_s] = value
|
||||
data
|
||||
end
|
||||
end
|
||||
|
||||
def to_hash
|
||||
@hash
|
||||
end
|
||||
alias_method :to_h, :to_hash
|
||||
|
||||
# Delegate to ObjectifiedHash.
|
||||
def method_missing(key)
|
||||
@data.key?(key.to_s) ? @data[key.to_s] : nil
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,113 @@
|
|||
require 'httparty'
|
||||
require 'json'
|
||||
|
||||
module Gitlab
|
||||
# @private
|
||||
class Request
|
||||
include HTTParty
|
||||
format :json
|
||||
headers 'Accept' => 'application/json'
|
||||
parser Proc.new { |body, _| parse(body) }
|
||||
|
||||
attr_accessor :private_token
|
||||
|
||||
# Converts the response body to an ObjectifiedHash.
|
||||
def self.parse(body)
|
||||
body = decode(body)
|
||||
|
||||
if body.is_a? Hash
|
||||
ObjectifiedHash.new body
|
||||
elsif body.is_a? Array
|
||||
body.collect! { |e| ObjectifiedHash.new(e) }
|
||||
else
|
||||
raise Error::Parsing.new "Couldn't parse a response body"
|
||||
end
|
||||
end
|
||||
|
||||
# Decodes a JSON response into Ruby object.
|
||||
def self.decode(response)
|
||||
begin
|
||||
JSON.load response
|
||||
rescue JSON::ParserError
|
||||
raise Error::Parsing.new "The response is not a valid JSON"
|
||||
end
|
||||
end
|
||||
|
||||
def get(path, options={})
|
||||
set_httparty_config(options)
|
||||
set_private_token_header(options)
|
||||
validate self.class.get(path, options)
|
||||
end
|
||||
|
||||
def post(path, options={})
|
||||
set_httparty_config(options)
|
||||
set_private_token_header(options, path)
|
||||
validate self.class.post(path, options)
|
||||
end
|
||||
|
||||
def put(path, options={})
|
||||
set_httparty_config(options)
|
||||
set_private_token_header(options)
|
||||
validate self.class.put(path, options)
|
||||
end
|
||||
|
||||
def delete(path, options={})
|
||||
set_httparty_config(options)
|
||||
set_private_token_header(options)
|
||||
validate self.class.delete(path, options)
|
||||
end
|
||||
|
||||
# Checks the response code for common errors.
|
||||
# Returns parsed response for successful requests.
|
||||
def validate(response)
|
||||
case response.code
|
||||
when 400; raise Error::BadRequest.new error_message(response)
|
||||
when 401; raise Error::Unauthorized.new error_message(response)
|
||||
when 403; raise Error::Forbidden.new error_message(response)
|
||||
when 404; raise Error::NotFound.new error_message(response)
|
||||
when 405; raise Error::MethodNotAllowed.new error_message(response)
|
||||
when 409; raise Error::Conflict.new error_message(response)
|
||||
when 500; raise Error::InternalServerError.new error_message(response)
|
||||
when 502; raise Error::BadGateway.new error_message(response)
|
||||
when 503; raise Error::ServiceUnavailable.new error_message(response)
|
||||
end
|
||||
|
||||
response.parsed_response
|
||||
end
|
||||
|
||||
# Sets a base_uri and default_params for requests.
|
||||
# @raise [Error::MissingCredentials] if endpoint not set.
|
||||
def set_request_defaults(endpoint, private_token, sudo=nil)
|
||||
raise Error::MissingCredentials.new("Please set an endpoint to API") unless endpoint
|
||||
@private_token = private_token
|
||||
|
||||
self.class.base_uri endpoint
|
||||
self.class.default_params :sudo => sudo
|
||||
self.class.default_params.delete(:sudo) if sudo.nil?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Sets a PRIVATE-TOKEN header for requests.
|
||||
# @raise [Error::MissingCredentials] if private_token not set.
|
||||
def set_private_token_header(options, path=nil)
|
||||
unless path == '/session'
|
||||
raise Error::MissingCredentials.new("Please set a private_token for user") unless @private_token
|
||||
options[:headers] = {'PRIVATE-TOKEN' => @private_token}
|
||||
end
|
||||
end
|
||||
|
||||
# Set HTTParty configuration
|
||||
# @see https://github.com/jnunemaker/httparty
|
||||
def set_httparty_config(options)
|
||||
if self.httparty
|
||||
options.merge!(self.httparty)
|
||||
end
|
||||
end
|
||||
|
||||
def error_message(response)
|
||||
"Server responded with code #{response.code}, message: #{response.parsed_response.message}. " \
|
||||
"Request URI: #{response.request.base_uri}#{response.request.path}"
|
||||
end
|
||||
end
|
||||
end
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue