From e9124c62ceb6d779b8f78cf9e11de46eb6bc3098 Mon Sep 17 00:00:00 2001 From: sw <939547590@qq.com> Date: Thu, 23 Oct 2014 09:22:41 +0800 Subject: [PATCH 1/7] =?UTF-8?q?#1250=E4=BF=AE=E6=94=B9=E5=B8=90=E5=8F=B7?= =?UTF-8?q?=E5=90=8E=E5=B0=86=E5=B8=90=E5=8F=B7=E6=9B=B4=E6=96=B0=E6=88=90?= =?UTF-8?q?=E5=8A=9F=E6=94=BE=E5=9C=A8=E4=B8=80=E4=B8=AA=E6=98=BE=E7=9C=BC?= =?UTF-8?q?=E7=9A=84=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/my_controller.rb | 2 +- app/views/layouts/base_users.html.erb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/my_controller.rb b/app/controllers/my_controller.rb index 4e23fc41b..00c843045 100644 --- a/app/controllers/my_controller.rb +++ b/app/controllers/my_controller.rb @@ -130,7 +130,7 @@ class MyController < ApplicationController @user.pref.save @user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : []) set_language_if_valid @user.language - flash.now[:notice] = l(:notice_account_updated) + flash[:notice] = l(:notice_account_updated) redirect_to user_url(@user) return else diff --git a/app/views/layouts/base_users.html.erb b/app/views/layouts/base_users.html.erb index c1c0eaf7b..97d5fc47f 100644 --- a/app/views/layouts/base_users.html.erb +++ b/app/views/layouts/base_users.html.erb @@ -281,7 +281,7 @@ <%= yield %> <%= call_hook :view_layouts_base_content %>
- <%= render_flash_messages %> + <%#= render_flash_messages %> From 91d08d5b9ac027ed26ce2b1b02f9e3ba4cab5f9a Mon Sep 17 00:00:00 2001 From: sw <939547590@qq.com> Date: Thu, 23 Oct 2014 09:44:06 +0800 Subject: [PATCH 2/7] =?UTF-8?q?#1233=E4=BF=AE=E5=A4=8D=E4=B8=AA=E4=BA=BA?= =?UTF-8?q?=E4=B8=BB=E9=A1=B5--=E5=8A=A8=E6=80=81=EF=BC=9A=E7=82=B9?= =?UTF-8?q?=E5=87=BB=E9=A1=B9=E7=9B=AE=E9=93=BE=E6=8E=A5=E6=8A=A5500?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E7=9A=84BUG=20=E4=BC=98=E5=8C=96=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/users/show.html.erb | 825 ++++++++++++++++++++-------------- 1 file changed, 484 insertions(+), 341 deletions(-) diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb index fd0195833..7d13e404e 100644 --- a/app/views/users/show.html.erb +++ b/app/views/users/show.html.erb @@ -48,353 +48,485 @@ <% if e.act_type == 'JournalsForMessage' || e.act_type == 'Bid' || e.act_type == 'Journal'|| e.act_type == 'Changeset' || e.act_type == 'Message' || e.act_type == 'Principal' || e.act_type == 'News' || e.act_type == 'Issue' || e.act_type == 'Contest'%><%= image_tag(url_to_avatar(e.user), :class => "avatar") %> | ++ <%= image_tag(url_to_avatar(e.user), :class => "avatar") %> + |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<%= textAreailizable e.notes %> |
+
+ + <%= textAreailizable e.notes %> + + |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
- <%= format_time e.created_on %> | + + <%= format_time e.created_on %> + +
<%= l(:label_no_user_respond_you) %>
++ <%= l(:label_no_user_respond_you) %> +
<% end %> From 923a33add544ba0c018e5ccb2ee08f44de0ab391 Mon Sep 17 00:00:00 2001 From: sw <939547590@qq.com> Date: Thu, 23 Oct 2014 10:44:06 +0800 Subject: [PATCH 3/7] =?UTF-8?q?#1397=E3=80=81#1396=E6=96=B0=E5=BB=BA?= =?UTF-8?q?=E7=AB=9E=E8=B5=9B=E9=80=9A=E7=9F=A5=E5=A2=9E=E5=8A=A0js?= =?UTF-8?q?=E9=AA=8C=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/contestnotifications/_form.html.erb | 39 +++++------ app/views/contestnotifications/index.html.erb | 64 ++++++++++++++++++- config/locales/zh.yml | 4 ++ 3 files changed, 86 insertions(+), 21 deletions(-) diff --git a/app/views/contestnotifications/_form.html.erb b/app/views/contestnotifications/_form.html.erb index 36bcd78c6..908d1138d 100644 --- a/app/views/contestnotifications/_form.html.erb +++ b/app/views/contestnotifications/_form.html.erb @@ -3,24 +3,27 @@ <%= l(:bale_news_notice) %>- <%= f.text_field :title, - :required => true, - :size => 60, - :maxlength => 60, - :style => "width:488px;" - %> -
-- <%= f.text_area :description, - :required => true, - :cols => 60, - :rows => 11, - :class => 'wiki-edit', - :style => "width:490px;" - %> -
- ++ <%= f.text_field :title, + :required => true, + :size => 60, + :maxlength => 60, + :style => "width:488px;", + :onblur => "regexTitle();" + %> +
+ ++ <%= f.text_area :description, + :required => true, + :cols => 60, + :rows => 11, + :class => 'wiki-edit', + :style => "width:490px;", + :onblur => "regexDescription();" + %> +
+((.|\s)*?)}m, '[...]') - @content = "> #{ll(User.current.language, :text_user_wrote, user)}\n> " - @content << text.gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n" - @id = user.id - rescue ActiveRecord::RecordNotFound - render_404 - end - - ##新建需求 - def new_bid - @bid = Bid.new - @bid.safe_attributes = params[:bid] - end - - #huang - def create_contest - @bid = Bid.new - @bid.name = params[:bid][:name] - @bid.description = params[:bid][:description] - @bid.reward_type = 2 - @bid.budget = params[:bid][:budget] - @bid.deadline = params[:bid][:deadline] - @bid.password = params[:bid][:password] #added by bai - @bid.author_id = User.current.id - @bid.commit = 0 - if @bid.save - unless @bid.watched_by?(User.current) - if @bid.add_watcher(User.current) - flash[:notice] = l(:label_bid_succeed) - end - end - redirect_to respond_url(@bid) - else - @bid.safe_attributes = params[:bid] - render :action => 'new_bid' - end - end - -# added by bai - def update_contest - @bid = Bid.find(params[:id]) - @bid.name = params[:bid][:name] - @bid.description = params[:bid][:description] - @bid.reward_type = 2 - @bid.budget = params[:bid][:budget] - @bid.deadline = params[:bid][:deadline] - @bid.password = params[:bid][:password] - @bid.author_id = User.current.id - @bid.commit = 0 - if @bid.save - unless @bid.watched_by?(User.current) - if @bid.add_watcher(User.current) - flash[:notice] = l(:label_bid_succeed) - end - end - redirect_to respond_url(@bid) - else - @bid.safe_attributes = params[:bid] - render :action => 'new_bid' - end - end - #huang - def new_contest - @bid = Bid.new - @bid.safe_attributes = params[:bid] - end - - def create_bid - @bid = Bid.new - @bid.name = params[:bid][:name] - @bid.description = params[:bid][:description] - @bid.reward_type = 1 - @bid.budget = params[:bid][:budget] - @bid.deadline = params[:bid][:deadline] - @bid.author_id = User.current.id - @bid.commit = 0 - if @bid.save - unless @bid.watched_by?(User.current) - if @bid.add_watcher(User.current) - flash[:notice] = l(:label_bid_succeed) - end - end - redirect_to respond_url(@bid) - else - @bid.safe_attributes = params[:bid] - render :action => 'new_bid' - end - end - - def create_homework - @bid = Bid.new - @bid.name = params[:bid][:name] - @bid.description = params[:bid][:description] - @bid.is_evaluation = params[:bid][:is_evaluation] - @bid.proportion = params[:bid][:proportion] - @bid.reward_type = 3 - # @bid.budget = params[:bid][:budget] - @bid.deadline = params[:bid][:deadline] - @bid.budget = 0 - @bid.author_id = User.current.id - @bid.commit = 0 - @bid.homework_type = 1 - @bid.save_attachments(params[:attachments] || (params[:bid] && params[:bid][:uploads])) - # @bid. - if @bid.save - HomeworkForCourse.create(:course_id => params[:course_id], :bid_id => @bid.id) - unless @bid.watched_by?(User.current) - if @bid.add_watcher(User.current) - flash[:notice] = l(:label_bid_succeed) - end - end - redirect_to respond_url(@bid) - else - @bid.safe_attributes = params[:bid] - @homework = @bid - @course = Course.find_by_id(params[:course_id]) - @course_id = @course.id - #respond_to do |format| - # format.html { redirect_to new_homework_course_path(params[:course_id]),:layout => 'base_courses'} - # format.api { render_validation_errors(@bid) } - #end - render file: 'courses/new_homework', layout: 'base_courses' - end - end - - # modify by nwb\ - # 编辑作业 - def edit - @bid = Bid.find(params[:bid_id]) - if (User.current.admin?||User.current.id==@bid.author_id) - @course_id = params[:course_id] - respond_to do |format| - format.html { - @course = Course.find(params[:course_id]) - @user= User.find(User.current.id) - render :layout => 'base_courses' - } - end - else - render_403 - end - end - - def update - @bid = Bid.find(params[:id]) - @course = @bid.courses.first#Project.find(params[:course_id]) - @bid.name = params[:bid][:name] - @bid.description = params[:bid][:description] - @bid.is_evaluation = params[:bid][:is_evaluation] - @bid.proportion = params[:bid][:proportion] - @bid.reward_type = 3 - @bid.deadline = params[:bid][:deadline] - @bid.budget = 0 - @bid.author_id = User.current.id - @bid.commit = 0 - @bid.homework_type = 1 - @bid.save_attachments(params[:attachments] || (params[:bid] && params[:bid][:uploads])) - if @bid.save - flash[:notice] = l(:label_update_homework_succeed) - redirect_to course_homework_url(@course) - else - @bid.safe_attributes = params[:bid] - render :action => 'edit', :layout =>'base_courses' - end - end - - def new_submit_homework - #render html to prepare create submit homework - find_bid - render :layout => 'base_homework' - end - - def add_homework - if User.current.logged? && (!Member.where('user_id = ? and project_id = ?', User.current.id, @bid.courses.first.id).first.nil? && (Member.where('user_id = ? and project_id = ?', User.current.id, @bid.courses.first.id).first.roles&Role.where('id = ? or id = ? or id =?',5, 10, 7)).size >0) - # homework = HomeworkAttach.create(:bid_id => @bid.id, :user_id => User.current.id) - # homework.save_attachments(params[:attachments] || (params[:bid] && params[:bid][:uploads])) - - if hadcommittedhomework(User.current.id, @bid.id) == true - @homework_flag = l(:label_bidding_homework_committed) - else - @homework = HomeworkAttach.new - @homework.safe_attributes = params[:homeworkattach] - @homework.bid_id = @bid.id - @homework.user_id = User.current.id - @homework.save_attachments(params[:attachments]) - - render_attachment_warning_if_needed(@homework) - - @homework_flag = if @homework.save - l(:label_bidding_homework_succeed) - else - l(:label_bidding_homework_failed) - end - - if @homework.attachments.empty? - @homework.delete - #flash[:error] = l(:no_attachmens_allowed) - @homework_flag = l(:no_attachmens_allowed) - # else - end - end - end - - @homework_list = @bid.homeworks - respond_to do |format| - format.html{ - #redirect_to project_for_bid_path, notice: @homework_flag.to_s - flash[:notice] = @homework_flag.to_s - redirect_back_or_default(project_for_bid_path) - } - format.js - end - - end - - # 作业统计 - def homework_statistics - @course = @bid.courses.first - @member = [] - @course.memberships.each do |member| - unless (member.roles && Role.where('id = ? ', 3)).empty? - @member.push member - end - end - if @bid.homework_type = 1 - @student = User.where("id in (select DISTINCT user_id from #{HomeworkAttach.table_name} where bid_id = ? )", @bid.id) - @homework_type = true - else - - @homework_type = false - end - @user = @bid.author - render :layout => 'base_homework' - end - - def homework_respond - @user = @bid.author - render :layout => 'base_homework' - end - - def more - @jour = @bid.journals_for_messages - @jour.each_with_index {|j,i| j.indice = i+1} - @state = true - - respond_to do |format| - format.html { redirect_to :back } - format.js - #format.api { render_api_ok } - end - end - - def back - @jour = @bid.journals_for_messages - @jour.each_with_index {|j,i| j.indice = i+1} - @state = false - - respond_to do |format| - format.html { redirect_to :back } - format.js - #format.api { render_api_ok } - end - end - - #added by william - #used to set the bidding project reward - def set_reward - @b_p = nil - @biding_project_id = nil - - if params[:set_reward][:reward]&&((User.current.id==@bid.author_id)||User.current.admin) - # @bid_id = params[:id] - @biding_project_id = params[:set_reward][:b_id] - @b_p = BidingProject.find_by_id(@biding_project_id) - - # 把字段存进表中 - @b_p.update_reward(params[:set_reward][:reward].to_s) - end - - respond_to do |format| - format.js - end - end - - # added by william - # used to manage the bid and end the bid - def manage - - end - - private - - def find_bid - if params[:id] - @bid = Bid.find(params[:id], :include => [{:homeworks => :user}]) - @user = @bid.author - end - rescue - render_404 - end - - def memberAccess - # 是课程,则判断当前用户是否参加了课程 - return true if current_user.admin? - #return 0 if @bid.courses.first.project_type == Project::ProjectType_project - currentUser = User.current - render_403 unless currentUser.member_of_course?(@bid.courses.first) - end - - #验证是否显示课程 - def can_show_course - @first_page = FirstPage.find_by_page_type('project') - if @first_page.show_course == 2 - render_404 - end - end - - #验证是否显示竞赛 - def can_show_contest - @first_page = FirstPage.find_by_page_type('project') - if @first_page.show_contest == 2 - render_404 - end - end - -end - +# fq +class BidsController < ApplicationController + #Added by young + menu_item l(:label_homework), :only => [:edit, :udpate] + menu_item :respond + menu_item :course, :only => :show_courseEx + menu_item :project, :only => [:show_project,:show_results, :new_submit_homework] + menu_item :homework_respond, :only => :homework_respond + menu_item :homework_statistics, :only => :homework_statistics + + before_filter :can_show_course,only: [] + before_filter :can_show_contest,only: [] + #Ended by young + before_filter :find_bid, :only => [:show, :show_project, :create,:destroy,:more,:back,:add,:delete,:new,:show_results,:set_reward, :add_homework, :fork, :create_fork, + :show_course, :show_courseEx,:show_bid_project, :show_bid_user, :join_in_contest, :unjoin_in_contest, :new_join,:show_participator, :settings] + # added by fq + before_filter :require_login, :only => [:join_in_contest, :unjoin_in_contest] + # end + before_filter :require_login,:only => [:set_reward, :destroy, :add, :new, ] + + #before_filter :memberAccess, only: :show_project + + helper :watchers + helper :attachments + include AttachmentsHelper + include ApplicationHelper + include BidsHelper + + helper :projects + helper :words + helper :welcome + helper :project_score + + def find_project_by_bid_id + @bid = Bid.find(params[:id]) + @project = @bid.courses[0] + rescue ActiveRecord::RecordNotFound + render_404 + end + + def homework_ajax_modal + @bid = Bid.find_by_id(params[:id]) + # find_bid + respond_to do |format| + format.js + end + end + + + def index + @project_type = params[:project_type] + # Modified by nie + # @requirement_title = "4" + @offset, @limit = api_offset_and_limit({:limit => 10}) + if @project_type == '1' + @bids = Bid.visible.where('reward_type = ?', 3) + # elsif + # @bids = Bid.visible.where('reward_type = ? or reward_type = ?', 4) + else + @bids = Bid.visible.where('reward_type = ?', 1) + end + + @bids = @bids.like(params[:name]) if params[:name].present? + @bid_count = @bids.count + @bid_pages = Paginator.new @bid_count, @limit, params['page'] + + @offset ||= @bid_pages.reverse_offset + #added by nie + if params[:bid_sort_type].present? + case params[:bid_sort_type] + when '0' + unless @offset == 0 + @bids = @bids.offset(@offset).limit(@limit).all.reverse + else + limit = @bid_count % @limit + limit = @limit if limit == 0 + @bids = @bids.offset(@offset).limit(limit).all.reverse + end + @s_state = 0 + when '1' + unless @offset == 0 + @bids = @bids.reorder('bids.commit').offset(@offset).limit(@limit).all.reverse + else + limit = @bid_count % @limit + limit = @limit if limit == 0 + @bids = @bids.reorder('bids.commit').offset(@offset).limit(limit).all.reverse + end + @s_state = 1 + when '2' + unless @offset == 0 + @bids = @bids.offset(@offset).limit(@limit).all.reverse + else + limit = @bid_count % @limit + limit = @limit if limit == 0 + @bids = @bids.offset(@offset).limit(@limit).all.reverse + end + @s_state = 0 + end + else + unless @offset == 0 + @bids = @bids.reorder('bids.commit').offset(@offset).limit(@limit).all.reverse + else + limit = @bid_count % @limit + limit = @limit if limit == 0 + @bids = @bids.reorder('bids.commit').offset(@offset).limit(limit).all.reverse + end + @s_state = 1 + end + #end + end + #huang + def contest + + # Modified by nie + # @requirement_title = "4" + @offset, @limit = api_offset_and_limit({:limit => 10}) + + @bids = Bid.visible.where('reward_type = ?', 2) + + # elsif + # @bids = Bid.visible.where('reward_type = ? or reward_type = ?', 4) + @bids = @bids.like(params[:name]) if params[:name].present? + @bid_count = @bids.count + @bid_pages = Paginator.new @bid_count, @limit, params['page'] + + @offset ||= @bid_pages.reverse_offset + #added by nie + if params[:contest_sort_type].present? + case params[:contest_sort_type] + when '0' + unless @offset == 0 + @bids = @bids.offset(@offset).limit(@limit).all.reverse + else + limit = @bid_count % @limit + limit = @limit if limit == 0 + @bids = @bids.offset(@offset).limit(limit).all.reverse + end + @s_state = 0 + when '1' + unless @offset == 0 + @bids = @bids.reorder('bids.commit').offset(@offset).limit(@limit).all.reverse + else + limit = @bid_count % @limit + limit = @limit if limit == 0 + @bids = @bids.reorder('bids.commit').offset(@offset).limit(limit).all.reverse + end + @s_state = 1 + when '2' + unless @offset == 0 + @bids = @bids.offset(@offset).limit(@limit).all.reverse + else + limit = @bid_count % @limit + limit = @limit if limit == 0 + @bids = @bids.offset(@offset).limit(@limit).all.reverse + end + @s_state = 0 + end + else + unless @offset == 0 + @bids = @bids.reorder('bids.commit').offset(@offset).limit(@limit).all.reverse + else + limit = @bid_count % @limit + limit = @limit if limit == 0 + @bids = @bids.reorder('bids.commit').offset(@offset).limit(limit).all.reverse + end + @s_state = 1 + end + #end + end + + def fork + @courses = [] + @membership = User.current.memberships.all(:conditions => Project.visible_condition(User.current)) + @membership.each do |membership| + if membership.project.project_type == 1 + @courses << membership.project + end + end + end + + def create_fork + @homework = Bid.new + @homework.name = params[:bid][:name] + @homework.description = params[:bid][:description] + @homework.reward_type = 3 + # @bid.budget = params[:bid][:budget] + @homework.deadline = params[:bid][:deadline] + @homework.budget = 0 + @homework.author_id = User.current.id + @homework.commit = 0 + @homework.homework_type = 1 + @homework.is_evaluation = params[:bid][:is_evaluation] + @homework.parent_id = @bid.id + @homework.save_attachments(params[:attachments] || (params[:bid] && params[:bid][:uploads])) + # @bid. + if @homework.save + HomeworkForCourse.create(:course_id => params[:course], :bid_id => @homework.id) + unless @bid.watched_by?(User.current) + if @bid.add_watcher(User.current) + flash[:notice] = l(:label_bid_succeed) + end + end + redirect_to respond_path(@homework) + else + @bid.safe_attributes = params[:bid] + @courses = [] + @membership = User.current.coursememberships.all#(:conditions => Project.visible_condition(User.current)) + @membership.each do |membership| + @courses << membership.course + end + render :action => 'fork' + end + end + + def show + @user = @bid.author + @jours = @bid.journals_for_messages.where('m_parent_id IS NULL').order('created_on DESC') + @limit = 10 + @feedback_count = @jours.count + @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] + @offset ||= @feedback_pages.offset + @jour = @jours[@offset, @limit] + @state = false + + respond_to do |format| + layout_file = '' + case @bid.reward_type + when 3 + html_title(l(:label_question_student)) + layout_file = 'base_homework' + when 1 + layout_file = 'base_bids' + else + layout_file = 'base_contest' + end + format.html { + render :layout => layout_file + } + format.api + end + end + + def join_in_contest + if @bid.reward_type == 2 && params[:course_password] == @bid.password + JoinInContest.create(:user_id => User.current.id, :bid_id => @bid.id) + @state = 0 + else + @state = 1 + end + + respond_to do |format| + # format.html { redirect_to_referer_or {render :text => (watching ? 'Watcher added.' : 'Watcher removed.'), :layout => true}} + # TO_DO + format.js { render :partial => 'set_join', :locals => {:user => User.current, :object_id => params[:id]} } + end + end + + def unjoin_in_contest + + joined = JoinInContest.where('bid_id = ? and user_id = ?', @bid.id, User.current.id) + + joined.each do |join| + join.delete + end + + respond_to do |format| + # format.html { redirect_to_referer_or {render :text => (watching ? 'Watcher added.' : 'Watcher removed.'), :layout => true}} + format.js { render :partial => 'set_join', :locals => {:user => User.current, :object_id => params[:id]} } + end + end + + def new_join + # added by fq + + + end + + # added by bai 增加了参与者和竞赛设置 + def show_participator + render :layout => 'base_contest' + + end + + def settings + if @bid.author.id == User.current.id + if @bid.reward_type == 2 + @contest = Bid.find_by_reward_type(@bid.reward_type) + render :layout => 'base_contest' + end + else + render_403 :message => :notice_not_contest_setting_authorized + end + end + #end + + # 显示课程 + def show_course + bids = Bid.where('parent_id = ?', @bid.id) + @courses = [] + for bid in bids + @courses << bid.courses.first + end + + respond_to do |format| + if @bid.reward_type == 3 + format.html { + render :layout => 'base_homework' + } + elsif @bid.reward_type == 1 + format.html { + render :layout => 'base_bids' + } + else + format.html { + render :layout => 'base_contest' + } + end + format.api + + end + end + + def show_bid_project + bids = Bid.where('parent_id = ?', @bid.id) + @projects = [] + for bid in bids + @projects += bid.biding_projects + end + + respond_to do |format| + if @bid.reward_type == 3 + format.html { + render :layout => 'base_homework' + } + elsif @bid.reward_type == 1 + format.html { + render :layout => 'base_bids' + } + else + format.html { + render :layout => 'base_contest' + } + end + format.api + + end + end + + def show_bid_user + bids = Bid.where('parent_id = ?', @bid.id) + @users = [] + for bid in bids + for project in bid.projects + @users += project.users + end + end + + respond_to do |format| + if @bid.reward_type == 3 + format.html { + render :layout => 'base_homework' + } + elsif @bid.reward_type == 1 + format.html { + render :layout => 'base_bids' + } + else + format.html { + render :layout => 'base_contest' + } + end + format.api + + end + end + + def show_project + # flash[:notice] = "" + @membership = User.current.memberships.all(:conditions => Project.visible_condition(User.current)) + @option = [] + @membership.each do |membership| + unless(membership.project.project_type==1) + if membership.user.allowed_to?(:quote_project,membership.project) + @option << membership.project + end + end + end + + # a = [1] + # @project = Project.where("id in []", a) + @user = @bid.author + @bidding_project = @bid.biding_projects.all + if params[:student_id].present? + @temp = [] + @bidding_project.each do |pro| + if pro.project && pro.project.project_status + if /#{params[:student_id]}/ =~ pro.user.user_extensions.student_id + @temp << pro + end + end + @temp + end + @bidding_project = @temp + else + #added by nie + @temp = [] + @bidding_project.each do |pro| + if pro.project && pro.project.project_status + @temp << pro + end + @temp + end + if @temp.size > 0 + @bidding_project = @temp.sort {|a,b| b.project.project_status.grade <=> a.project.project_status.grade} + end + #ended + end + + if @bid.homework_type == 1 + @homework = HomeworkAttach.new + #@homework_list = @bid.homeworks + #增加作业按评分排序, + @homework_list = @bid.homeworks.eager_load(:rate_averages, :user, :attachments).order('seems_rateable_cached_ratings.avg DESC').order("#{HomeworkAttach.table_name}.created_at ASC") + if params[:student_id].present? + @temp = [] + @homework_list.each do |pro| + if /#{params[:student_id]}/ =~ pro.user.user_extensions.student_id + @temp << pro + end + @temp + end + @homework_list = @temp + end + end + + respond_to do |format| + if @bid.reward_type == 3 + format.html { + render :layout => 'base_homework' + } + elsif @bid.reward_type == 1 + format.html { + render :layout => 'base_bids' + } + else + format.html { + render :layout => 'base_contest' + } + end + format.api + end + end + + # 显示作业课程 + # add by nwb + def show_courseEx + if (User.current.logged? && (User.current.member_of_course?(@bid.courses.first) || User.current.admin?)) + # flash[:notice] = "" + @membership = User.current.coursememberships.all(:conditions => Course.visible_condition(User.current)) + + @user = @bid.author + @bidding_project = @bid.biding_projects.all + + if params[:student_id].present? + @temp = [] + @bidding_project.each do |pro| + if pro.project && pro.project.project_status + if /#{params[:student_id]}/ =~ pro.user.user_extensions.student_id + @temp << pro + end + end + @temp + end + @bidding_project = @temp + else + #added by nie + @temp = [] + @bidding_project.each do |pro| + if pro.project && pro.project.project_status + @temp << pro + end + @temp + end + if @temp.size > 0 + @bidding_project = @temp.sort {|a,b| b.project.project_status.grade <=> a.project.project_status.grade} + end + #ended + end + + if @bid.homework_type + @homework = HomeworkAttach.new + if @bid.proportion + teacher_proportion = @bid.proportion * 1.0 / 100 + else + teacher_proportion = 1.0 + end + #@homework_list = @bid.homeworks + #增加作业按评分排序, + #@homework_list = @bid.homeworks.eager_load(:rate_averages, :user, :attachments).order('seems_rateable_cached_ratings.avg DESC').order("#{HomeworkAttach.table_name}.created_at ASC") + all_homework_list = HomeworkAttach.eager_load(:attachments,:user,:rate_averages).find_by_sql("SELECT homework_attaches.*, + (SELECT AVG(stars) FROM seems_rateable_rates WHERE rateable_type = 'HomeworkAttach' AND rateable_id = homework_attaches.id AND rater_id = #{@bid.author_id}) AS t_score, + (SELECT AVG(stars) FROM seems_rateable_rates WHERE rateable_type = 'HomeworkAttach' AND rateable_id = homework_attaches.id AND rater_id <> #{@bid.author_id}) AS s_score + FROM homework_attaches WHERE bid_id = #{@bid.id} ORDER BY + (CASE WHEN t_score IS NULL THEN 0 ELSE t_score * #{teacher_proportion} END + CASE WHEN s_score IS NULL THEN 0 ELSE s_score * #{1 - teacher_proportion} END) DESC,created_at ASC") + + limit = 10 + feedback_count = all_homework_list.count + @feedback_pages = Paginator.new feedback_count, limit, params['page'] + offset ||= @feedback_pages.offset + @homework_list = all_homework_list[offset, limit] + + if params[:student_id].present? + @temp = [] + @homework_list.each do |pro| + if /#{params[:student_id]}/ =~ pro.user.user_extensions.student_id + @temp << pro + end + @temp + end + @homework_list = @temp + end + end + + respond_to do |format| + if @bid.reward_type == 3 + format.html { + html_title(l(:label_homework_info)) + render :layout => 'base_homework' + } + elsif @bid.reward_type == 1 + format.html { + render :layout => 'base_bids' + } + else + format.html { + render :layout => 'base_contest' + } + end + format.api + end + else + render_403 :message => :notice_not_authorized + end + end + + ##### by huang + def show_project_homework + # flash[:notice] = "" + @membership = User.current.memberships.all(:conditions => Project.visible_condition(User.current)) + @option = [] + @membership.each do |membership| + end + # a = [1] + # @project = Project.where("id in []", a) + @user = @bid.author + @bidding_project = @bid.biding_projects + respond_to do |format| + if @bid.reward_type == 3 + format.html { + render :layout => 'base_homework' + } + elsif @bid.reward_type == 1 + format.html { + render :layout => 'base_bids' + } + else + format.html { + render :layout => 'base_contest' + } + end + format.api + end + end + + ###添加应标项目 + def add + project = Project.find(params[:bid]) + bid_message = params[:bid_for_save][:bid_message] + if BidingProject.where("project_id = ? and bid_id = ?", project.id, @bid.id).size == 0 + if BidingProject.cerate_bidding(@bid.id, project.id, bid_message) + + # added by bai type ==1 需求,type==2 竞赛, type==3 作业 + if @bid.reward_type == 1 + flash.now[:notice] = l(:label_bidding_succeed) + + elsif @bid.reward_type == 2 + flash.now[:notice] = l(:label_bidding_contest_succeed) + + else @bid.reward_type == 3 + flash.now[:notice] = l(:label_bidding_homework_succeed) + end + # end + + end + else + if @bid.reward_type == 3 + flash.now[:error] = l(:label_bidding_homework_fail) + else + flash.now[:error] = l(:label_bidding_fail) + end + end + @bidding_project = @bid.biding_projects + respond_to do |format| + # format.html { redirect_to_referer_or {render :text => 'Watcher added.', :layout => true}} + # format.html + format.html { redirect_to :back } + format.js + #format.api { render_api_ok } + end + end + + #删除已提交的项目作业(不删项目) + def delete + binding_project = params[:binding_project] + if can_delete_project_homework(BidingProject.find(binding_project),User.current) + if BidingProject.delete(binding_project) + redirect_to project_for_bid_url + else + render_403; + end + end + end + ## 新建留言 + def create + + if params[:bid_message][:message].size>0 + if params[:reference_content] + message = params[:bid_message][:message] + "\n" + params[:reference_content] + else + message = params[:bid_message][:message] + @m = message + end + refer_user_id = params[:bid_message][:reference_user_id].to_i + @bid.add_jour(User.current, message, refer_user_id) + end + @user = @bid.author + @jours = @bid.journals_for_messages.where('m_parent_id IS NULL').order('created_on DESC') + @limit = 10 + @feedback_count = @jours.count + @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] + @offset ||= @feedback_pages.offset + @jour = @jours[@offset, @limit] + @bid.set_commit(@feedback_count) + + respond_to do |format| + format.js + #format.api { render_api_ok } + end + + end + + ##删除留言 + def destroy + @user = @bid.author + if User.current.admin? || User.current.id == @user.id + JournalsForMessage.delete_message(params[:object_id]) + end + @jours = @bid.journals_for_messages.reverse + @limit = 10 + @feedback_count = @jours.count + @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] + @offset ||= @feedback_pages.offset + @jour = @jours[@offset, @limit] + + @bid.set_commit(@feedback_count) + # if a_message.size > 5 + # @message = a_message[-5, 5] + # else + # @message = a_message + # end + # @message_count = a_message.count + + respond_to do |format| + # format.html + format.js + #format.api { render_api_ok } + end + end + + #删除作业 + #by xianbo + def homework_destroy + @bid_to_destroy = Bid.find params[:course_id] + (render_403; return false) unless User.current.admin?||User.current.id==@bid_to_destroy.author_id + @bid_to_destroy.destroy + respond_to do |format| + format.html { redirect_to :back } + format.js + #format.api { render_api_ok } + end + end + + #end by xianbo + ##引用 + def new + @jour = JournalsForMessage.find(params[:journal_id]) if params[:journal_id] + if @jour + user = @jour.user + text = @jour.notes + else + user = @bid.author + text = @bid.description + end + # Replaces pre blocks with [...] + text = text.to_s.strip.gsub(%r{
((.|\s)*?)}m, '[...]') + @content = "> #{ll(User.current.language, :text_user_wrote, user)}\n> " + @content << text.gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n" + @id = user.id + rescue ActiveRecord::RecordNotFound + render_404 + end + + ##新建需求 + def new_bid + @bid = Bid.new + @bid.safe_attributes = params[:bid] + end + + #huang + def create_contest + @bid = Bid.new + @bid.name = params[:bid][:name] + @bid.description = params[:bid][:description] + @bid.reward_type = 2 + @bid.budget = params[:bid][:budget] + @bid.deadline = params[:bid][:deadline] + @bid.password = params[:bid][:password] #added by bai + @bid.author_id = User.current.id + @bid.commit = 0 + if @bid.save + unless @bid.watched_by?(User.current) + if @bid.add_watcher(User.current) + flash[:notice] = l(:label_bid_succeed) + end + end + redirect_to respond_url(@bid) + else + @bid.safe_attributes = params[:bid] + render :action => 'new_bid' + end + end + +# added by bai + def update_contest + @bid = Bid.find(params[:id]) + @bid.name = params[:bid][:name] + @bid.description = params[:bid][:description] + @bid.reward_type = 2 + @bid.budget = params[:bid][:budget] + @bid.deadline = params[:bid][:deadline] + @bid.password = params[:bid][:password] + @bid.author_id = User.current.id + @bid.commit = 0 + if @bid.save + unless @bid.watched_by?(User.current) + if @bid.add_watcher(User.current) + flash[:notice] = l(:label_bid_succeed) + end + end + redirect_to respond_url(@bid) + else + @bid.safe_attributes = params[:bid] + render :action => 'new_bid' + end + end + #huang + def new_contest + @bid = Bid.new + @bid.safe_attributes = params[:bid] + end + + def create_bid + @bid = Bid.new + @bid.name = params[:bid][:name] + @bid.description = params[:bid][:description] + @bid.reward_type = 1 + @bid.budget = params[:bid][:budget] + @bid.deadline = params[:bid][:deadline] + @bid.author_id = User.current.id + @bid.commit = 0 + if @bid.save + unless @bid.watched_by?(User.current) + if @bid.add_watcher(User.current) + flash[:notice] = l(:label_bid_succeed) + end + end + redirect_to respond_url(@bid) + else + @bid.safe_attributes = params[:bid] + render :action => 'new_bid' + end + end + + def create_homework + @bid = Bid.new + @bid.name = params[:bid][:name] + @bid.description = params[:bid][:description] + @bid.is_evaluation = params[:bid][:is_evaluation] + @bid.proportion = params[:bid][:proportion] + @bid.reward_type = 3 + # @bid.budget = params[:bid][:budget] + @bid.deadline = params[:bid][:deadline] + @bid.budget = 0 + @bid.author_id = User.current.id + @bid.commit = 0 + @bid.homework_type = 1 + @bid.save_attachments(params[:attachments] || (params[:bid] && params[:bid][:uploads])) + # @bid. + if @bid.save + HomeworkForCourse.create(:course_id => params[:course_id], :bid_id => @bid.id) + unless @bid.watched_by?(User.current) + if @bid.add_watcher(User.current) + flash[:notice] = l(:label_bid_succeed) + end + end + redirect_to respond_url(@bid) + else + @bid.safe_attributes = params[:bid] + @homework = @bid + @course = Course.find_by_id(params[:course_id]) + @course_id = @course.id + #respond_to do |format| + # format.html { redirect_to new_homework_course_path(params[:course_id]),:layout => 'base_courses'} + # format.api { render_validation_errors(@bid) } + #end + render file: 'courses/new_homework', layout: 'base_courses' + end + end + + # modify by nwb\ + # 编辑作业 + def edit + @bid = Bid.find(params[:bid_id]) + if (User.current.admin?||User.current.id==@bid.author_id) + @course_id = params[:course_id] + respond_to do |format| + format.html { + @course = Course.find(params[:course_id]) + @user= User.find(User.current.id) + render :layout => 'base_courses' + } + end + else + render_403 + end + end + + def update + @bid = Bid.find(params[:id]) + @course = @bid.courses.first#Project.find(params[:course_id]) + @bid.name = params[:bid][:name] + @bid.description = params[:bid][:description] + @bid.is_evaluation = params[:bid][:is_evaluation] + @bid.proportion = params[:bid][:proportion] + @bid.reward_type = 3 + @bid.deadline = params[:bid][:deadline] + @bid.budget = 0 + @bid.author_id = User.current.id + @bid.commit = 0 + @bid.homework_type = 1 + @bid.save_attachments(params[:attachments] || (params[:bid] && params[:bid][:uploads])) + if @bid.save + flash[:notice] = l(:label_update_homework_succeed) + redirect_to course_homework_url(@course) + else + @bid.safe_attributes = params[:bid] + render :action => 'edit', :layout =>'base_courses' + end + end + + def new_submit_homework + #render html to prepare create submit homework + find_bid + render :layout => 'base_homework' + end + + def add_homework + if User.current.logged? && (!Member.where('user_id = ? and project_id = ?', User.current.id, @bid.courses.first.id).first.nil? && (Member.where('user_id = ? and project_id = ?', User.current.id, @bid.courses.first.id).first.roles&Role.where('id = ? or id = ? or id =?',5, 10, 7)).size >0) + # homework = HomeworkAttach.create(:bid_id => @bid.id, :user_id => User.current.id) + # homework.save_attachments(params[:attachments] || (params[:bid] && params[:bid][:uploads])) + + if hadcommittedhomework(User.current.id, @bid.id) == true + @homework_flag = l(:label_bidding_homework_committed) + else + @homework = HomeworkAttach.new + @homework.safe_attributes = params[:homeworkattach] + @homework.bid_id = @bid.id + @homework.user_id = User.current.id + @homework.save_attachments(params[:attachments]) + + render_attachment_warning_if_needed(@homework) + + @homework_flag = if @homework.save + l(:label_bidding_homework_succeed) + else + l(:label_bidding_homework_failed) + end + + if @homework.attachments.empty? + @homework.delete + #flash[:error] = l(:no_attachmens_allowed) + @homework_flag = l(:no_attachmens_allowed) + # else + end + end + end + + @homework_list = @bid.homeworks + respond_to do |format| + format.html{ + #redirect_to project_for_bid_path, notice: @homework_flag.to_s + flash[:notice] = @homework_flag.to_s + redirect_back_or_default(project_for_bid_path) + } + format.js + end + + end + + # 作业统计 + def homework_statistics + @course = @bid.courses.first + @member = [] + @course.memberships.each do |member| + unless (member.roles && Role.where('id = ? ', 3)).empty? + @member.push member + end + end + if @bid.homework_type = 1 + @student = User.where("id in (select DISTINCT user_id from #{HomeworkAttach.table_name} where bid_id = ? )", @bid.id) + @homework_type = true + else + + @homework_type = false + end + @user = @bid.author + render :layout => 'base_homework' + end + + def homework_respond + @user = @bid.author + render :layout => 'base_homework' + end + + def more + @jour = @bid.journals_for_messages + @jour.each_with_index {|j,i| j.indice = i+1} + @state = true + + respond_to do |format| + format.html { redirect_to :back } + format.js + #format.api { render_api_ok } + end + end + + def back + @jour = @bid.journals_for_messages + @jour.each_with_index {|j,i| j.indice = i+1} + @state = false + + respond_to do |format| + format.html { redirect_to :back } + format.js + #format.api { render_api_ok } + end + end + + #added by william + #used to set the bidding project reward + def set_reward + @b_p = nil + @biding_project_id = nil + + if params[:set_reward][:reward]&&((User.current.id==@bid.author_id)||User.current.admin) + # @bid_id = params[:id] + @biding_project_id = params[:set_reward][:b_id] + @b_p = BidingProject.find_by_id(@biding_project_id) + + # 把字段存进表中 + @b_p.update_reward(params[:set_reward][:reward].to_s) + end + + respond_to do |format| + format.js + end + end + + # added by william + # used to manage the bid and end the bid + def manage + + end + + private + + def find_bid + if params[:id] + @bid = Bid.find(params[:id], :include => [{:homeworks => :user}]) + @user = @bid.author + end + rescue + render_404 + end + + def memberAccess + # 是课程,则判断当前用户是否参加了课程 + return true if current_user.admin? + #return 0 if @bid.courses.first.project_type == Project::ProjectType_project + currentUser = User.current + render_403 unless currentUser.member_of_course?(@bid.courses.first) + end + + #验证是否显示课程 + def can_show_course + @first_page = FirstPage.find_by_page_type('project') + if @first_page.show_course == 2 + render_404 + end + end + + #验证是否显示竞赛 + def can_show_contest + @first_page = FirstPage.find_by_page_type('project') + if @first_page.show_contest == 2 + render_404 + end + end + +end + diff --git a/app/controllers/boards_controller.rb b/app/controllers/boards_controller.rb index ed9fcd52f..56ed69c49 100644 --- a/app/controllers/boards_controller.rb +++ b/app/controllers/boards_controller.rb @@ -1,152 +1,152 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class BoardsController < ApplicationController - layout 'base_projects'#by young - default_search_scope :messages - before_filter :find_project_by_project_id, :find_board_if_available - before_filter :authorize, :except => [:new, :show, :create, :index] - accept_rss_auth :index, :show - - - helper :sort - include SortHelper - helper :watchers - helper :project_score - - def index - #modify by nwb - if @project - @boards = @project.boards.includes(:last_message => :author).all - @boards = [] << @boards[0] if @boards.any? - if @boards.size == 1 - @board = @boards.first - show and return - end - render :layout => false if request.xhr? - elsif @course - @boards = @course.boards.includes(:last_message => :author).all - @boards = [] << @boards[0] if @boards.any? - if @boards.size == 1 - @board = @boards.first - show and return - end - render :layout => 'base_courses' - end - - end - - def show - respond_to do |format| - format.html { - sort_init 'updated_on', 'desc' - sort_update 'created_on' => "#{Message.table_name}.created_on", - 'replies' => "#{Message.table_name}.replies_count", - 'updated_on' => "COALESCE(last_replies_messages.created_on, #{Message.table_name}.created_on)" - - @topic_count = @board.topics.count - @topic_pages = Paginator.new @topic_count, per_page_option, params['page'] - @topics = @board.topics. - reorder("#{Message.table_name}.sticky DESC"). - includes(:last_reply). - limit(@topic_pages.per_page). - offset(@topic_pages.offset). - order(sort_clause). - preload(:author, {:last_reply => :author}). - all - @message = Message.new(:board => @board) - #modify by nwb - if @project - render :action => 'show', :layout => 'base_projects' - elsif @course - render :action => 'show', :layout => 'base_courses' - end - } - format.atom { - @messages = @board.messages. - reorder('created_on DESC'). - includes(:author, :board). - limit(Setting.feeds_limit.to_i). - all - if @project - render_feed(@messages, :title => "#{@project}: #{@board}") - elsif @course - render_feed(@messages, :title => "#{@course}: #{@board}") - end - - } - end - end - - def new - @board = @project.boards.build - @board.safe_attributes = params[:board] - if @project.project_type == 1 - render :layout => 'base_courses' - end - end - - def create - @board = @project.boards.build - @board.safe_attributes = params[:board] - - if @board.save - flash[:notice] = l(:notice_successful_create) - #Modified by young - #redirect_to_settings_in_projects - redirect_to project_board_url(@project, @board) - #Ended by young - else - render :action => 'new' - end - end - - def edit - if @project.project_type == 1 - render :layout => 'base_courses' - end - end - - def update - @board.safe_attributes = params[:board] - if @board.save - redirect_to_settings_in_projects - else - render :action => 'edit' - end - end - - def destroy - @board.destroy - redirect_to_settings_in_projects - end - -private - def redirect_to_settings_in_projects - redirect_to settings_project_url(@project, :tab => 'boards') - end - - def find_board_if_available - if @project - @board = @project.boards.find(params[:id]) if params[:id] - elsif @course - @board = @course.boards.find(params[:id]) if params[:id] - end - rescue ActiveRecord::RecordNotFound - render_404 - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class BoardsController < ApplicationController + layout 'base_projects'#by young + default_search_scope :messages + before_filter :find_project_by_project_id, :find_board_if_available + before_filter :authorize, :except => [:new, :show, :create, :index] + accept_rss_auth :index, :show + + + helper :sort + include SortHelper + helper :watchers + helper :project_score + + def index + #modify by nwb + if @project + @boards = @project.boards.includes(:last_message => :author).all + @boards = [] << @boards[0] if @boards.any? + if @boards.size == 1 + @board = @boards.first + show and return + end + render :layout => false if request.xhr? + elsif @course + @boards = @course.boards.includes(:last_message => :author).all + @boards = [] << @boards[0] if @boards.any? + if @boards.size == 1 + @board = @boards.first + show and return + end + render :layout => 'base_courses' + end + + end + + def show + respond_to do |format| + format.html { + sort_init 'updated_on', 'desc' + sort_update 'created_on' => "#{Message.table_name}.created_on", + 'replies' => "#{Message.table_name}.replies_count", + 'updated_on' => "COALESCE(last_replies_messages.created_on, #{Message.table_name}.created_on)" + + @topic_count = @board.topics.count + @topic_pages = Paginator.new @topic_count, per_page_option, params['page'] + @topics = @board.topics. + reorder("#{Message.table_name}.sticky DESC"). + includes(:last_reply). + limit(@topic_pages.per_page). + offset(@topic_pages.offset). + order(sort_clause). + preload(:author, {:last_reply => :author}). + all + @message = Message.new(:board => @board) + #modify by nwb + if @project + render :action => 'show', :layout => 'base_projects' + elsif @course + render :action => 'show', :layout => 'base_courses' + end + } + format.atom { + @messages = @board.messages. + reorder('created_on DESC'). + includes(:author, :board). + limit(Setting.feeds_limit.to_i). + all + if @project + render_feed(@messages, :title => "#{@project}: #{@board}") + elsif @course + render_feed(@messages, :title => "#{@course}: #{@board}") + end + + } + end + end + + def new + @board = @project.boards.build + @board.safe_attributes = params[:board] + if @project.project_type == 1 + render :layout => 'base_courses' + end + end + + def create + @board = @project.boards.build + @board.safe_attributes = params[:board] + + if @board.save + flash[:notice] = l(:notice_successful_create) + #Modified by young + #redirect_to_settings_in_projects + redirect_to project_board_url(@project, @board) + #Ended by young + else + render :action => 'new' + end + end + + def edit + if @project.project_type == 1 + render :layout => 'base_courses' + end + end + + def update + @board.safe_attributes = params[:board] + if @board.save + redirect_to_settings_in_projects + else + render :action => 'edit' + end + end + + def destroy + @board.destroy + redirect_to_settings_in_projects + end + +private + def redirect_to_settings_in_projects + redirect_to settings_project_url(@project, :tab => 'boards') + end + + def find_board_if_available + if @project + @board = @project.boards.find(params[:id]) if params[:id] + elsif @course + @board = @course.boards.find(params[:id]) if params[:id] + end + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index 72d9ebbe5..9f61306ab 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -1,55 +1,55 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class CommentsController < ApplicationController - default_search_scope :news - model_object News - before_filter :find_model_object - before_filter :find_project_from_association - before_filter :authorize - - def create - raise Unauthorized unless @news.commentable? - - @comment = Comment.new - @comment.safe_attributes = params[:comment] - @comment.author = User.current - if @news.comments << @comment - flash[:notice] = l(:label_comment_added) - end - - redirect_to news_url(@news) - end - - def destroy - @news.comments.find(params[:comment_id]).destroy - redirect_to news_url(@news) - end - - private - - # ApplicationController's find_model_object sets it based on the controller - # name so it needs to be overriden and set to @news instead - def find_model_object - super - @news = @object - @comment = nil - @news - end - - -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class CommentsController < ApplicationController + default_search_scope :news + model_object News + before_filter :find_model_object + before_filter :find_project_from_association + before_filter :authorize + + def create + raise Unauthorized unless @news.commentable? + + @comment = Comment.new + @comment.safe_attributes = params[:comment] + @comment.author = User.current + if @news.comments << @comment + flash[:notice] = l(:label_comment_added) + end + + redirect_to news_url(@news) + end + + def destroy + @news.comments.find(params[:comment_id]).destroy + redirect_to news_url(@news) + end + + private + + # ApplicationController's find_model_object sets it based on the controller + # name so it needs to be overriden and set to @news instead + def find_model_object + super + @news = @object + @comment = nil + @news + end + + +end diff --git a/app/controllers/contest_notification_controller.rb b/app/controllers/contest_notification_controller.rb index 461b62457..2ae841ed0 100644 --- a/app/controllers/contest_notification_controller.rb +++ b/app/controllers/contest_notification_controller.rb @@ -1,6 +1,6 @@ -class ContestNotificationController < ApplicationController - layout 'contest_base' - def show - @notification = ContestNotification.find(params[:id]) - end -end +class ContestNotificationController < ApplicationController + layout 'contest_base' + def show + @notification = ContestNotification.find(params[:id]) + end +end diff --git a/app/controllers/contestnotifications_controller.rb b/app/controllers/contestnotifications_controller.rb index f9c7e80c2..54ba33262 100644 --- a/app/controllers/contestnotifications_controller.rb +++ b/app/controllers/contestnotifications_controller.rb @@ -1,187 +1,187 @@ -class ContestnotificationsController < ApplicationController - # GET /contestnotifications - # GET /contestnotifications.json - layout 'base_newcontest' - default_search_scope :contestnotifications - model_object Contestnotification - # before_filter :find_model_object, :except => [:new, :create, :index] - # before_filter :find_contest_from_association, :except => [:new, :create, :index] - before_filter :find_contest_by_contest_id, :only => [:new, :create] - before_filter :find_contest - before_filter :find_author - # before_filter :authorize, :except => [:index] - before_filter :find_optional_contest, :only => [:index] - accept_rss_auth :index - accept_api_auth :index - - before_filter :access_edit_destroy, only: [:edit ,:update, :destroy] - - def find_author - @user = @contest.author - render_404 if @user.nil? - end - def find_contest - @contest = Contest.find(params[:contest_id]) - render_404 if @contest.nil? - end - - - def index - - # @contestnotifications = Contestnotification.all - # - # respond_to do |format| - # format.html # index.html.erb - # format.json { render json: @contestnotifications } - # end - - ### begin ### - case params[:format] - when 'xml', 'json' - @offset, @limit = api_offset_and_limit - else - @limit = 10 - end - - scope = @contest ? @contest.contestnotifications.visible : Contestnotifications.visible - - @contestnotifications_count = scope.count - @contestnotifications_pages = Paginator.new @contestnotifications_count, @limit, params['page'] - @offset ||= @contestnotifications_pages.offset - @contestnotificationss = scope.all(:include => [:author, :contest], - :order => "#{Contestnotification.table_name}.created_at DESC", - :offset => @offset, - :limit => @limit) - - respond_to do |format| - format.html { - @contestnotification = Contestnotification.new # for adding news inline - render :layout => 'base_newcontest' - } - format.api - format.atom { render_feed(@contestnotificationss, :title => (@contest ? @contest.name : Setting.app_title) + ": #{l(:label_contest_notification)}") } - end - ### end ### - end - - # GET /contestnotifications/1 - # GET /contestnotifications/1.json - def show - @contestnotification = Contestnotification.find(params[:id]) - - # - # respond_to do |format| - # format.html # show.html.erb - # format.json { render json: @contestnotification } - # end - @notificationcomments = @contestnotification.notificationcomments - @notificationcomments.reverse! if User.current.wants_notificationcomments_in_reverse_order? - render :layout => 'base_newcontest' - - end - - # GET /contestnotifications/new - # GET /contestnotifications/new.json - def new - # @contestnotification = Contestnotification.new -# - # respond_to do |format| - # format.html # new.html.erb - # format.json { render json: @contestnotification } - # end - @contestnotification = Contestnotification.new(:contest => @contest, :author => User.current) - render :layout => 'base_newcontest' - end - - # GET /contestnotifications/1/edit - def edit - @contestnotification = Contestnotification.find(params[:id]) - end - - # POST /contestnotifications - # POST /contestnotifications.json - def create - # @contestnotification = Contestnotification.new(params[:contestnotification]) - # - # respond_to do |format| - # if @contestnotification.save - # format.html { redirect_to @contestnotification, notice: 'Contestnotification was successfully created.' } - # format.json { render json: @contestnotification, status: :created, location: @contestnotification } - # else - # format.html { render action: "new" } - # format.json { render json: @contestnotification.errors, status: :unprocessable_entity } - # end - # end - @contestnotification = Contestnotification.new(:contest => @contest, :author => User.current) - @contestnotification.safe_attributes = params[:contestnotification] - @contestnotification.save_attachments(params[:attachments]) - if @contestnotification.save - render_attachment_warning_if_needed(@contestnotification) - flash[:notice] = l(:notice_successful_create) - redirect_to contest_contestnotifications_url(@contest) - else - layout_file = 'base_newcontest' - render :action => 'new', :layout => layout_file - end - end - - # PUT /contestnotifications/1 - # PUT /contestnotifications/1.json - def update - # @contestnotification = Contestnotification.find(params[:id]) - # - # respond_to do |format| - # if @contestnotification.update_attributes(params[:contestnotification]) - # format.html { redirect_to @contestnotification, notice: 'Contestnotification was successfully updated.' } - # format.json { head :no_content } - # else - # format.html { render action: "edit" } - # format.json { render json: @contestnotification.errors, status: :unprocessable_entity } - # end - # end - @contestnotification = Contestnotification.find(params[:id]) - @contestnotification.safe_attributes = params[:contestnotification] - @contestnotification.save_attachments(params[:attachments]) - if @contestnotification.save - render_attachment_warning_if_needed(@contestnotification) - flash[:notice] = l(:notice_successful_update) - redirect_to contest_contestnotification_url(@contestnotification.contest, @contestnotification) - else - render :action => 'edit' - end - end - - # DELETE /contestnotifications/1 - # DELETE /contestnotifications/1.json - def destroy - # @contestnotification = Contestnotification.find(params[:id]) - # @contestnotification.destroy - # - # respond_to do |format| - # format.html { redirect_to contestnotifications_url } - # format.json { head :no_content } - # end - @contestnotification = Contestnotification.find(params[:id]) - @contestnotification.destroy - redirect_to contest_contestnotifications_url(@contest) - end - - private - - def find_optional_contest - return true unless params[:id] - @contest = Contest.find(params[:id]) - # authorize - rescue ActiveRecord::RecordNotFound - render_404 - end - - def access_edit_destroy - if (User.current.admin? && User.current.logged? )||(User.current == @contest.author && User.current.logged?) - return true - else - render_403 - end - end - -end +class ContestnotificationsController < ApplicationController + # GET /contestnotifications + # GET /contestnotifications.json + layout 'base_newcontest' + default_search_scope :contestnotifications + model_object Contestnotification + # before_filter :find_model_object, :except => [:new, :create, :index] + # before_filter :find_contest_from_association, :except => [:new, :create, :index] + before_filter :find_contest_by_contest_id, :only => [:new, :create] + before_filter :find_contest + before_filter :find_author + # before_filter :authorize, :except => [:index] + before_filter :find_optional_contest, :only => [:index] + accept_rss_auth :index + accept_api_auth :index + + before_filter :access_edit_destroy, only: [:edit ,:update, :destroy] + + def find_author + @user = @contest.author + render_404 if @user.nil? + end + def find_contest + @contest = Contest.find(params[:contest_id]) + render_404 if @contest.nil? + end + + + def index + + # @contestnotifications = Contestnotification.all + # + # respond_to do |format| + # format.html # index.html.erb + # format.json { render json: @contestnotifications } + # end + + ### begin ### + case params[:format] + when 'xml', 'json' + @offset, @limit = api_offset_and_limit + else + @limit = 10 + end + + scope = @contest ? @contest.contestnotifications.visible : Contestnotifications.visible + + @contestnotifications_count = scope.count + @contestnotifications_pages = Paginator.new @contestnotifications_count, @limit, params['page'] + @offset ||= @contestnotifications_pages.offset + @contestnotificationss = scope.all(:include => [:author, :contest], + :order => "#{Contestnotification.table_name}.created_at DESC", + :offset => @offset, + :limit => @limit) + + respond_to do |format| + format.html { + @contestnotification = Contestnotification.new # for adding news inline + render :layout => 'base_newcontest' + } + format.api + format.atom { render_feed(@contestnotificationss, :title => (@contest ? @contest.name : Setting.app_title) + ": #{l(:label_contest_notification)}") } + end + ### end ### + end + + # GET /contestnotifications/1 + # GET /contestnotifications/1.json + def show + @contestnotification = Contestnotification.find(params[:id]) + + # + # respond_to do |format| + # format.html # show.html.erb + # format.json { render json: @contestnotification } + # end + @notificationcomments = @contestnotification.notificationcomments + @notificationcomments.reverse! if User.current.wants_notificationcomments_in_reverse_order? + render :layout => 'base_newcontest' + + end + + # GET /contestnotifications/new + # GET /contestnotifications/new.json + def new + # @contestnotification = Contestnotification.new +# + # respond_to do |format| + # format.html # new.html.erb + # format.json { render json: @contestnotification } + # end + @contestnotification = Contestnotification.new(:contest => @contest, :author => User.current) + render :layout => 'base_newcontest' + end + + # GET /contestnotifications/1/edit + def edit + @contestnotification = Contestnotification.find(params[:id]) + end + + # POST /contestnotifications + # POST /contestnotifications.json + def create + # @contestnotification = Contestnotification.new(params[:contestnotification]) + # + # respond_to do |format| + # if @contestnotification.save + # format.html { redirect_to @contestnotification, notice: 'Contestnotification was successfully created.' } + # format.json { render json: @contestnotification, status: :created, location: @contestnotification } + # else + # format.html { render action: "new" } + # format.json { render json: @contestnotification.errors, status: :unprocessable_entity } + # end + # end + @contestnotification = Contestnotification.new(:contest => @contest, :author => User.current) + @contestnotification.safe_attributes = params[:contestnotification] + @contestnotification.save_attachments(params[:attachments]) + if @contestnotification.save + render_attachment_warning_if_needed(@contestnotification) + flash[:notice] = l(:notice_successful_create) + redirect_to contest_contestnotifications_url(@contest) + else + layout_file = 'base_newcontest' + render :action => 'new', :layout => layout_file + end + end + + # PUT /contestnotifications/1 + # PUT /contestnotifications/1.json + def update + # @contestnotification = Contestnotification.find(params[:id]) + # + # respond_to do |format| + # if @contestnotification.update_attributes(params[:contestnotification]) + # format.html { redirect_to @contestnotification, notice: 'Contestnotification was successfully updated.' } + # format.json { head :no_content } + # else + # format.html { render action: "edit" } + # format.json { render json: @contestnotification.errors, status: :unprocessable_entity } + # end + # end + @contestnotification = Contestnotification.find(params[:id]) + @contestnotification.safe_attributes = params[:contestnotification] + @contestnotification.save_attachments(params[:attachments]) + if @contestnotification.save + render_attachment_warning_if_needed(@contestnotification) + flash[:notice] = l(:notice_successful_update) + redirect_to contest_contestnotification_url(@contestnotification.contest, @contestnotification) + else + render :action => 'edit' + end + end + + # DELETE /contestnotifications/1 + # DELETE /contestnotifications/1.json + def destroy + # @contestnotification = Contestnotification.find(params[:id]) + # @contestnotification.destroy + # + # respond_to do |format| + # format.html { redirect_to contestnotifications_url } + # format.json { head :no_content } + # end + @contestnotification = Contestnotification.find(params[:id]) + @contestnotification.destroy + redirect_to contest_contestnotifications_url(@contest) + end + + private + + def find_optional_contest + return true unless params[:id] + @contest = Contest.find(params[:id]) + # authorize + rescue ActiveRecord::RecordNotFound + render_404 + end + + def access_edit_destroy + if (User.current.admin? && User.current.logged? )||(User.current == @contest.author && User.current.logged?) + return true + else + render_403 + end + end + +end diff --git a/app/controllers/contests_controller.rb b/app/controllers/contests_controller.rb index 204dcc201..5cdbda5a7 100644 --- a/app/controllers/contests_controller.rb +++ b/app/controllers/contests_controller.rb @@ -1,732 +1,734 @@ -# fq -# class BidsController < ApplicationController -class ContestsController < ApplicationController - layout "contest_base" - - menu_item :respond - menu_item :project, :only => :show_project - menu_item :application, :only => :show_softapplication - menu_item :attendingcontests, :only => :show_attendingcontest - menu_item :contestnotifications, :only => :index - - before_filter :can_show_contest, :except => [] # modified by alan - - # modified by longjun - before_filter :find_contest, :only => [ - :show_contest, :show_project, :show_softapplication, - :show_attendingcontest, :index, :set_reward_project, - :set_reward_softapplication, :create, :destroy, :more, - :back, :add, :add_softapplication, :new,:show_results, - :set_reward, :show_contest_project, :show_contest_user, - :join_in_contest, :unjoin_in_contest, :new_join, :show_participator, :settings - ] - # end longjun - - # added by fq - before_filter :require_login, :only => [:join_in_contest, :unjoin_in_contest] - # end - before_filter :require_login,:only => [:set_reward, :destroy, :add, :new ] - - helper :watchers - helper :attachments - helper :projects - helper :words - - include AttachmentsHelper - include ApplicationHelper - - - def index - # @contests = Contest.visible - # @contests ||= [] - @offset, @limit = api_offset_and_limit(:limit => 10) - #@contests = Contest.visible - #@contests = @contests.like(params[:name]) if params[:name].present? - @contests = Contest.visible.where("name like '%#{params[:name]}%'") - if params[:contests_search] - (redirect_to contests_url, :notice => l(:label_sumbit_empty);return) if params[:name].blank? - end - @contest_count = @contests.count - @contest_pages = Paginator.new @contest_count, @limit, params['page'] - - @offset ||= @contest_pages.reverse_offset - if params[:contest_sort_type].present? - case params[:contest_sort_type] - when '0' - # modified by longjun - # never use unless and else, 将下面重复操作模块化,放在private下 - # unless @offset == 0 - # if @offset != 0 - # @contests = @contests.reorder('contests.commit').offset(@offset).limit(@limit).all.reverse - # else - # limit = @contest_count % @limit - # limit = @limit if limit == 0 - # @contests = @contests.reorder('contests.commit').offset(@offset).limit(limit).all.reverse - - @contests = index_page_sort(@offset, @limit, @contest_count, @contests, 'contests.commit') - # end - @s_state = 0 - when '1' - - @contests = index_page_sort(@offset, @limit, @contest_count, @contests, 'contests.created_on') - @s_state = 1 - # modified by longjun - # 目前只有 0, 1 两个sort_type - # when '2' - else - # end longjun - - @contests = index_page_sort(@offset, @limit, @contest_count, @contests, '') - @s_state = 0 - end - else - # modified by longjun - # never use unless and else - # unless @offset == 0 - if @offset != 0 - @contests = @contests.reorder('contests.created_on').offset(@offset).limit(@limit).all.reverse - else - limit = @contest_count % @limit - limit = @limit if limit == 0 - @contests = @contests.reorder('contests.created_on').offset(@offset).limit(limit).all.reverse - end - @s_state = 1 - end - end - - def search - redirect_to action: 'index',name:params[:name] - end - - def homework - @offset, @limit = api_offset_and_limit({:limit => 10}) - @bids = @course.homeworks.order('deadline DESC') - @bids = @bids.like(params[:name]) if params[:name].present? - @bid_count = @bids.count - @bid_pages = Paginator.new @bid_count, @limit, params['page'] - - @offset ||= @bid_pages.reverse_offset - # modified by longjun - # never use unless and else - # unless @offset == 0 - if @offset != 0 - @bids = @bids.offset(@offset).limit(@limit).all.reverse - else - limit = @bid_count % @limit - @bids = @bids.offset(@offset).limit(limit).all.reverse - end - render :layout => 'base_courses' - - end - - - def show_contest - @user = @contest.author - @jours = @contest.journals_for_messages.where('m_parent_id IS NULL').order('created_on DESC') - @limit = 10 - @feedback_count = @jours.count - @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] - @offset ||= @feedback_pages.offset - @jour = @jours[@offset, @limit] - @state = false - - respond_to do |format| - layout_file = 'base_newcontest' - format.html { - render :layout => layout_file - } - format.api - end - end - - def join_in_contest - if params[:contest_password] == @contest.password - JoinInCompetition.create(:user_id => User.current.id, :competition_id => @contest.id) - @state = 0 - else - @state = 1 - end - - respond_to do |format| - format.js { render :partial => 'set_join', :locals => {:user => User.current, :object_id => params[:id]} } - end - end - - def unjoin_in_contest - - joined = JoinInCompetition.where('competition_id = ? and user_id = ?', @contest.id, User.current.id) - - joined.each do |join| - join.delete - end - - respond_to do |format| - format.js { render :partial => 'set_join', :locals => {:user => User.current, :object_id => params[:id]} } - end - end - - - - def show_participator - render :layout => 'base_newcontest' - - end - - - def settings - if @contest.author.id == User.current.id - @contest = Contest.find(params[:id]) - render :layout => 'base_newcontest' - else - render_403 :message => :notice_not_contest_setting_authorized - end - end - - # Added by Longjun - def destroy_contest - @contest = Contest.find(params[:id]) - if @contest.author_id == User.current.id - - @contest.destroy - redirect_to action: 'index' - else - render_403 :message => :notice_not_contest_delete_authorized - end - - end - # end - - def show_contest_project - contests = Contest.where('parent_id = ?', @contest.id) - @projects = [] - - # Modified by longjun - # 用 arr.each 替换 for [ according to the style guide ] - - # for contest in contests - # @projects += contest.contesting_projects - # end - - contests.each do |contest| - @projects += contest.contesting_projects - end - - # end - - respond_to do |format| - format.html { - render :layout => 'base_newcontest' - } - format.api - end - end - - def show_contest_softapplication - contests = Contest.where('parent_id = ?', @contest.id) - @softapplications = [] - - # Modified by Longjun - # for contest in contests - # @softapplications += contest.contesting_softapplications - - - contests.each do |contest| - @softapplications += contest.contesting_softapplications - end - - # end - - respond_to do |format| - format.html { - render :layout => 'base_newcontest' - } - format.api - - end - end - - def show_contest_user - contests = Contest.find(:all) - @users = [] - - # Modified by Longjun - # for contest in contests - # for project in contest.projects - # @users += project.users - # end - - - contests.each do |contest| - contest.projects.each do |project| - @users += project.users - end - end - # end - - respond_to do |format| - format.html { - render :layout => 'base_newcontest' - } - format.api - - end - end - #显示参赛的项目 - def show_project - @membership = User.current.memberships.all(:conditions => Project.visible_condition(User.current)) - @option = [] - # @contesting_project_count = @contesting_project_all.count - # @contesting_project_pages = Paginator.new @contesting_project_count, per_page_option, params['page'] - @membership.each do |membership| - - # Modified by Longjun - # 将两个判断语句合并 - # unless membership.project.project_type==1 - # if User.current.allowed_to?(:quote_project, membership.project) - # @option << membership.project - # end - # end - if membership.project.project_type != 1 && User.current.allowed_to?(:quote_project, membership.project) - @option << membership.project - - end - # end - - end - @user = @contest.author - @contesting_project = @contest.contesting_projects.all - if params[:student_id].present? - @temp = [] - @contesting_project.each do |pro| - if pro.project && pro.project.project_status - if /#{params[:student_id]}/ =~ pro.user.user_extensions.student_id - @temp << pro - end - end - @temp - end - @contesting_project = @temp - else - - @temp = [] - @contesting_project.each do |pro| - # modified by longjun - # if pro.project && pro.project.project_status - # @temp << pro - # end - @temp << pro if pro.project && pro.project.project_status - # end longjun - @temp - end - if @temp.size > 0 - @contesting_project = @temp.sort {|a,b| b.project.project_status.grade <=> a.project.project_status.grade} - end - end - @contesting_project = paginateHelper(@contesting_project) - respond_to do |format| - format.html { - render :layout => 'base_newcontest' - } - format.api - end - end - ############ - ##显示参赛的应用 - def show_softapplication - - # @membership = User.current.memberships.all(:conditions => Project.visible_condition(User.current)) - # @option = [] - - # @user = @contest.user - @softapplication = Softapplication.all - @contesting_softapplication = @contest.contesting_softapplications - - @contesting_softapplication = paginateHelper(@contesting_softapplication, 10) - - # @temp = [] - # @softapplicationt.each do |pro| - # if pro.project && pro.project.project_status - # @temp << pro - # end - # @temp - - # if @temp.size > 0 - # @contesting_project = @temp.sort {|a,b| b.project.project_status.grade <=> a.project.project_status.grade} - # end - # end - # respond_to do |format| - # format.html { - # render :layout => 'base_newcontest' - # } - # format.api - # end -########################## - @contest = Contest.find_by_id(params[:id]) - respond_to do |format| - format.html { - render :layout => 'base_newcontest' - } - format.api - end - end - - - ###我要参赛 - def show_attendingcontest -##取出参赛项目--项目列表 - @membership = User.current.memberships.all(:conditions => Project.visible_condition(User.current)) - @option = [] - # @contesting_project_count = @contesting_project_all.count - # @contesting_project_pages = Paginator.new @contesting_project_count, per_page_option, params['page'] - @membership.each do |membership| - unless membership.project.project_type==1 - #拥有编辑项目权限的可将该项目参赛 - if User.current.allowed_to?(:quote_project, membership.project) - @option << membership.project - end - end - end - @user = @contest.author - @contesting_project = @contest.contesting_projects.all - if params[:student_id].present? - @temp = [] - @contesting_project.each do |pro| - if pro.project && pro.project.project_status - if /#{params[:student_id]}/ =~ pro.user.user_extensions.student_id - @temp << pro - end - end - @temp - end - @contesting_project = @temp - else - - @temp = [] - @contesting_project.each do |pro| - # modified by longjun - # if pro.project && pro.project.project_status - # @temp << pro - # end - @temp << pro if pro.project && pro.project.project_status - # end longjun - @temp - end - if @temp.size > 0 - @contesting_project = @temp.sort {|a,b| b.project.project_status.grade <=> a.project.project_status.grade} - end - end - # 取出参赛应用 --应用列表 - @softapplication = Softapplication.all - @contesting_softapplication = @contest.contesting_softapplications. - joins("LEFT JOIN softapplications ON contesting_softapplications.softapplication_id=softapplications.id"). - joins("LEFT JOIN ( - SELECT * FROM seems_rateable_cached_ratings - WHERE cacheable_type='Softapplication' AND DIMENSION = 'quality') AS cached - ON cached.cacheable_id=softapplications.id"). - order("cached.avg").reverse_order - @contesting_softapplication = paginateHelper @contesting_softapplication, 10 - - - #引用base_newcontest整体样式 - @contest = Contest.find_by_id(params[:id]) - respond_to do |format| - format.html { - render :layout => 'base_newcontest' - } - format.api - end - end - - ###end - - def show_notification - @contest = Contest.find_by_id(params[:id]) - respond_to do |format| - format.html { - render :layout => 'base_newcontest' - } - format.api - end - end - - - def set_reward_project - @c_p = nil - @contesting_project_id = nil - - if params[:set_reward_project][:reward]&&((User.current.id==@contest.author_id)||User.current.admin) - # @bid_id = params[:id] - @contesting_project_id = params[:set_reward_project][:c_id] - @c_p = ContestingProject.find_by_id(@contesting_project_id) - - # 把字段存进表中 - @c_p.update_reward(params[:set_reward_project][:reward].to_s) - end - - respond_to do |format| - format.js - end - end - - def set_reward_softapplication - @c_sa = nil - @contesting_softapplication_id = nil - - if params[:set_reward_softapplication][:reward]&&((User.current.id==@contest.author_id)||User.current.admin) - # @bid_id = params[:id] - @contesting_softapplication_id = params[:set_reward_softapplication][:c_id] - @c_sa = ContestingSoftapplication.find_by_id(@contesting_softapplication_id) - - # 把字段存进表中 - @c_sa.update_reward(params[:set_reward_softapplication][:reward].to_s) - end - - respond_to do |format| - format.js - end - end - - - ###添加已创建的参赛项目 - def add - project = Project.find(params[:contest]) - contest_message = params[:contest_for_save][:contest_message] - if ContestingProject.where("project_id = ? and contest_id = ?", project.id, @contest.id).size == 0 - # modified by longjun, create 写错了 - # if ContestingProject.cerate_contesting(@contest.id, project.id, contest_message) - if ContestingProject.create_contesting(@contest.id, project.id, contest_message) - # end longjun - - flash.now[:notice] = l(:label_bidding_contest_succeed) - end - else - flash.now[:error] = l(:label_bidding_fail) - end - - @contesting_project = paginateHelper @contest.contesting_projects - - respond_to do |format| - - format.html { redirect_to :back } - format.js - end - end - ###添加已发布的参赛应用 - def add_softapplication - softapplication = Softapplication.find(params[:contest]) - contest_message = params[:contest_for_save][:contest_message] - if ContestingSoftapplication.where("softapplication_id = ? and contest_id = ?", softapplication.id, @contest.id).size == 0 - if ContestingSoftapplication.create_softapplication_contesting(@contest.id, softapplication.id, contest_message) - flash.now[:notice] = l(:label_release_add_contest_succeed) - end - else - flash.now[:error] = l(:label_add_contest_succeed_fail) - end - - @contesting_softapplication = paginateHelper @contest.contesting_softapplications - - respond_to do |format| - - format.html { redirect_to :back } - format.js - end - end - ## 新建留言 - def create - - if params[:contest_message][:message].size>0 - if params[:reference_content] - message = params[:contest_message][:message] + "\n" + params[:reference_content] - else - message = params[:contest_message][:message] - end - refer_user_id = params[:contest_message][:reference_user_id].to_i - @contest.add_jour(User.current, message, refer_user_id) - end - @user = @contest.author - @jours = @contest.journals_for_messages.where('m_parent_id IS NULL').order('created_on DESC') - @limit = 10 - @feedback_count = @jours.count - @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] - @offset ||= @feedback_pages.offset - @jour = @jours[@offset, @limit] - @contest.set_commit(@feedback_count) - - respond_to do |format| - format.js - end - - end - - ##删除留言 - def destroy - @user = @contest.author - if User.current.admin? || User.current.id == @user.id - JournalsForMessage.delete_message(params[:object_id]) - end - @jours = @contest.journals_for_messages.reverse - @limit = 10 - @feedback_count = @jours.count - @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] - @offset ||= @feedback_pages.offset - @jour = @jours[@offset, @limit] - - @contest.set_commit(@feedback_count) - respond_to do |format| - format.js - end - end - - ##引用留言 - def new - @jour = JournalsForMessage.find(params[:journal_id]) if params[:journal_id] - if @jour - user = @jour.user - text = @jour.notes - else - user = @contest.author - text = @contest.description - end - text = text.to_s.strip.gsub(%r{
((.|\s)*?)}m, '[...]') - @content = "> #{ll(User.current.language, :text_user_wrote, user)}\n> " - @content << text.gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n" - @id = user.id - rescue ActiveRecord::RecordNotFound - render_404 - end - - ##新建竞赛 - def new_contest - @contest = Contest.new - @contest.safe_attributes = params[:contest] - end - - ##提交创建的竞赛 - def create_contest - @contest = Contest.new - @contest.name = params[:contest][:name] - @contest.description = params[:contest][:description] - @contest.budget = params[:contest][:budget] - @contest.deadline = params[:contest][:deadline] - @contest.password = params[:contest][:password] - @contest.author_id = User.current.id - @contest.commit = 0 - if @contest.save - unless @contest.watched_by?(User.current) - if @contest.add_watcher(User.current) - flash[:notice] = l(:label_contesting_created_succeed) - end - end - redirect_to show_contest_contest_url(@contest) - else - @contest.safe_attributes = params[:contest] - render :action => 'new_contest' - end - end - - ##更新竞赛配置信息 - def update_contest - @contest = Contest.find(params[:id]) - @contest.name = params[:contest][:name] - @contest.description = params[:contest][:description] - - @contest.budget = params[:contest][:budget] - @contest.deadline = params[:contest][:deadline] - @contest.password = params[:contest][:password] - @contest.author_id = User.current.id - @contest.commit = 0 - if @contest.save - unless @contest.watched_by?(User.current) - if @contest.add_watcher(User.current) - flash[:notice] = l(:label_contesting_updated_succeed) - end - end - redirect_to show_contest_contest_url(@contest) - - else - @contest.safe_attributes = params[:contest] - render :action => 'new_contest' - end - end - - def more - @jour = @contest.journals_for_messages - @jour.each_with_index {|j,i| j.indice = i+1} - @state = true - - respond_to do |format| - format.html { redirect_to :back } - format.js - #format.api { render_api_ok } - end - end - - def back - @jour = @contest.journals_for_messages - @jour.each_with_index {|j,i| j.indice = i+1} - @state = false - - respond_to do |format| - format.html { redirect_to :back } - format.js - #format.api { render_api_ok } - end - end - - def set_reward - @b_p = nil - @contesting_project_id = nil - - if params[:set_reward][:reward]&&((User.current.id==@contest.author_id)||User.current.admin) - # @contest_id = params[:id] - @contesting_project_id = params[:set_reward][:b_id] #[:b_id]??? - @b_p = ContestingProject.find_by_id(@contesting_project_id) - - # 把字段存进表中 - @b_p.update_reward(params[:set_reward][:reward].to_s) - end - - respond_to do |format| - format.js - end - end - - - - - private - - def find_contest - if params[:id] - @contest = Contest.find(params[:id]) - @user = @contest.author - end - rescue - render_404 - end - - #验证是否显示竞赛 - def can_show_contest - @first_page = FirstPage.find_by_page_type('project') - if @first_page.show_contest == 2 - render_404 - end - end - - # added by longjun - # 将index页面中分页排序的方法抽离出来 - def index_page_sort(offset, limit, contest_count, contests, contest_sort_by) - # modified by longjun - # never use unless and else - # unless @offset == 0 - if offset != 0 - contests = contests.reorder(contest_sort_by).offset(offset).limit(limit).all.reverse - else - limit = contest_count % limit - limit = limit if limit == 0 - contests = contests.reorder(contest_sort_by).offset(offset).limit(limit).all.reverse - end - contests - end -end - +# fq +# class BidsController < ApplicationController +class ContestsController < ApplicationController + layout "contest_base" + + menu_item :respond + menu_item :project, :only => :show_project + menu_item :application, :only => :show_softapplication + menu_item :attendingcontests, :only => :show_attendingcontest + menu_item :contestnotifications, :only => :index + + before_filter :can_show_contest, :except => [] # modified by alan + + # modified by longjun + before_filter :find_contest, :only => [ + :show_contest, :show_project, :show_softapplication, + :show_attendingcontest, :index, :set_reward_project, + :set_reward_softapplication, :create, :destroy, :more, + :back, :add, :add_softapplication, :new,:show_results, + :set_reward, :show_contest_project, :show_contest_user, :watcherlist, + :join_in_contest, :unjoin_in_contest, :new_join, :settings + ] + # end longjun + + # added by fq + before_filter :require_login, :only => [:join_in_contest, :unjoin_in_contest] + # end + before_filter :require_login,:only => [:set_reward, :destroy, :add, :new ] + + helper :watchers + helper :attachments + helper :projects + helper :words + + include AttachmentsHelper + include ApplicationHelper + + + def index + # @contests = Contest.visible + # @contests ||= [] + @offset, @limit = api_offset_and_limit(:limit => 10) + #@contests = Contest.visible + #@contests = @contests.like(params[:name]) if params[:name].present? + @contests = Contest.visible.where("name like '%#{params[:name]}%'") + if params[:contests_search] + (redirect_to contests_url, :notice => l(:label_sumbit_empty);return) if params[:name].blank? + end + @contest_count = @contests.count + @contest_pages = Paginator.new @contest_count, @limit, params['page'] + + @offset ||= @contest_pages.reverse_offset + if params[:contest_sort_type].present? + case params[:contest_sort_type] + when '0' + # modified by longjun + # never use unless and else, 将下面重复操作模块化,放在private下 + # unless @offset == 0 + # if @offset != 0 + # @contests = @contests.reorder('contests.commit').offset(@offset).limit(@limit).all.reverse + # else + # limit = @contest_count % @limit + # limit = @limit if limit == 0 + # @contests = @contests.reorder('contests.commit').offset(@offset).limit(limit).all.reverse + + @contests = index_page_sort(@offset, @limit, @contest_count, @contests, 'contests.commit') + # end + @s_state = 0 + when '1' + + @contests = index_page_sort(@offset, @limit, @contest_count, @contests, 'contests.created_on') + @s_state = 1 + # modified by longjun + # 目前只有 0, 1 两个sort_type + # when '2' + else + # end longjun + + @contests = index_page_sort(@offset, @limit, @contest_count, @contests, '') + @s_state = 0 + end + else + # modified by longjun + # never use unless and else + # unless @offset == 0 + if @offset != 0 + @contests = @contests.reorder('contests.created_on').offset(@offset).limit(@limit).all.reverse + else + limit = @contest_count % @limit + limit = @limit if limit == 0 + @contests = @contests.reorder('contests.created_on').offset(@offset).limit(limit).all.reverse + end + @s_state = 1 + end + end + + def search + redirect_to action: 'index',name:params[:name] + end + + def homework + @offset, @limit = api_offset_and_limit({:limit => 10}) + @bids = @course.homeworks.order('deadline DESC') + @bids = @bids.like(params[:name]) if params[:name].present? + @bid_count = @bids.count + @bid_pages = Paginator.new @bid_count, @limit, params['page'] + + @offset ||= @bid_pages.reverse_offset + # modified by longjun + # never use unless and else + # unless @offset == 0 + if @offset != 0 + @bids = @bids.offset(@offset).limit(@limit).all.reverse + else + limit = @bid_count % @limit + @bids = @bids.offset(@offset).limit(limit).all.reverse + end + render :layout => 'base_courses' + + end + + + def show_contest + @user = @contest.author + @jours = @contest.journals_for_messages.where('m_parent_id IS NULL').order('created_on DESC') + @limit = 10 + @feedback_count = @jours.count + @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] + @offset ||= @feedback_pages.offset + @jour = @jours[@offset, @limit] + @state = false + + respond_to do |format| + layout_file = 'base_newcontest' + format.html { + render :layout => layout_file + } + format.api + end + end + + def join_in_contest + if params[:contest_password] == @contest.password + JoinInCompetition.create(:user_id => User.current.id, :competition_id => @contest.id) + @state = 0 + else + @state = 1 + end + + respond_to do |format| + format.js { render :partial => 'set_join', :locals => {:user => User.current, :object_id => params[:id]} } + end + end + + def unjoin_in_contest + + joined = JoinInCompetition.where('competition_id = ? and user_id = ?', @contest.id, User.current.id) + + joined.each do |join| + join.delete + end + + respond_to do |format| + format.js { render :partial => 'set_join', :locals => {:user => User.current, :object_id => params[:id]} } + end + end + + + + def show_participator + render :layout => 'base_newcontest' + + end + + + def settings + if @contest.author.id == User.current.id + @contest = Contest.find(params[:id]) + render :layout => 'base_newcontest' + else + render_403 :message => :notice_not_contest_setting_authorized + end + end + + # Added by Longjun + def destroy_contest + @contest = Contest.find(params[:id]) + if @contest.author_id == User.current.id + + @contest.destroy + redirect_to action: 'index' + else + render_403 :message => :notice_not_contest_delete_authorized + end + + end + # end + + def show_contest_project + contests = Contest.where('parent_id = ?', @contest.id) + @projects = [] + + # Modified by longjun + # 用 arr.each 替换 for [ according to the style guide ] + + # for contest in contests + # @projects += contest.contesting_projects + # end + + contests.each do |contest| + @projects += contest.contesting_projects + end + + # end + + respond_to do |format| + format.html { + render :layout => 'base_newcontest' + } + format.api + end + end + + def show_contest_softapplication + contests = Contest.where('parent_id = ?', @contest.id) + @softapplications = [] + + # Modified by Longjun + # for contest in contests + # @softapplications += contest.contesting_softapplications + + + contests.each do |contest| + @softapplications += contest.contesting_softapplications + end + + # end + + respond_to do |format| + format.html { + render :layout => 'base_newcontest' + } + format.api + + end + end + + def show_contest_user + contests = Contest.find(:all) + @users = [] + + # Modified by Longjun + # for contest in contests + # for project in contest.projects + # @users += project.users + # end + + + contests.each do |contest| + contest.projects.each do |project| + @users += project.users + end + end + # end + + respond_to do |format| + format.html { + render :layout => 'base_newcontest' + } + format.api + + end + end + #显示参赛的项目 + def show_project + @membership = User.current.memberships.all(:conditions => Project.visible_condition(User.current)) + @option = [] + # @contesting_project_count = @contesting_project_all.count + # @contesting_project_pages = Paginator.new @contesting_project_count, per_page_option, params['page'] + @membership.each do |membership| + + # Modified by Longjun + # 将两个判断语句合并 + # unless membership.project.project_type==1 + # if User.current.allowed_to?(:quote_project, membership.project) + # @option << membership.project + # end + # end + if membership.project.project_type != 1 && User.current.allowed_to?(:quote_project, membership.project) + @option << membership.project + + end + # end + + end + @user = @contest.author + @contesting_project = @contest.contesting_projects.all + if params[:student_id].present? + @temp = [] + @contesting_project.each do |pro| + if pro.project && pro.project.project_status + if /#{params[:student_id]}/ =~ pro.user.user_extensions.student_id + @temp << pro + end + end + @temp + end + @contesting_project = @temp + else + + @temp = [] + @contesting_project.each do |pro| + # modified by longjun + # if pro.project && pro.project.project_status + # @temp << pro + # end + @temp << pro if pro.project && pro.project.project_status + # end longjun + @temp + end + if @temp.size > 0 + @contesting_project = @temp.sort {|a,b| b.project.project_status.grade <=> a.project.project_status.grade} + end + end + @contesting_project = paginateHelper(@contesting_project) + respond_to do |format| + format.html { + render :layout => 'base_newcontest' + } + format.api + end + end + ############ + ##显示参赛的应用 + def show_softapplication + + # @membership = User.current.memberships.all(:conditions => Project.visible_condition(User.current)) + # @option = [] + + # @user = @contest.user + @softapplication = Softapplication.all + @contesting_softapplication = @contest.contesting_softapplications + + @contesting_softapplication = paginateHelper(@contesting_softapplication, 10) + + # @temp = [] + # @softapplicationt.each do |pro| + # if pro.project && pro.project.project_status + # @temp << pro + # end + # @temp + + # if @temp.size > 0 + # @contesting_project = @temp.sort {|a,b| b.project.project_status.grade <=> a.project.project_status.grade} + # end + # end + # respond_to do |format| + # format.html { + # render :layout => 'base_newcontest' + # } + # format.api + # end +########################## + @contest = Contest.find_by_id(params[:id]) + respond_to do |format| + format.html { + render :layout => 'base_newcontest' + } + format.api + end + end + + + ###我要参赛 + def show_attendingcontest +##取出参赛项目--项目列表 + @membership = User.current.memberships.all(:conditions => Project.visible_condition(User.current)) + @option = [] + # @contesting_project_count = @contesting_project_all.count + # @contesting_project_pages = Paginator.new @contesting_project_count, per_page_option, params['page'] + @membership.each do |membership| + unless membership.project.project_type==1 + #拥有编辑项目权限的可将该项目参赛 + if User.current.allowed_to?(:quote_project, membership.project) + @option << membership.project + end + end + end + @user = @contest.author + @contesting_project = @contest.contesting_projects.all + if params[:student_id].present? + @temp = [] + @contesting_project.each do |pro| + if pro.project && pro.project.project_status + if /#{params[:student_id]}/ =~ pro.user.user_extensions.student_id + @temp << pro + end + end + @temp + end + @contesting_project = @temp + else + + @temp = [] + @contesting_project.each do |pro| + # modified by longjun + # if pro.project && pro.project.project_status + # @temp << pro + # end + @temp << pro if pro.project && pro.project.project_status + # end longjun + @temp + end + if @temp.size > 0 + @contesting_project = @temp.sort {|a,b| b.project.project_status.grade <=> a.project.project_status.grade} + end + end + # 取出参赛应用 --应用列表 + @softapplication = Softapplication.all + @contesting_softapplication = @contest.contesting_softapplications. + joins("LEFT JOIN softapplications ON contesting_softapplications.softapplication_id=softapplications.id"). + joins("LEFT JOIN ( + SELECT * FROM seems_rateable_cached_ratings + WHERE cacheable_type='Softapplication' AND DIMENSION = 'quality') AS cached + ON cached.cacheable_id=softapplications.id"). + order("cached.avg").reverse_order + @contesting_softapplication = paginateHelper @contesting_softapplication, 10 + + + #引用base_newcontest整体样式 + @contest = Contest.find_by_id(params[:id]) + respond_to do |format| + format.html { + render :layout => 'base_newcontest' + } + format.api + end + end + + ###end + + def show_notification + @contest = Contest.find_by_id(params[:id]) + respond_to do |format| + format.html { + render :layout => 'base_newcontest' + } + format.api + end + end + + + def set_reward_project + @c_p = nil + @contesting_project_id = nil + + if params[:set_reward_project][:reward]&&((User.current.id==@contest.author_id)||User.current.admin) + # @bid_id = params[:id] + @contesting_project_id = params[:set_reward_project][:c_id] + @c_p = ContestingProject.find_by_id(@contesting_project_id) + + # 把字段存进表中 + @c_p.update_reward(params[:set_reward_project][:reward].to_s) + end + + respond_to do |format| + format.js + end + end + + def set_reward_softapplication + @c_sa = nil + @contesting_softapplication_id = nil + + if params[:set_reward_softapplication][:reward]&&((User.current.id==@contest.author_id)||User.current.admin) + # @bid_id = params[:id] + @contesting_softapplication_id = params[:set_reward_softapplication][:c_id] + @c_sa = ContestingSoftapplication.find_by_id(@contesting_softapplication_id) + + # 把字段存进表中 + @c_sa.update_reward(params[:set_reward_softapplication][:reward].to_s) + end + + respond_to do |format| + format.js + end + end + + + ###添加已创建的参赛项目 + def add + project = Project.find(params[:contest]) + contest_message = params[:contest_for_save][:contest_message] + if ContestingProject.where("project_id = ? and contest_id = ?", project.id, @contest.id).size == 0 + # modified by longjun, create 写错了 + # if ContestingProject.cerate_contesting(@contest.id, project.id, contest_message) + if ContestingProject.create_contesting(@contest.id, project.id, contest_message) + # end longjun + + flash.now[:notice] = l(:label_bidding_contest_succeed) + end + else + flash.now[:error] = l(:label_bidding_fail) + end + + @contesting_project = paginateHelper @contest.contesting_projects + + respond_to do |format| + + format.html { redirect_to :back } + format.js + end + end + ###添加已发布的参赛应用 + def add_softapplication + softapplication = Softapplication.find(params[:contest]) + contest_message = params[:contest_for_save][:contest_message] + if ContestingSoftapplication.where("softapplication_id = ? and contest_id = ?", softapplication.id, @contest.id).size == 0 + if ContestingSoftapplication.create_softapplication_contesting(@contest.id, softapplication.id, contest_message) + flash.now[:notice] = l(:label_release_add_contest_succeed) + end + else + flash.now[:error] = l(:label_add_contest_succeed_fail) + end + + @contesting_softapplication = paginateHelper @contest.contesting_softapplications + + respond_to do |format| + + format.html { redirect_to :back } + format.js + end + end + ## 新建留言 + def create + + if params[:contest_message][:message].size>0 + if params[:reference_content] + message = params[:contest_message][:message] + "\n" + params[:reference_content] + else + message = params[:contest_message][:message] + end + refer_user_id = params[:contest_message][:reference_user_id].to_i + @contest.add_jour(User.current, message, refer_user_id) + end + @user = @contest.author + @jours = @contest.journals_for_messages.where('m_parent_id IS NULL').order('created_on DESC') + @limit = 10 + @feedback_count = @jours.count + @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] + @offset ||= @feedback_pages.offset + @jour = @jours[@offset, @limit] + @contest.set_commit(@feedback_count) + + respond_to do |format| + format.js + end + + end + + ##删除留言 + def destroy + @user = @contest.author + if User.current.admin? || User.current.id == @user.id + JournalsForMessage.delete_message(params[:object_id]) + end + @jours = @contest.journals_for_messages.reverse + @limit = 10 + @feedback_count = @jours.count + @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] + @offset ||= @feedback_pages.offset + @jour = @jours[@offset, @limit] + + @contest.set_commit(@feedback_count) + respond_to do |format| + format.js + end + end + + ##引用留言 + def new + @jour = JournalsForMessage.find(params[:journal_id]) if params[:journal_id] + if @jour + user = @jour.user + text = @jour.notes + else + user = @contest.author + text = @contest.description + end + text = text.to_s.strip.gsub(%r{
((.|\s)*?)}m, '[...]') + @content = "> #{ll(User.current.language, :text_user_wrote, user)}\n> " + @content << text.gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n" + @id = user.id + rescue ActiveRecord::RecordNotFound + render_404 + end + + ##新建竞赛 + def new_contest + @contest = Contest.new + @contest.safe_attributes = params[:contest] + end + + ##提交创建的竞赛 + def create_contest + @contest = Contest.new + @contest.name = params[:contest][:name] + @contest.description = params[:contest][:description] + @contest.budget = params[:contest][:budget] + @contest.deadline = params[:contest][:deadline] + @contest.password = params[:contest][:password] + @contest.author_id = User.current.id + @contest.commit = 0 + if @contest.save + unless @contest.watched_by?(User.current) + if @contest.add_watcher(User.current) + flash[:notice] = l(:label_contesting_created_succeed) + end + end + redirect_to show_contest_contest_url(@contest) + else + @contest.safe_attributes = params[:contest] + render :action => 'new_contest' + end + end + + ##更新竞赛配置信息 + def update_contest + @contest = Contest.find(params[:id]) + @contest.name = params[:contest][:name] + @contest.description = params[:contest][:description] + + @contest.budget = params[:contest][:budget] + @contest.deadline = params[:contest][:deadline] + @contest.password = params[:contest][:password] + @contest.author_id = User.current.id + @contest.commit = 0 + if @contest.save + unless @contest.watched_by?(User.current) + if @contest.add_watcher(User.current) + flash[:notice] = l(:label_contesting_updated_succeed) + end + end + redirect_to show_contest_contest_url(@contest) + + else + @contest.safe_attributes = params[:contest] + render :action => 'new_contest' + end + end + + def more + @jour = @contest.journals_for_messages + @jour.each_with_index {|j,i| j.indice = i+1} + @state = true + + respond_to do |format| + format.html { redirect_to :back } + format.js + #format.api { render_api_ok } + end + end + + def back + @jour = @contest.journals_for_messages + @jour.each_with_index {|j,i| j.indice = i+1} + @state = false + + respond_to do |format| + format.html { redirect_to :back } + format.js + #format.api { render_api_ok } + end + end + + def set_reward + @b_p = nil + @contesting_project_id = nil + + if params[:set_reward][:reward]&&((User.current.id==@contest.author_id)||User.current.admin) + # @contest_id = params[:id] + @contesting_project_id = params[:set_reward][:b_id] #[:b_id]??? + @b_p = ContestingProject.find_by_id(@contesting_project_id) + + # 把字段存进表中 + @b_p.update_reward(params[:set_reward][:reward].to_s) + end + + respond_to do |format| + format.js + end + end + def watcherlist + render :layout => 'base_newcontest' + end + + + + private + + def find_contest + if params[:id] + @contest = Contest.find(params[:id]) + @user = @contest.author + end + rescue + render_404 + end + + #验证是否显示竞赛 + def can_show_contest + @first_page = FirstPage.find_by_page_type('project') + if @first_page.show_contest == 2 + render_404 + end + end + + # added by longjun + # 将index页面中分页排序的方法抽离出来 + def index_page_sort(offset, limit, contest_count, contests, contest_sort_by) + # modified by longjun + # never use unless and else + # unless @offset == 0 + if offset != 0 + contests = contests.reorder(contest_sort_by).offset(offset).limit(limit).all.reverse + else + limit = contest_count % limit + limit = limit if limit == 0 + contests = contests.reorder(contest_sort_by).offset(offset).limit(limit).all.reverse + end + contests + end +end + diff --git a/app/controllers/custom_fields_controller.rb b/app/controllers/custom_fields_controller.rb index d017de5ca..2d06af9ba 100644 --- a/app/controllers/custom_fields_controller.rb +++ b/app/controllers/custom_fields_controller.rb @@ -1,81 +1,81 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class CustomFieldsController < ApplicationController - layout 'admin' - - before_filter :require_admin - before_filter :build_new_custom_field, :only => [:new, :create] - before_filter :find_custom_field, :only => [:edit, :update, :destroy] - - def index - @custom_fields_by_type = CustomField.all.group_by {|f| f.class.name } - @tab = params[:tab] || 'IssueCustomField' - end - - def new - end - - def create - if @custom_field.save - flash[:notice] = l(:notice_successful_create) - call_hook(:controller_custom_fields_new_after_save, :params => params, :custom_field => @custom_field) - redirect_to custom_fields_url(:tab => @custom_field.class.name) - else - render :action => 'new' - end - end - - def edit - end - - def update - if @custom_field.update_attributes(params[:custom_field]) - flash[:notice] = l(:notice_successful_update) - call_hook(:controller_custom_fields_edit_after_save, :params => params, :custom_field => @custom_field) - redirect_to custom_fields_url(:tab => @custom_field.class.name) - else - render :action => 'edit' - end - end - - def destroy - begin - @custom_field.destroy - rescue - flash[:error] = l(:error_can_not_delete_custom_field) - end - redirect_to custom_fields_url(:tab => @custom_field.class.name) - end - - private - - def build_new_custom_field - @custom_field = CustomField.new_subclass_instance(params[:type], params[:custom_field]) - if @custom_field.nil? - render_404 - else - @custom_field.default_value = nil - end - end - - def find_custom_field - @custom_field = CustomField.find(params[:id]) - rescue ActiveRecord::RecordNotFound - render_404 - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class CustomFieldsController < ApplicationController + layout 'admin' + + before_filter :require_admin + before_filter :build_new_custom_field, :only => [:new, :create] + before_filter :find_custom_field, :only => [:edit, :update, :destroy] + + def index + @custom_fields_by_type = CustomField.all.group_by {|f| f.class.name } + @tab = params[:tab] || 'IssueCustomField' + end + + def new + end + + def create + if @custom_field.save + flash[:notice] = l(:notice_successful_create) + call_hook(:controller_custom_fields_new_after_save, :params => params, :custom_field => @custom_field) + redirect_to custom_fields_url(:tab => @custom_field.class.name) + else + render :action => 'new' + end + end + + def edit + end + + def update + if @custom_field.update_attributes(params[:custom_field]) + flash[:notice] = l(:notice_successful_update) + call_hook(:controller_custom_fields_edit_after_save, :params => params, :custom_field => @custom_field) + redirect_to custom_fields_url(:tab => @custom_field.class.name) + else + render :action => 'edit' + end + end + + def destroy + begin + @custom_field.destroy + rescue + flash[:error] = l(:error_can_not_delete_custom_field) + end + redirect_to custom_fields_url(:tab => @custom_field.class.name) + end + + private + + def build_new_custom_field + @custom_field = CustomField.new_subclass_instance(params[:type], params[:custom_field]) + if @custom_field.nil? + render_404 + else + @custom_field.default_value = nil + end + end + + def find_custom_field + @custom_field = CustomField.find(params[:id]) + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff --git a/app/controllers/documents_controller.rb b/app/controllers/documents_controller.rb index bf2a7b303..2fcc2e89b 100644 --- a/app/controllers/documents_controller.rb +++ b/app/controllers/documents_controller.rb @@ -1,120 +1,120 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class DocumentsController < ApplicationController - layout 'base_projects'#by young - default_search_scope :documents - model_object Document - before_filter :find_project_by_project_id, :only => [:index, :new, :create] - before_filter :find_model_object, :except => [:index, :new, :create] - before_filter :find_project_from_association, :except => [:index, :new, :create] - before_filter :authorize , :except => [:index]#Added by young - before_filter :authorize_document - - helper :attachments - helper :project_score - - def index - @sort_by = %w(category date title author).include?(params[:sort_by]) ? params[:sort_by] : 'category' - temp = @project.documents.includes(:attachments, :category).all - documents = [] - temp.each do |doc| - if doc.has_right?(@project) - documents << doc - end - end - case @sort_by - when 'date' - @grouped = documents.group_by {|d| d.updated_on.to_date } - when 'title' - @grouped = documents.group_by {|d| d.title.first.upcase} - when 'author' - # @grouped = documents.select{|d| d.attachments.any?}.group_by {|d| d.attachments.last.author} - @grouped = documents.group_by {|d| d.user.name } - else - @grouped = documents.group_by(&:category) - end - @document = @project.documents.build - if @project.project_type == 1 - render :layout => 'base_courses' - else - render :layout => false if request.xhr? - end - end - - def show - @attachments = @document.attachments.all - if @project.project_type ==1 - render :action => 'show', :layout => 'base_courses' - end - end - - def new - @document = @project.documents.build - @document.safe_attributes = params[:document] - end - - def create - @document = @project.documents.build - @document.safe_attributes = params[:document] - @document.user = User.current - @document.save_attachments(params[:attachments]) - if @document.save - render_attachment_warning_if_needed(@document) - flash[:notice] = l(:notice_successful_create) - redirect_to project_documents_url(@project) - else - render :action => 'new' - end - end - - def edit - end - - def update - @document.safe_attributes = params[:document] - if request.put? and @document.save - flash[:notice] = l(:notice_successful_update) - redirect_to document_url(@document) - else - render :action => 'edit' - end - end - - def destroy - @document.destroy if request.delete? - redirect_to project_documents_url(@project) - end - - def add_attachment - attachments = Attachment.attach_files(@document, params[:attachments]) - render_attachment_warning_if_needed(@document) - - if attachments.present? && attachments[:files].present? && Setting.notified_events.include?('document_added') - Mailer.attachments_added(attachments[:files]).deliver - end - redirect_to document_url(@document) - end - - # 权限判断 - # add by nwb - def authorize_document - if !(User.current.admin? || User.current.member_of?(@project) || @document == nil || (@document != nil && @document.is_public==1)) - render_403 :message => :notice_not_authorized - end - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class DocumentsController < ApplicationController + layout 'base_projects'#by young + default_search_scope :documents + model_object Document + before_filter :find_project_by_project_id, :only => [:index, :new, :create] + before_filter :find_model_object, :except => [:index, :new, :create] + before_filter :find_project_from_association, :except => [:index, :new, :create] + before_filter :authorize , :except => [:index]#Added by young + before_filter :authorize_document + + helper :attachments + helper :project_score + + def index + @sort_by = %w(category date title author).include?(params[:sort_by]) ? params[:sort_by] : 'category' + temp = @project.documents.includes(:attachments, :category).all + documents = [] + temp.each do |doc| + if doc.has_right?(@project) + documents << doc + end + end + case @sort_by + when 'date' + @grouped = documents.group_by {|d| d.updated_on.to_date } + when 'title' + @grouped = documents.group_by {|d| d.title.first.upcase} + when 'author' + # @grouped = documents.select{|d| d.attachments.any?}.group_by {|d| d.attachments.last.author} + @grouped = documents.group_by {|d| d.user.name } + else + @grouped = documents.group_by(&:category) + end + @document = @project.documents.build + if @project.project_type == 1 + render :layout => 'base_courses' + else + render :layout => false if request.xhr? + end + end + + def show + @attachments = @document.attachments.all + if @project.project_type ==1 + render :action => 'show', :layout => 'base_courses' + end + end + + def new + @document = @project.documents.build + @document.safe_attributes = params[:document] + end + + def create + @document = @project.documents.build + @document.safe_attributes = params[:document] + @document.user = User.current + @document.save_attachments(params[:attachments]) + if @document.save + render_attachment_warning_if_needed(@document) + flash[:notice] = l(:notice_successful_create) + redirect_to project_documents_url(@project) + else + render :action => 'new' + end + end + + def edit + end + + def update + @document.safe_attributes = params[:document] + if request.put? and @document.save + flash[:notice] = l(:notice_successful_update) + redirect_to document_url(@document) + else + render :action => 'edit' + end + end + + def destroy + @document.destroy if request.delete? + redirect_to project_documents_url(@project) + end + + def add_attachment + attachments = Attachment.attach_files(@document, params[:attachments]) + render_attachment_warning_if_needed(@document) + + if attachments.present? && attachments[:files].present? && Setting.notified_events.include?('document_added') + Mailer.attachments_added(attachments[:files]).deliver + end + redirect_to document_url(@document) + end + + # 权限判断 + # add by nwb + def authorize_document + if !(User.current.admin? || User.current.member_of?(@project) || @document == nil || (@document != nil && @document.is_public==1)) + render_403 :message => :notice_not_authorized + end + end +end diff --git a/app/controllers/enumerations_controller.rb b/app/controllers/enumerations_controller.rb index 58e76ed4a..de9414de5 100644 --- a/app/controllers/enumerations_controller.rb +++ b/app/controllers/enumerations_controller.rb @@ -1,98 +1,98 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class EnumerationsController < ApplicationController - layout 'admin' - - before_filter :require_admin, :except => :index - before_filter :require_admin_or_api_request, :only => :index - before_filter :build_new_enumeration, :only => [:new, :create] - before_filter :find_enumeration, :only => [:edit, :update, :destroy] - accept_api_auth :index - - helper :custom_fields - - def index - respond_to do |format| - format.html - format.api { - @klass = Enumeration.get_subclass(params[:type]) - if @klass - @enumerations = @klass.shared.sorted.all - else - render_404 - end - } - end - end - - def new - end - - def create - if request.post? && @enumeration.save - flash[:notice] = l(:notice_successful_create) - redirect_to enumerations_url - else - render :action => 'new' - end - end - - def edit - end - - def update - if request.put? && @enumeration.update_attributes(params[:enumeration]) - flash[:notice] = l(:notice_successful_update) - redirect_to enumerations_url - else - render :action => 'edit' - end - end - - def destroy - if !@enumeration.in_use? - # No associated objects - @enumeration.destroy - redirect_to enumerations_url - return - elsif params[:reassign_to_id] - if reassign_to = @enumeration.class.find_by_id(params[:reassign_to_id]) - @enumeration.destroy(reassign_to) - redirect_to enumerations_url - return - end - end - @enumerations = @enumeration.class.all - [@enumeration] - end - - private - - def build_new_enumeration - class_name = params[:enumeration] && params[:enumeration][:type] || params[:type] - @enumeration = Enumeration.new_subclass_instance(class_name, params[:enumeration]) - if @enumeration.nil? - render_404 - end - end - - def find_enumeration - @enumeration = Enumeration.find(params[:id]) - rescue ActiveRecord::RecordNotFound - render_404 - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class EnumerationsController < ApplicationController + layout 'admin' + + before_filter :require_admin, :except => :index + before_filter :require_admin_or_api_request, :only => :index + before_filter :build_new_enumeration, :only => [:new, :create] + before_filter :find_enumeration, :only => [:edit, :update, :destroy] + accept_api_auth :index + + helper :custom_fields + + def index + respond_to do |format| + format.html + format.api { + @klass = Enumeration.get_subclass(params[:type]) + if @klass + @enumerations = @klass.shared.sorted.all + else + render_404 + end + } + end + end + + def new + end + + def create + if request.post? && @enumeration.save + flash[:notice] = l(:notice_successful_create) + redirect_to enumerations_url + else + render :action => 'new' + end + end + + def edit + end + + def update + if request.put? && @enumeration.update_attributes(params[:enumeration]) + flash[:notice] = l(:notice_successful_update) + redirect_to enumerations_url + else + render :action => 'edit' + end + end + + def destroy + if !@enumeration.in_use? + # No associated objects + @enumeration.destroy + redirect_to enumerations_url + return + elsif params[:reassign_to_id] + if reassign_to = @enumeration.class.find_by_id(params[:reassign_to_id]) + @enumeration.destroy(reassign_to) + redirect_to enumerations_url + return + end + end + @enumerations = @enumeration.class.all - [@enumeration] + end + + private + + def build_new_enumeration + class_name = params[:enumeration] && params[:enumeration][:type] || params[:type] + @enumeration = Enumeration.new_subclass_instance(class_name, params[:enumeration]) + if @enumeration.nil? + render_404 + end + end + + def find_enumeration + @enumeration = Enumeration.find(params[:id]) + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff --git a/app/controllers/files_controller.rb b/app/controllers/files_controller.rb index 313afa1c7..234d09d1c 100644 --- a/app/controllers/files_controller.rb +++ b/app/controllers/files_controller.rb @@ -1,280 +1,280 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class FilesController < ApplicationController - layout 'base_projects'#by young - menu_item :files - - before_filter :find_project_by_project_id#, :except => [:getattachtype] - before_filter :authorize, :except => [:getattachtype] - - helper :sort - include SortHelper - helper :project_score - - def show_attachments obj - all_attachments = [] - obj.each do |container| - all_attachments += container.attachments - end - @limit = 10 - @feedback_count = all_attachments.count - @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] - @offset ||= @feedback_pages.offset - @curse_attachments = all_attachments[@offset, @limit] - end - - def index - #sort_init 'filename', 'asc' - sort_init 'created_on', 'desc' - sort_update 'created_on' => "#{Attachment.table_name}.created_on", - 'filename' => "#{Attachment.table_name}.filename", - 'size' => "#{Attachment.table_name}.filesize", - 'downloads' => "#{Attachment.table_name}.downloads" - sort = "" - - if params[:project_id] - @isproject = true - - if params[:sort] - params[:sort].split(",").each do |sort_type| - order_by = sort_type.split(":") - - case order_by[0] - when "filename" - attribute = "filename" - when "size" - attribute = "filesize" - when "attach_type" - attribute = "attachtype" - when "content_type" - attribute = "created_on" - when "field_file_dense" - attribute = "is_public" - when "downloads" - attribute = "downloads" - when "created_on" - attribute = "created_on" - end - - if order_by.count == 1 - sort += "#{Attachment.table_name}.#{attribute} desc " - elsif order_by.count == 2 - sort += "#{Attachment.table_name}.#{attribute} #{order_by[1]} " - end - if sort_type != params[:sort].split(",").last - sort += "," - end - end - end - - @containers = [ Project.includes(:attachments).reorder(sort).find(@project.id)] - @containers += @project.versions.includes(:attachments).reorder(sort).all.sort - - show_attachments @containers - - render :layout => !request.xhr? - elsif params[:course_id] - @isproject = false - - if params[:sort] - params[:sort].split(",").each do |sort_type| - order_by = sort_type.split(":") - - case order_by[0] - when "filename" - attribute = "filename" - when "size" - attribute = "filesize" - when "attach_type" - attribute = "attachtype" - when "content_type" - attribute = "created_on" - when "field_file_dense" - attribute = "is_public" - when "downloads" - attribute = "downloads" - when "created_on" - attribute = "created_on" - end - - if order_by.count == 1 - sort += "#{Attachment.table_name}.#{attribute} asc " - elsif order_by.count == 2 - sort += "#{Attachment.table_name}.#{attribute} #{order_by[1]} " - end - if sort_type != params[:sort].split(",").last - sort += "," - end - end - end - @containers = [ Course.includes(:attachments).reorder(sort).find(@course.id)] - - show_attachments @containers - - render :layout => 'base_courses' - end - - end - - def new - @versions = @project.versions.sort - @course_tag = @project.project_type - if @project.project_type == 1 - render :layout => 'base_courses' - end - end - - def create - if params[:add_tag] - @addTag=true - #render :back - tag_saveEx - #render :text =>"success" - respond_to do |format| - format.js - end - else - #modify by nwb - if @project - @addTag=false - container = (params[:version_id].blank? ? @project : @project.versions.find_by_id(params[:version_id])) - attachments = Attachment.attach_filesex(container, params[:attachments], params[:attachment_type]) - render_attachment_warning_if_needed(container) - - if !attachments.empty? && !attachments[:files].blank? && Setting.notified_events.include?('file_added') - Mailer.attachments_added(attachments[:files]).deliver - end - - # TODO: 临时用 nyan - sort_init 'created_on', 'desc' - sort_update 'created_on' => "#{Attachment.table_name}.created_on", - 'filename' => "#{Attachment.table_name}.filename", - 'size' => "#{Attachment.table_name}.filesize", - 'downloads' => "#{Attachment.table_name}.downloads" - - @containers = [Project.includes(:attachments).reorder("#{Attachment.table_name}.created_on DESC").find(@project.id)] #modify by Long Jun - @containers += @project.versions.includes(:attachments).reorder("#{Attachment.table_name}.created_on DESC").all.sort - - show_attachments @containers - - @attachtype = 0 - @contenttype = 0 - - respond_to do |format| - format.js - format.html { - redirect_to project_files_url(@project) - } - end - elsif @course - @addTag=false - attachments = Attachment.attach_filesex(@course, params[:attachments], params[:attachment_type]) - - if !attachments.empty? && !attachments[:files].blank? && Setting.notified_events.include?('file_added') - Mailer.attachments_added(attachments[:files]).deliver - end - - # TODO: 临时用 nyan - sort_init 'created_on', 'desc' - sort_update 'created_on' => "#{Attachment.table_name}.created_on", - 'filename' => "#{Attachment.table_name}.filename", - 'size' => "#{Attachment.table_name}.filesize", - 'downloads' => "#{Attachment.table_name}.downloads" - - @containers = [Course.includes(:attachments).reorder("#{Attachment.table_name}.created_on DESC").find(@course.id)] - - show_attachments @containers - - @attachtype = 0 - @contenttype = 0 - - respond_to do |format| - format.js - format.html { - redirect_to course_files_url(@course) - } - end - end - - end - end - - def tag_saveEx - @tags = params[:tag_name][:name] - @obj_id = params[:object_id] - @obj_flag = params[:object_flag] - - case @obj_flag - when '1' then - @obj = User.find_by_id(@obj_id) - when '2' then - @obj = Project.find_by_id(@obj_id) - when '3' then - @obj = Issue.find_by_id(@obj_id) - when '4' then - @obj = Bid.find_by_id(@obj_id) - when '5' then - @obj = Forum.find_by_id(@obj_id) - when '6' - @obj = Attachment.find_by_id(@obj_id) - when '7' then - @obj = Contest.find_by_id(@obj_id) - when '8' - @obj = OpenSourceProject.find_by_id(@obj_id) - when '9' - @obj = Course.find_by_id(@obj_id) - else - @obj = nil - end - unless @obj.nil? - @obj.tag_list.add(@tags.split(",")) - else - return - end - if @obj.save - ## 执行成功的操作。 - else - #捕获异常 - end - end - - # 返回指定资源类型的资源列表 - # added by nwb - def getattachtype - sort_init 'created_on', 'desc' - sort_update 'created_on' => "#{Attachment.table_name}.created_on", - 'filename' => "#{Attachment.table_name}.filename", - 'size' => "#{Attachment.table_name}.filesize", - 'downloads' => "#{Attachment.table_name}.downloads" - - if @project - @containers = [ Project.includes(:attachments).reorder("#{Attachment.table_name}.created_on DESC").find(@project.id)] - @containers += @project.versions.includes(:attachments).reorder("#{Attachment.table_name}.created_on DESC").all.sort - elsif @course - @containers = [ Course.includes(:attachments).reorder("#{Attachment.table_name}.created_on DESC").find(@course.id)] - end - show_attachments @containers - - @attachtype = params[:type].to_i - @contenttype = params[:contentType].to_s - - respond_to do |format| - format.js - end - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class FilesController < ApplicationController + layout 'base_projects'#by young + menu_item :files + + before_filter :find_project_by_project_id#, :except => [:getattachtype] + before_filter :authorize, :except => [:getattachtype] + + helper :sort + include SortHelper + helper :project_score + + def show_attachments obj + all_attachments = [] + obj.each do |container| + all_attachments += container.attachments + end + @limit = 10 + @feedback_count = all_attachments.count + @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] + @offset ||= @feedback_pages.offset + @curse_attachments = all_attachments[@offset, @limit] + end + + def index + #sort_init 'filename', 'asc' + sort_init 'created_on', 'desc' + sort_update 'created_on' => "#{Attachment.table_name}.created_on", + 'filename' => "#{Attachment.table_name}.filename", + 'size' => "#{Attachment.table_name}.filesize", + 'downloads' => "#{Attachment.table_name}.downloads" + sort = "" + + if params[:project_id] + @isproject = true + + if params[:sort] + params[:sort].split(",").each do |sort_type| + order_by = sort_type.split(":") + + case order_by[0] + when "filename" + attribute = "filename" + when "size" + attribute = "filesize" + when "attach_type" + attribute = "attachtype" + when "content_type" + attribute = "created_on" + when "field_file_dense" + attribute = "is_public" + when "downloads" + attribute = "downloads" + when "created_on" + attribute = "created_on" + end + + if order_by.count == 1 + sort += "#{Attachment.table_name}.#{attribute} desc " + elsif order_by.count == 2 + sort += "#{Attachment.table_name}.#{attribute} #{order_by[1]} " + end + if sort_type != params[:sort].split(",").last + sort += "," + end + end + end + + @containers = [ Project.includes(:attachments).reorder(sort).find(@project.id)] + @containers += @project.versions.includes(:attachments).reorder(sort).all.sort + + show_attachments @containers + + render :layout => !request.xhr? + elsif params[:course_id] + @isproject = false + + if params[:sort] + params[:sort].split(",").each do |sort_type| + order_by = sort_type.split(":") + + case order_by[0] + when "filename" + attribute = "filename" + when "size" + attribute = "filesize" + when "attach_type" + attribute = "attachtype" + when "content_type" + attribute = "created_on" + when "field_file_dense" + attribute = "is_public" + when "downloads" + attribute = "downloads" + when "created_on" + attribute = "created_on" + end + + if order_by.count == 1 + sort += "#{Attachment.table_name}.#{attribute} asc " + elsif order_by.count == 2 + sort += "#{Attachment.table_name}.#{attribute} #{order_by[1]} " + end + if sort_type != params[:sort].split(",").last + sort += "," + end + end + end + @containers = [ Course.includes(:attachments).reorder(sort).find(@course.id)] + + show_attachments @containers + + render :layout => 'base_courses' + end + + end + + def new + @versions = @project.versions.sort + @course_tag = @project.project_type + if @project.project_type == 1 + render :layout => 'base_courses' + end + end + + def create + if params[:add_tag] + @addTag=true + #render :back + tag_saveEx + #render :text =>"success" + respond_to do |format| + format.js + end + else + #modify by nwb + if @project + @addTag=false + container = (params[:version_id].blank? ? @project : @project.versions.find_by_id(params[:version_id])) + attachments = Attachment.attach_filesex(container, params[:attachments], params[:attachment_type]) + render_attachment_warning_if_needed(container) + + if !attachments.empty? && !attachments[:files].blank? && Setting.notified_events.include?('file_added') + Mailer.attachments_added(attachments[:files]).deliver + end + + # TODO: 临时用 nyan + sort_init 'created_on', 'desc' + sort_update 'created_on' => "#{Attachment.table_name}.created_on", + 'filename' => "#{Attachment.table_name}.filename", + 'size' => "#{Attachment.table_name}.filesize", + 'downloads' => "#{Attachment.table_name}.downloads" + + @containers = [Project.includes(:attachments).reorder("#{Attachment.table_name}.created_on DESC").find(@project.id)] #modify by Long Jun + @containers += @project.versions.includes(:attachments).reorder("#{Attachment.table_name}.created_on DESC").all.sort + + show_attachments @containers + + @attachtype = 0 + @contenttype = 0 + + respond_to do |format| + format.js + format.html { + redirect_to project_files_url(@project) + } + end + elsif @course + @addTag=false + attachments = Attachment.attach_filesex(@course, params[:attachments], params[:attachment_type]) + + if !attachments.empty? && !attachments[:files].blank? && Setting.notified_events.include?('file_added') + Mailer.attachments_added(attachments[:files]).deliver + end + + # TODO: 临时用 nyan + sort_init 'created_on', 'desc' + sort_update 'created_on' => "#{Attachment.table_name}.created_on", + 'filename' => "#{Attachment.table_name}.filename", + 'size' => "#{Attachment.table_name}.filesize", + 'downloads' => "#{Attachment.table_name}.downloads" + + @containers = [Course.includes(:attachments).reorder("#{Attachment.table_name}.created_on DESC").find(@course.id)] + + show_attachments @containers + + @attachtype = 0 + @contenttype = 0 + + respond_to do |format| + format.js + format.html { + redirect_to course_files_url(@course) + } + end + end + + end + end + + def tag_saveEx + @tags = params[:tag_name][:name] + @obj_id = params[:object_id] + @obj_flag = params[:object_flag] + + case @obj_flag + when '1' then + @obj = User.find_by_id(@obj_id) + when '2' then + @obj = Project.find_by_id(@obj_id) + when '3' then + @obj = Issue.find_by_id(@obj_id) + when '4' then + @obj = Bid.find_by_id(@obj_id) + when '5' then + @obj = Forum.find_by_id(@obj_id) + when '6' + @obj = Attachment.find_by_id(@obj_id) + when '7' then + @obj = Contest.find_by_id(@obj_id) + when '8' + @obj = OpenSourceProject.find_by_id(@obj_id) + when '9' + @obj = Course.find_by_id(@obj_id) + else + @obj = nil + end + unless @obj.nil? + @obj.tag_list.add(@tags.split(",")) + else + return + end + if @obj.save + ## 执行成功的操作。 + else + #捕获异常 + end + end + + # 返回指定资源类型的资源列表 + # added by nwb + def getattachtype + sort_init 'created_on', 'desc' + sort_update 'created_on' => "#{Attachment.table_name}.created_on", + 'filename' => "#{Attachment.table_name}.filename", + 'size' => "#{Attachment.table_name}.filesize", + 'downloads' => "#{Attachment.table_name}.downloads" + + if @project + @containers = [ Project.includes(:attachments).reorder("#{Attachment.table_name}.created_on DESC").find(@project.id)] + @containers += @project.versions.includes(:attachments).reorder("#{Attachment.table_name}.created_on DESC").all.sort + elsif @course + @containers = [ Course.includes(:attachments).reorder("#{Attachment.table_name}.created_on DESC").find(@course.id)] + end + show_attachments @containers + + @attachtype = params[:type].to_i + @contenttype = params[:contentType].to_s + + respond_to do |format| + format.js + end + end +end diff --git a/app/controllers/forums_controller.rb b/app/controllers/forums_controller.rb index 88bec0f2a..d5fc1770c 100644 --- a/app/controllers/forums_controller.rb +++ b/app/controllers/forums_controller.rb @@ -1,230 +1,230 @@ -# added by fq -class ForumsController < ApplicationController - layout "users_base" - - # GET /forums - # GET /forums.json - before_filter :find_forum_if_available - before_filter :authenticate_user_edit, :only => [:edit, :update] - before_filter :authenticate_user_destroy, :only => [:destroy] - before_filter :require_login, :only => [:new, :create] - - helper :sort - include SortHelper - - PageLimit = 20 - - def create_memo - @memo = Memo.new(params[:memo]) - @memo.forum_id = @forum.id - @memo.author_id = User.current.id - - @memo.save_attachments(params[:attachments] || (params[:memo] && params[:memo][:uploads])) - - respond_to do |format| - if @memo.save - format.html { redirect_to (forum_memo_url(@forum, (@memo.parent_id.nil? ? @memo : @memo.parent_id))), notice: "#{l :label_memo_create_succ}" } - format.json { render json: @memo, status: :created, location: @memo } - else - sort_init 'updated_at', 'desc' - sort_update 'created_at' => "#{Memo.table_name}.created_at", - 'replies' => "#{Memo.table_name}.replies_count", - 'updated_at' => "COALESCE (last_replies_memos.created_at, #{Memo.table_name}.created_at)" - - @topic_count = @forum.topics.count - @topic_pages = Paginator.new @topic_count, per_page_option, params['page'] - @memos = @forum.topics. - reorder("#{Memo.table_name}.sticky DESC"). - includes(:last_reply). - limit(@topic_pages.per_page). - offset(@topic_pages.offset). - order(sort_clause). - preload(:author, {:last_reply => :author}). - all - - flash.now[:error] = "#{l :label_memo_create_fail}: #{@memo.errors.full_messages[0]}" - # back_error_page = @memo.parent_id.nil? ? forum_path(@forum) : forum_memo_path(@forum, @memo.parent_id) - format.html { render action: :show, layout: 'base_forums' }#, error: "#{l :label_memo_create_fail}: #{@memo.errors.full_messages[0]}" } - format.json { render json: @memo.errors, status: :unprocessable_entity } - end - end - end - - def index - @offset, @limit = api_offset_and_limit({:limit => 10}) - @forums_all = Forum.where('1=1') - @forums_count = @forums_all.count - @forums_pages = Paginator.new @forums_count, @limit, params['page'] - - - @offset ||= @forums_pages.offset - @forums = @forums_all.offset(@offset).limit(@limit).all - #@forums = Forum.all - respond_to do |format| - format.html # index.html.erb - format.json { render json: @forums } - end - end - - # GET /forums/1 - # GET /forums/1.json - def show - sort_init 'updated_at', 'desc' - sort_update 'created_at' => "#{Memo.table_name}.created_at", - 'replies' => "#{Memo.table_name}.replies_count", - 'updated_at' => "COALESCE (last_replies_memos.created_at, #{Memo.table_name}.created_at)" - - @memo = Memo.new(:forum => @forum) - @topic_count = @forum.topics.count - @topic_pages = Paginator.new @topic_count, per_page_option, params['page'] - @memos = @forum.topics. - reorder("#{Memo.table_name}.sticky DESC"). - includes(:last_reply). - limit(@topic_pages.per_page). - offset(@topic_pages.offset). - order(sort_clause). - preload(:author, {:last_reply => :author}). - all - - - - # @offset, @limit = api_offset_and_limit({:limit => 10}) - # @forum = Forum.find(params[:id]) - # @memos_all = @forum.topics - # @topic_count = @memos_all.count - # @topic_pages = Paginator.new @topic_count, @limit, params['page'] - - # @offset ||= @topic_pages.offset - # @memos = @memos_all.offset(@offset).limit(@limit).all - respond_to do |format| - format.html { - render :layout => 'base_forums' - }# show.html.erb - format.json { render json: @forum } - end - end - - # GET /forums/new - # GET /forums/new.json - def new - @forum = Forum.new - - respond_to do |format| - format.html # new.html.erb - format.json { render json: @forum } - end - end - - # GET /forums/1/edit - def edit - @forum = Forum.find(params[:id]) - end - - # POST /forums - # POST /forums.json - def create - @forum = Forum.new(params[:forum]) - @forum.creator_id = User.current.id - - respond_to do |format| - if @forum.save - format.html { redirect_to @forum, notice: l(:label_forum_create_succ) } - format.json { render json: @forum, status: :created, location: @forum } - else - flash.now[:error] = "#{l :label_forum_create_fail}: #{@forum.errors.full_messages[0]}" - format.html { render action: "new" } - format.json { render json: @forum.errors, status: :unprocessable_entity } - end - end - end - - # PUT /forums/1 - # PUT /forums/1.json - def update - @forum = Forum.find(params[:id]) - - respond_to do |format| - if @forum.update_attributes(params[:forum]) - format.html { redirect_to @forum, notice: l(:label_forum_update_succ) } - format.json { head :no_content } - else - flash.now[:error] = "#{l :label_forum_update_fail}: #{@forum.errors.full_messages[0]}" - format.html { render action: "edit" } - format.json { render json: @forum.errors, status: :unprocessable_entity } - end - end - end - - # DELETE /forums/1 - # DELETE /forums/1.json - def destroy - @forum = Forum.find(params[:id]) - @forum.destroy - - respond_to do |format| - format.html { redirect_to forums_url } - format.json { head :no_content } - end - end - - def search_forum - # @forums = paginateHelper Forum.where("name LIKE '%#{params[:name]}%'") - q = "%#{params[:name].strip}%" - (redirect_to forums_url, :notice => l(:label_sumbit_empty);return) if params[:name].blank? - @offset, @limit = api_offset_and_limit({:limit => 10}) - @forums_all = Forum.where("name LIKE ?", q) - @forums_count = @forums_all.count - @forums_pages = Paginator.new @forums_count, @limit, params['page'] - - - @offset ||= @forums_pages.offset - @forums = @forums_all.offset(@offset).limit(@limit).all - respond_to do |format| - format.html { - render 'index' - } - format.json { render json: @forums } - end - end - - def search_memo - q = "%#{params[:name].strip}%" - - limit = PageLimit - @memo = Memo.new - @offset, @limit = api_offset_and_limit({:limit => limit}) - @forum = Forum.find(params[:id]) - @memos_all = @forum.topics.where("subject LIKE ?", q) - @topic_count = @memos_all.count - @topic_pages = Paginator.new @topic_count, @limit, params['page'] - - @offset ||= @topic_pages.offset - @memos = @memos_all.offset(@offset).limit(@limit).all - respond_to do |format| - format.html { - render 'show', :layout => 'base_forums' - } - format.json { render json: @forum } - end - end - - private - - - def find_forum_if_available - @forum = Forum.find(params[:id]) if params[:id] - rescue ActiveRecord::RecordNotFound - render_404 - nil - end - - def authenticate_user_edit - find_forum_if_available - render_403 unless @forum.editable_by? User.current - end - - def authenticate_user_destroy - find_forum_if_available - render_403 unless @forum.destroyable_by? User.current - end +# added by fq +class ForumsController < ApplicationController + layout "users_base" + + # GET /forums + # GET /forums.json + before_filter :find_forum_if_available + before_filter :authenticate_user_edit, :only => [:edit, :update] + before_filter :authenticate_user_destroy, :only => [:destroy] + before_filter :require_login, :only => [:new, :create] + + helper :sort + include SortHelper + + PageLimit = 20 + + def create_memo + @memo = Memo.new(params[:memo]) + @memo.forum_id = @forum.id + @memo.author_id = User.current.id + + @memo.save_attachments(params[:attachments] || (params[:memo] && params[:memo][:uploads])) + + respond_to do |format| + if @memo.save + format.html { redirect_to (forum_memo_url(@forum, (@memo.parent_id.nil? ? @memo : @memo.parent_id))), notice: "#{l :label_memo_create_succ}" } + format.json { render json: @memo, status: :created, location: @memo } + else + sort_init 'updated_at', 'desc' + sort_update 'created_at' => "#{Memo.table_name}.created_at", + 'replies' => "#{Memo.table_name}.replies_count", + 'updated_at' => "COALESCE (last_replies_memos.created_at, #{Memo.table_name}.created_at)" + + @topic_count = @forum.topics.count + @topic_pages = Paginator.new @topic_count, per_page_option, params['page'] + @memos = @forum.topics. + reorder("#{Memo.table_name}.sticky DESC"). + includes(:last_reply). + limit(@topic_pages.per_page). + offset(@topic_pages.offset). + order(sort_clause). + preload(:author, {:last_reply => :author}). + all + + flash.now[:error] = "#{l :label_memo_create_fail}: #{@memo.errors.full_messages[0]}" + # back_error_page = @memo.parent_id.nil? ? forum_path(@forum) : forum_memo_path(@forum, @memo.parent_id) + format.html { render action: :show, layout: 'base_forums' }#, error: "#{l :label_memo_create_fail}: #{@memo.errors.full_messages[0]}" } + format.json { render json: @memo.errors, status: :unprocessable_entity } + end + end + end + + def index + @offset, @limit = api_offset_and_limit({:limit => 10}) + @forums_all = Forum.where('1=1') + @forums_count = @forums_all.count + @forums_pages = Paginator.new @forums_count, @limit, params['page'] + + + @offset ||= @forums_pages.offset + @forums = @forums_all.offset(@offset).limit(@limit).all + #@forums = Forum.all + respond_to do |format| + format.html # index.html.erb + format.json { render json: @forums } + end + end + + # GET /forums/1 + # GET /forums/1.json + def show + sort_init 'updated_at', 'desc' + sort_update 'created_at' => "#{Memo.table_name}.created_at", + 'replies' => "#{Memo.table_name}.replies_count", + 'updated_at' => "COALESCE (last_replies_memos.created_at, #{Memo.table_name}.created_at)" + + @memo = Memo.new(:forum => @forum) + @topic_count = @forum.topics.count + @topic_pages = Paginator.new @topic_count, per_page_option, params['page'] + @memos = @forum.topics. + reorder("#{Memo.table_name}.sticky DESC"). + includes(:last_reply). + limit(@topic_pages.per_page). + offset(@topic_pages.offset). + order(sort_clause). + preload(:author, {:last_reply => :author}). + all + + + + # @offset, @limit = api_offset_and_limit({:limit => 10}) + # @forum = Forum.find(params[:id]) + # @memos_all = @forum.topics + # @topic_count = @memos_all.count + # @topic_pages = Paginator.new @topic_count, @limit, params['page'] + + # @offset ||= @topic_pages.offset + # @memos = @memos_all.offset(@offset).limit(@limit).all + respond_to do |format| + format.html { + render :layout => 'base_forums' + }# show.html.erb + format.json { render json: @forum } + end + end + + # GET /forums/new + # GET /forums/new.json + def new + @forum = Forum.new + + respond_to do |format| + format.html # new.html.erb + format.json { render json: @forum } + end + end + + # GET /forums/1/edit + def edit + @forum = Forum.find(params[:id]) + end + + # POST /forums + # POST /forums.json + def create + @forum = Forum.new(params[:forum]) + @forum.creator_id = User.current.id + + respond_to do |format| + if @forum.save + format.html { redirect_to @forum, notice: l(:label_forum_create_succ) } + format.json { render json: @forum, status: :created, location: @forum } + else + flash.now[:error] = "#{l :label_forum_create_fail}: #{@forum.errors.full_messages[0]}" + format.html { render action: "new" } + format.json { render json: @forum.errors, status: :unprocessable_entity } + end + end + end + + # PUT /forums/1 + # PUT /forums/1.json + def update + @forum = Forum.find(params[:id]) + + respond_to do |format| + if @forum.update_attributes(params[:forum]) + format.html { redirect_to @forum, notice: l(:label_forum_update_succ) } + format.json { head :no_content } + else + flash.now[:error] = "#{l :label_forum_update_fail}: #{@forum.errors.full_messages[0]}" + format.html { render action: "edit" } + format.json { render json: @forum.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /forums/1 + # DELETE /forums/1.json + def destroy + @forum = Forum.find(params[:id]) + @forum.destroy + + respond_to do |format| + format.html { redirect_to forums_url } + format.json { head :no_content } + end + end + + def search_forum + # @forums = paginateHelper Forum.where("name LIKE '%#{params[:name]}%'") + q = "%#{params[:name].strip}%" + (redirect_to forums_url, :notice => l(:label_sumbit_empty);return) if params[:name].blank? + @offset, @limit = api_offset_and_limit({:limit => 10}) + @forums_all = Forum.where("name LIKE ?", q) + @forums_count = @forums_all.count + @forums_pages = Paginator.new @forums_count, @limit, params['page'] + + + @offset ||= @forums_pages.offset + @forums = @forums_all.offset(@offset).limit(@limit).all + respond_to do |format| + format.html { + render 'index' + } + format.json { render json: @forums } + end + end + + def search_memo + q = "%#{params[:name].strip}%" + + limit = PageLimit + @memo = Memo.new + @offset, @limit = api_offset_and_limit({:limit => limit}) + @forum = Forum.find(params[:id]) + @memos_all = @forum.topics.where("subject LIKE ?", q) + @topic_count = @memos_all.count + @topic_pages = Paginator.new @topic_count, @limit, params['page'] + + @offset ||= @topic_pages.offset + @memos = @memos_all.offset(@offset).limit(@limit).all + respond_to do |format| + format.html { + render 'show', :layout => 'base_forums' + } + format.json { render json: @forum } + end + end + + private + + + def find_forum_if_available + @forum = Forum.find(params[:id]) if params[:id] + rescue ActiveRecord::RecordNotFound + render_404 + nil + end + + def authenticate_user_edit + find_forum_if_available + render_403 unless @forum.editable_by? User.current + end + + def authenticate_user_destroy + find_forum_if_available + render_403 unless @forum.destroyable_by? User.current + end end \ No newline at end of file diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index 0b7eeacfb..cd2ae11b9 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -1,141 +1,141 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class GroupsController < ApplicationController - layout 'admin' - - before_filter :require_admin - before_filter :find_group, :except => [:index, :new, :create] - accept_api_auth :index, :show, :create, :update, :destroy, :add_users, :remove_user - - helper :custom_fields - - def index - @groups = Group.sorted.all - - respond_to do |format| - format.html - format.api - end - end - - def show - respond_to do |format| - format.html - format.api - end - end - - def new - @group = Group.new - end - - def create - @group = Group.new - @group.safe_attributes = params[:group] - - respond_to do |format| - if @group.save - format.html { - flash[:notice] = l(:notice_successful_create) - redirect_to(params[:continue] ? new_group_url : groups_url) - } - format.api { render :action => 'show', :status => :created, :location => group_url(@group) } - else - format.html { render :action => "new" } - format.api { render_validation_errors(@group) } - end - end - end - - def edit - end - - def update - @group.safe_attributes = params[:group] - - respond_to do |format| - if @group.save - flash[:notice] = l(:notice_successful_update) - format.html { redirect_to(groups_url) } - format.api { render_api_ok } - else - format.html { render :action => "edit" } - format.api { render_validation_errors(@group) } - end - end - end - - def destroy - @group.destroy - - respond_to do |format| - format.html { redirect_to(groups_url) } - format.api { render_api_ok } - end - end - - def add_users - @users = User.find_all_by_id(params[:user_id] || params[:user_ids]) - @group.users << @users if request.post? - respond_to do |format| - format.html { redirect_to edit_group_url(@group, :tab => 'users') } - format.js - format.api { render_api_ok } - end - end - - def remove_user - @group.users.delete(User.find(params[:user_id])) if request.delete? - respond_to do |format| - format.html { redirect_to edit_group_url(@group, :tab => 'users') } - format.js - format.api { render_api_ok } - end - end - - def autocomplete_for_user - respond_to do |format| - format.js - end - end - - def edit_membership - @membership = Member.edit_membership(params[:membership_id], params[:membership], @group) - @membership.save if request.post? - respond_to do |format| - format.html { redirect_to edit_group_url(@group, :tab => 'memberships') } - format.js - end - end - - def destroy_membership - Member.find(params[:membership_id]).destroy if request.post? - respond_to do |format| - format.html { redirect_to edit_group_url(@group, :tab => 'memberships') } - format.js - end - end - - private - - def find_group - @group = Group.find(params[:id]) - rescue ActiveRecord::RecordNotFound - render_404 - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class GroupsController < ApplicationController + layout 'admin' + + before_filter :require_admin + before_filter :find_group, :except => [:index, :new, :create] + accept_api_auth :index, :show, :create, :update, :destroy, :add_users, :remove_user + + helper :custom_fields + + def index + @groups = Group.sorted.all + + respond_to do |format| + format.html + format.api + end + end + + def show + respond_to do |format| + format.html + format.api + end + end + + def new + @group = Group.new + end + + def create + @group = Group.new + @group.safe_attributes = params[:group] + + respond_to do |format| + if @group.save + format.html { + flash[:notice] = l(:notice_successful_create) + redirect_to(params[:continue] ? new_group_url : groups_url) + } + format.api { render :action => 'show', :status => :created, :location => group_url(@group) } + else + format.html { render :action => "new" } + format.api { render_validation_errors(@group) } + end + end + end + + def edit + end + + def update + @group.safe_attributes = params[:group] + + respond_to do |format| + if @group.save + flash[:notice] = l(:notice_successful_update) + format.html { redirect_to(groups_url) } + format.api { render_api_ok } + else + format.html { render :action => "edit" } + format.api { render_validation_errors(@group) } + end + end + end + + def destroy + @group.destroy + + respond_to do |format| + format.html { redirect_to(groups_url) } + format.api { render_api_ok } + end + end + + def add_users + @users = User.find_all_by_id(params[:user_id] || params[:user_ids]) + @group.users << @users if request.post? + respond_to do |format| + format.html { redirect_to edit_group_url(@group, :tab => 'users') } + format.js + format.api { render_api_ok } + end + end + + def remove_user + @group.users.delete(User.find(params[:user_id])) if request.delete? + respond_to do |format| + format.html { redirect_to edit_group_url(@group, :tab => 'users') } + format.js + format.api { render_api_ok } + end + end + + def autocomplete_for_user + respond_to do |format| + format.js + end + end + + def edit_membership + @membership = Member.edit_membership(params[:membership_id], params[:membership], @group) + @membership.save if request.post? + respond_to do |format| + format.html { redirect_to edit_group_url(@group, :tab => 'memberships') } + format.js + end + end + + def destroy_membership + Member.find(params[:membership_id]).destroy if request.post? + respond_to do |format| + format.html { redirect_to edit_group_url(@group, :tab => 'memberships') } + format.js + end + end + + private + + def find_group + @group = Group.find(params[:id]) + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff --git a/app/controllers/homework_attach_controller.rb b/app/controllers/homework_attach_controller.rb index 27a221266..1841c90ea 100644 --- a/app/controllers/homework_attach_controller.rb +++ b/app/controllers/homework_attach_controller.rb @@ -1,365 +1,365 @@ -class HomeworkAttachController < ApplicationController - layout "course_base" - include CoursesHelper - ############################### - before_filter :can_show_course,except: [] - #判断当前角色权限时需先找到当前操作的project - before_filter :find_course_by_bid_id, :only => [:new] - before_filter :find_course_by_hoemwork_id, :only => [:edit,:update,:destroy,:show,:add_homework_users,:destory_homework_users] - #判断当前角色是否有操作权限 - #勿删 before_filter :authorize, :only => [:new,:edit,:update,:destroy] - - def find_course_by_bid_id - @bid = Bid.find(params[:id]) - @course = @bid.courses[0] - rescue ActiveRecord::RecordNotFound - render_404 - end - - def find_course_by_hoemwork_id - @homework = HomeworkAttach.find(params[:id]) - @course = @homework.bid.courses[0] - end - - #获取作业的成员 - def get_homework_member homework - @hoemwork_users = users_for_homework(@homework) - @members = members_for_homework(@homework,@hoemwork_users,params[:q]) - @members = paginateHelper @members,10 - end - - def index - @homeworks = HomeworkAttach.all - respond_to do |format| - format.html # index.html.erb - format.json { render json: @homeworks } - end - end - - #作业添加成员(参与人员) - def add_homework_users - if User.current.admin? || User.current.member_of_course?(@homework.bid.courses.first) - #@homework = HomeworkAttach.find(params[:id]) - if params[:membership] - if params[:membership][:user_ids] - attrs = params[:membership].dup - user_ids = attrs.delete(:user_ids) - user_ids.each do |user_id| - @homework.homework_users.build(:user_id => user_id) - end - end - end - @homework.save - get_homework_member @homework - respond_to do |format| - format.js - end - else - render_403 :message => :notice_not_authorized - end - end - - #作业删除成员(参与人员) - def destory_homework_users - #@homework = HomeworkAttach.find(params[:id]) - if User.current.admin? || User.current.member_of_course?(@homework.bid.courses.first) - homework_user = @homework.homework_users.where("user_id = #{params[:user_id]}").first - homework_user.destroy - get_homework_member @homework - respond_to do |format| - format.js - end - else - render_403 :message => :notice_not_authorized - end - end - - def create - bid = Bid.find params[:bid_id] - if User.current.admin? || User.current.member_of_course?(bid.courses.first) # modify by nwb - if bid.homeworks.where("user_id = ?",User.current).count == 0 - user_id = params[:user_id] - bid_id = params[:bid_id] - if params[:homework_attach] - if params[:homework_attach][:project_id] - project_id = params[:homework_attach][:project_id] - else - project_id = 0 - end - else - project_id = 0 - end - sta = 0 - name = params[:new_form][:name] - description = params[:new_form][:description] - options = { - :user_id => user_id, - :state => sta, - :name => name, - :description => description, - :bid_id => bid_id, - :project_id => project_id - } - - - #@homework_list = @bid.homeworks - - @homework = HomeworkAttach.new(options) - @homework.save_attachments(params[:attachments]) - render_attachment_warning_if_needed(@homework) - - if @homework.save - respond_to do |format| - format.html { redirect_to course_for_bid_url @homework.bid } - format.json { head :no_content } - end - else - render_403 :message => :notice_not_authorized - end - else - render_403 :message => :notice_has_homework - end - else - render_403 :message => :notice_not_authorized - end - end - - def new - @bid = Bid.find(params[:id]) - if User.current.admin? || User.current.member_of_course?(@bid.courses.first) #nwb - #该课程的学生的集合(新建不实现功能:添加成员) - #@members = @bid.courses.first.members.joins(:member_roles).where("member_roles.role_id IN (:role_id) and user_id <> #{User.current.id}", {:role_id => [5, 10]}) - - #@members = paginateHelper @members,10 - #@all_user = [] - #@bid.courses.first.members.each do |member| - # @all_user << member.user - #end - @homework = HomeworkAttach.new - #@homework_user = members_for_homework(@homework) + User.current - #@members = @all_user - @homework_user - respond_to do |format| - format.html # new.html.erb - format.json { render json: @homework } - end - else - render_403 :message => :notice_not_authorized - end - end - - #获取作业成员的集合 - def get_homework_member_list - @homework = HomeworkAttach.find(params[:bid_id]) - course = @homework.bid.courses.first - if User.current.admin? || User.current.member_of_course?(course) - get_homework_member @homework - else - raise "error" - end - respond_to do |format| - format.js - end - end - - #获取指定作业的所有成员 - def users_for_homework homework - homework.nil? ? [] : (homework.users + [homework.user]) - end - - #获取可选成员列表 - #homework:作业 - #users:该作业所有成员 - #q:模糊匹配的用户的昵称 - def members_for_homework homework,users,q - #homework.bid.courses.first.members.joins(:member_roles).where("member_roles.role_id IN (:role_id) and user_id not in (:users)", {:role_id => [5, 10],:users => users}).joins(:user).where("users.login like '%#{q}%'") - unpartin_users = homework.bid.courses.first.members.where("user_id not in (:users)", {:users => users}).joins(:user).where("users.login like '%#{q}%'") - canpartin_users = [] - unpartin_users.each do |m| - if m.user.allowed_to?(:paret_in_homework,homework.bid.courses.first) - canpartin_users << m - end - end - canpartin_users - end - - def edit - #@homework = HomeworkAttach.find(params[:id]) - if User.current.admin? || User.current.member_of_course?(@homework.bid.courses.first) - #@members = @homework.bid.courses.first.members.joins(:member_roles).where("member_roles.role_id IN (:role_id)", {:role_id => [5, 10]}) - get_homework_member @homework - else - render_403 :message => :notice_not_authorized - end - end - - def update - #@homework = HomeworkAttach.find(params[:id]) - course = @homework.bid.courses.first - if User.current.admin? || User.current.member_of_course?(course) - name = params[:homework_name] - description = params[:homework_description] - if params[:homework_attach] - if params[:homework_attach][:project_id] - project_id = params[:homework_attach][:project_id] - else - project_id = 0 - end - else - project_id = 0 - end - @homework.name = name - @homework.description = description - @homework.project_id = project_id - if params[:attachments] - @homework.save_attachments(params[:attachments]) - end - if @homework.save - respond_to do |format| - format.html { redirect_to course_for_bid_url @homework.bid } - format.json { head :no_content } - end - else - end - else - render_403 :message => :notice_not_authorized - end - end - - def destroy - #@homework = HomeworkAttach.find(params[:id]) - if User.current.admin? || User.current == @homework.user - if @homework.destroy - respond_to do |format| - format.html { redirect_to course_for_bid_url @homework.bid } - format.json { head :no_content } - end - else - end - else - render_403 :message => :notice_not_authorized - end - end - - #显示作业信息 - def show - #@homework = HomeworkAttach.find(params[:id]) - if User.current.admin? || User.current.member_of_course?(@homework.bid.courses.first) - # 打分统计 - stars_reates = @homework. - rates(:quality) - stars_reates_count = stars_reates.count == 0 ? 1 : stars_reates.count - stars_status = stars_reates.select("stars, count(*) as scount"). - group("stars") - @stars_status_map = Hash.new(0.0) - stars_status.each do |star_status| - percent = (star_status.scount * 1.0/ stars_reates_count) * 100.to_f - percent_m = format("%.2f", percent) - @stars_status_map["star#{star_status.stars.to_i}".to_sym] = - percent_m.to_s + "%" - end - #是否已经进行过评价 - @has_evaluation = stars_reates.where("rater_id = ?",User.current).count > 0 - #是否开启互评功能 - @is_evaluation = @homework.bid.is_evaluation == 1 || @homework.bid.is_evaluation == nil - @limit = 10 - @jours = @homework.journals_for_messages.where("is_comprehensive_evaluation is null").order("created_on DESC") - @feedback_count = @jours.count - @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] - @offset ||= @feedback_pages.offset - @jour = @jours[@offset, @limit] - @comprehensive_evaluation = @homework.journals_for_messages.where("is_comprehensive_evaluation is not null").order("created_on DESC") - - @totle_score = score_for_homework @homework - @teaher_score = teacher_score_for_homework @homework - else - render_403 :message => :notice_not_authorized - end - end - - #删除留言 - def destroy_jour - @journal_destroyed = JournalsForMessage.delete_message(params[:object_id]) - #@homework = HomeworkAttach.find(params[:id]) - #@jours = @homework.journals_for_messages.order("created_on DESC") - #@limit = 10 - #@feedback_count = @jours.count - #@feedback_pages = Paginator.new @feedback_count, @limit, params['page'] - #@offset ||= @feedback_pages.offset - #@jour = @jours[@offset, @limit] - respond_to do |format| - format.js - end - end - - #添加留言 - def addjours - @homework = HomeworkAttach.find(params[:jour_id]) - @add_jour = @homework.addjours User.current.id, params[:new_form][:user_message],0,params[:is_comprehensive_evaluation] - @jours = @homework.journals_for_messages.where("is_comprehensive_evaluation is null").order("created_on DESC") - @limit = 10 - @feedback_count = @jours.count - @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] - @offset ||= @feedback_pages.offset - @jour = @jours[@offset, @limit] - @comprehensive_evaluation = @homework.journals_for_messages.where("is_comprehensive_evaluation is not null").order("created_on DESC") - - @totle_score = score_for_homework @homework - @teaher_score = teacher_score_for_homework @homework - respond_to do |format| - format.js - end - end - - #教师综评 - def comprehensive_evaluation_jour - @homework = HomeworkAttach.find(params[:jour_id]) - @add_jour = @homework.addjours User.current.id, params[:new_form][:user_message],0,params[:is_comprehensive_evaluation] - respond_to do |format| - format.html { redirect_to homework_attach_url @homework } - format.json { head :no_content } - end - end - - #获取指定作业的平均得分 - def score - #stars_reates = @homework.rates(:quality) - #percent = 0 - #stars_reates.each do |star_reates| - # percent = percent + star_reates.stars - #end - #stars_reates_count = stars_reates.count == 0 ? 1 : stars_reates.count - #result = percent * 1.0 / stars_reates_count - #result - end - - #添加回复 - def add_jour_reply - parent_id = params[:reference_id] - author_id = User.current.id - reply_user_id = params[:reference_user_id] - reply_id = params[:reference_message_id] # 暂时不实现 - content = params[:user_notes] - options = {:user_id => author_id, - :m_parent_id => parent_id, - :m_reply_id => reply_id, - :reply_id => reply_user_id, - :notes => content, - :is_readed => false} - @jfm = JournalsForMessage.new(options) - @jfm.save - respond_to do |format| - format.js{ - @save_succ = true if @jfm.errors.empty? - } - end - end - - #验证是否显示课程 - def can_show_course - @first_page = FirstPage.find_by_page_type('project') - if @first_page.show_course == 2 - render_404 - end - end -end - +class HomeworkAttachController < ApplicationController + layout "course_base" + include CoursesHelper + ############################### + before_filter :can_show_course,except: [] + #判断当前角色权限时需先找到当前操作的project + before_filter :find_course_by_bid_id, :only => [:new] + before_filter :find_course_by_hoemwork_id, :only => [:edit,:update,:destroy,:show,:add_homework_users,:destory_homework_users] + #判断当前角色是否有操作权限 + #勿删 before_filter :authorize, :only => [:new,:edit,:update,:destroy] + + def find_course_by_bid_id + @bid = Bid.find(params[:id]) + @course = @bid.courses[0] + rescue ActiveRecord::RecordNotFound + render_404 + end + + def find_course_by_hoemwork_id + @homework = HomeworkAttach.find(params[:id]) + @course = @homework.bid.courses[0] + end + + #获取作业的成员 + def get_homework_member homework + @hoemwork_users = users_for_homework(@homework) + @members = members_for_homework(@homework,@hoemwork_users,params[:q]) + @members = paginateHelper @members,10 + end + + def index + @homeworks = HomeworkAttach.all + respond_to do |format| + format.html # index.html.erb + format.json { render json: @homeworks } + end + end + + #作业添加成员(参与人员) + def add_homework_users + if User.current.admin? || User.current.member_of_course?(@homework.bid.courses.first) + #@homework = HomeworkAttach.find(params[:id]) + if params[:membership] + if params[:membership][:user_ids] + attrs = params[:membership].dup + user_ids = attrs.delete(:user_ids) + user_ids.each do |user_id| + @homework.homework_users.build(:user_id => user_id) + end + end + end + @homework.save + get_homework_member @homework + respond_to do |format| + format.js + end + else + render_403 :message => :notice_not_authorized + end + end + + #作业删除成员(参与人员) + def destory_homework_users + #@homework = HomeworkAttach.find(params[:id]) + if User.current.admin? || User.current.member_of_course?(@homework.bid.courses.first) + homework_user = @homework.homework_users.where("user_id = #{params[:user_id]}").first + homework_user.destroy + get_homework_member @homework + respond_to do |format| + format.js + end + else + render_403 :message => :notice_not_authorized + end + end + + def create + bid = Bid.find params[:bid_id] + if User.current.admin? || User.current.member_of_course?(bid.courses.first) # modify by nwb + if bid.homeworks.where("user_id = ?",User.current).count == 0 + user_id = params[:user_id] + bid_id = params[:bid_id] + if params[:homework_attach] + if params[:homework_attach][:project_id] + project_id = params[:homework_attach][:project_id] + else + project_id = 0 + end + else + project_id = 0 + end + sta = 0 + name = params[:new_form][:name] + description = params[:new_form][:description] + options = { + :user_id => user_id, + :state => sta, + :name => name, + :description => description, + :bid_id => bid_id, + :project_id => project_id + } + + + #@homework_list = @bid.homeworks + + @homework = HomeworkAttach.new(options) + @homework.save_attachments(params[:attachments]) + render_attachment_warning_if_needed(@homework) + + if @homework.save + respond_to do |format| + format.html { redirect_to course_for_bid_url @homework.bid } + format.json { head :no_content } + end + else + render_403 :message => :notice_not_authorized + end + else + render_403 :message => :notice_has_homework + end + else + render_403 :message => :notice_not_authorized + end + end + + def new + @bid = Bid.find(params[:id]) + if User.current.admin? || User.current.member_of_course?(@bid.courses.first) #nwb + #该课程的学生的集合(新建不实现功能:添加成员) + #@members = @bid.courses.first.members.joins(:member_roles).where("member_roles.role_id IN (:role_id) and user_id <> #{User.current.id}", {:role_id => [5, 10]}) + + #@members = paginateHelper @members,10 + #@all_user = [] + #@bid.courses.first.members.each do |member| + # @all_user << member.user + #end + @homework = HomeworkAttach.new + #@homework_user = members_for_homework(@homework) + User.current + #@members = @all_user - @homework_user + respond_to do |format| + format.html # new.html.erb + format.json { render json: @homework } + end + else + render_403 :message => :notice_not_authorized + end + end + + #获取作业成员的集合 + def get_homework_member_list + @homework = HomeworkAttach.find(params[:bid_id]) + course = @homework.bid.courses.first + if User.current.admin? || User.current.member_of_course?(course) + get_homework_member @homework + else + raise "error" + end + respond_to do |format| + format.js + end + end + + #获取指定作业的所有成员 + def users_for_homework homework + homework.nil? ? [] : (homework.users + [homework.user]) + end + + #获取可选成员列表 + #homework:作业 + #users:该作业所有成员 + #q:模糊匹配的用户的昵称 + def members_for_homework homework,users,q + #homework.bid.courses.first.members.joins(:member_roles).where("member_roles.role_id IN (:role_id) and user_id not in (:users)", {:role_id => [5, 10],:users => users}).joins(:user).where("users.login like '%#{q}%'") + unpartin_users = homework.bid.courses.first.members.where("user_id not in (:users)", {:users => users}).joins(:user).where("users.login like '%#{q}%'") + canpartin_users = [] + unpartin_users.each do |m| + if m.user.allowed_to?(:paret_in_homework,homework.bid.courses.first) + canpartin_users << m + end + end + canpartin_users + end + + def edit + #@homework = HomeworkAttach.find(params[:id]) + if User.current.admin? || User.current.member_of_course?(@homework.bid.courses.first) + #@members = @homework.bid.courses.first.members.joins(:member_roles).where("member_roles.role_id IN (:role_id)", {:role_id => [5, 10]}) + get_homework_member @homework + else + render_403 :message => :notice_not_authorized + end + end + + def update + #@homework = HomeworkAttach.find(params[:id]) + course = @homework.bid.courses.first + if User.current.admin? || User.current.member_of_course?(course) + name = params[:homework_name] + description = params[:homework_description] + if params[:homework_attach] + if params[:homework_attach][:project_id] + project_id = params[:homework_attach][:project_id] + else + project_id = 0 + end + else + project_id = 0 + end + @homework.name = name + @homework.description = description + @homework.project_id = project_id + if params[:attachments] + @homework.save_attachments(params[:attachments]) + end + if @homework.save + respond_to do |format| + format.html { redirect_to course_for_bid_url @homework.bid } + format.json { head :no_content } + end + else + end + else + render_403 :message => :notice_not_authorized + end + end + + def destroy + #@homework = HomeworkAttach.find(params[:id]) + if User.current.admin? || User.current == @homework.user + if @homework.destroy + respond_to do |format| + format.html { redirect_to course_for_bid_url @homework.bid } + format.json { head :no_content } + end + else + end + else + render_403 :message => :notice_not_authorized + end + end + + #显示作业信息 + def show + #@homework = HomeworkAttach.find(params[:id]) + if User.current.admin? || User.current.member_of_course?(@homework.bid.courses.first) + # 打分统计 + stars_reates = @homework. + rates(:quality) + stars_reates_count = stars_reates.count == 0 ? 1 : stars_reates.count + stars_status = stars_reates.select("stars, count(*) as scount"). + group("stars") + @stars_status_map = Hash.new(0.0) + stars_status.each do |star_status| + percent = (star_status.scount * 1.0/ stars_reates_count) * 100.to_f + percent_m = format("%.2f", percent) + @stars_status_map["star#{star_status.stars.to_i}".to_sym] = + percent_m.to_s + "%" + end + #是否已经进行过评价 + @has_evaluation = stars_reates.where("rater_id = ?",User.current).count > 0 + #是否开启互评功能 + @is_evaluation = @homework.bid.is_evaluation == 1 || @homework.bid.is_evaluation == nil + @limit = 10 + @jours = @homework.journals_for_messages.where("is_comprehensive_evaluation is null").order("created_on DESC") + @feedback_count = @jours.count + @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] + @offset ||= @feedback_pages.offset + @jour = @jours[@offset, @limit] + @comprehensive_evaluation = @homework.journals_for_messages.where("is_comprehensive_evaluation is not null").order("created_on DESC") + + @totle_score = score_for_homework @homework + @teaher_score = teacher_score_for_homework @homework + else + render_403 :message => :notice_not_authorized + end + end + + #删除留言 + def destroy_jour + @journal_destroyed = JournalsForMessage.delete_message(params[:object_id]) + #@homework = HomeworkAttach.find(params[:id]) + #@jours = @homework.journals_for_messages.order("created_on DESC") + #@limit = 10 + #@feedback_count = @jours.count + #@feedback_pages = Paginator.new @feedback_count, @limit, params['page'] + #@offset ||= @feedback_pages.offset + #@jour = @jours[@offset, @limit] + respond_to do |format| + format.js + end + end + + #添加留言 + def addjours + @homework = HomeworkAttach.find(params[:jour_id]) + @add_jour = @homework.addjours User.current.id, params[:new_form][:user_message],0,params[:is_comprehensive_evaluation] + @jours = @homework.journals_for_messages.where("is_comprehensive_evaluation is null").order("created_on DESC") + @limit = 10 + @feedback_count = @jours.count + @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] + @offset ||= @feedback_pages.offset + @jour = @jours[@offset, @limit] + @comprehensive_evaluation = @homework.journals_for_messages.where("is_comprehensive_evaluation is not null").order("created_on DESC") + + @totle_score = score_for_homework @homework + @teaher_score = teacher_score_for_homework @homework + respond_to do |format| + format.js + end + end + + #教师综评 + def comprehensive_evaluation_jour + @homework = HomeworkAttach.find(params[:jour_id]) + @add_jour = @homework.addjours User.current.id, params[:new_form][:user_message],0,params[:is_comprehensive_evaluation] + respond_to do |format| + format.html { redirect_to homework_attach_url @homework } + format.json { head :no_content } + end + end + + #获取指定作业的平均得分 + def score + #stars_reates = @homework.rates(:quality) + #percent = 0 + #stars_reates.each do |star_reates| + # percent = percent + star_reates.stars + #end + #stars_reates_count = stars_reates.count == 0 ? 1 : stars_reates.count + #result = percent * 1.0 / stars_reates_count + #result + end + + #添加回复 + def add_jour_reply + parent_id = params[:reference_id] + author_id = User.current.id + reply_user_id = params[:reference_user_id] + reply_id = params[:reference_message_id] # 暂时不实现 + content = params[:user_notes] + options = {:user_id => author_id, + :m_parent_id => parent_id, + :m_reply_id => reply_id, + :reply_id => reply_user_id, + :notes => content, + :is_readed => false} + @jfm = JournalsForMessage.new(options) + @jfm.save + respond_to do |format| + format.js{ + @save_succ = true if @jfm.errors.empty? + } + end + end + + #验证是否显示课程 + def can_show_course + @first_page = FirstPage.find_by_page_type('project') + if @first_page.show_course == 2 + render_404 + end + end +end + diff --git a/app/controllers/issue_categories_controller.rb b/app/controllers/issue_categories_controller.rb index 8b7a8d5ce..fb62821d8 100644 --- a/app/controllers/issue_categories_controller.rb +++ b/app/controllers/issue_categories_controller.rb @@ -1,132 +1,132 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class IssueCategoriesController < ApplicationController - layout "project_base" - menu_item :settings - model_object IssueCategory - before_filter :find_model_object, :except => [:index, :new, :create] - #before_filter :find_model_object_contest, :except => [:index, :new, :create] - before_filter :find_project_from_association, :except => [:index, :new, :create] - before_filter :find_project_by_project_id, :only => [:index, :new, :create] - before_filter :authorize - accept_api_auth :index, :show, :create, :update, :destroy - - helper :project_score - - def index - respond_to do |format| - format.html { redirect_to_settings_in_projects } - format.api { @categories = @project.issue_categories.all } - end - end - - def show - respond_to do |format| - format.html { redirect_to_settings_in_projects } - format.api - end - end - - def new - @category = @project.issue_categories.build - @category.safe_attributes = params[:issue_category] - - respond_to do |format| - format.html{render :layout => 'base_projects'}# by young - format.js - end - end - - def create - @category = @project.issue_categories.build - @category.safe_attributes = params[:issue_category] - if @category.save - respond_to do |format| - format.html do - flash[:notice] = l(:notice_successful_create) - redirect_to_settings_in_projects - end - format.js - format.api { render :action => 'show', :status => :created, :location => issue_category_path(@category) } - end - else - respond_to do |format| - format.html { render :action => 'new'} - format.js { render :action => 'new'} - format.api { render_validation_errors(@category) } - end - end - end - - def edit - end - - def update - @category.safe_attributes = params[:issue_category] - if @category.save - respond_to do |format| - format.html { - flash[:notice] = l(:notice_successful_update) - redirect_to_settings_in_projects - } - format.api { render_api_ok } - end - else - respond_to do |format| - format.html { render :action => 'edit' } - format.api { render_validation_errors(@category) } - end - end - end - - def destroy - @issue_count = @category.issues.size - if @issue_count == 0 || params[:todo] || api_request? - reassign_to = nil - if params[:reassign_to_id] && (params[:todo] == 'reassign' || params[:todo].blank?) - reassign_to = @project.issue_categories.find_by_id(params[:reassign_to_id]) - end - @category.destroy(reassign_to) - respond_to do |format| - format.html { redirect_to_settings_in_projects } - format.api { render_api_ok } - end - return - end - @categories = @project.issue_categories - [@category] - end - - private - - def redirect_to_settings_in_projects - redirect_to settings_project_url(@project, :tab => 'categories') - end - - # Wrap ApplicationController's find_model_object method to set - # @category instead of just @issue_category - def find_model_object - super - @category = @object - end - - def find_model_object_contest - super - @category = @object - end - -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class IssueCategoriesController < ApplicationController + layout "project_base" + menu_item :settings + model_object IssueCategory + before_filter :find_model_object, :except => [:index, :new, :create] + #before_filter :find_model_object_contest, :except => [:index, :new, :create] + before_filter :find_project_from_association, :except => [:index, :new, :create] + before_filter :find_project_by_project_id, :only => [:index, :new, :create] + before_filter :authorize + accept_api_auth :index, :show, :create, :update, :destroy + + helper :project_score + + def index + respond_to do |format| + format.html { redirect_to_settings_in_projects } + format.api { @categories = @project.issue_categories.all } + end + end + + def show + respond_to do |format| + format.html { redirect_to_settings_in_projects } + format.api + end + end + + def new + @category = @project.issue_categories.build + @category.safe_attributes = params[:issue_category] + + respond_to do |format| + format.html{render :layout => 'base_projects'}# by young + format.js + end + end + + def create + @category = @project.issue_categories.build + @category.safe_attributes = params[:issue_category] + if @category.save + respond_to do |format| + format.html do + flash[:notice] = l(:notice_successful_create) + redirect_to_settings_in_projects + end + format.js + format.api { render :action => 'show', :status => :created, :location => issue_category_path(@category) } + end + else + respond_to do |format| + format.html { render :action => 'new'} + format.js { render :action => 'new'} + format.api { render_validation_errors(@category) } + end + end + end + + def edit + end + + def update + @category.safe_attributes = params[:issue_category] + if @category.save + respond_to do |format| + format.html { + flash[:notice] = l(:notice_successful_update) + redirect_to_settings_in_projects + } + format.api { render_api_ok } + end + else + respond_to do |format| + format.html { render :action => 'edit' } + format.api { render_validation_errors(@category) } + end + end + end + + def destroy + @issue_count = @category.issues.size + if @issue_count == 0 || params[:todo] || api_request? + reassign_to = nil + if params[:reassign_to_id] && (params[:todo] == 'reassign' || params[:todo].blank?) + reassign_to = @project.issue_categories.find_by_id(params[:reassign_to_id]) + end + @category.destroy(reassign_to) + respond_to do |format| + format.html { redirect_to_settings_in_projects } + format.api { render_api_ok } + end + return + end + @categories = @project.issue_categories - [@category] + end + + private + + def redirect_to_settings_in_projects + redirect_to settings_project_url(@project, :tab => 'categories') + end + + # Wrap ApplicationController's find_model_object method to set + # @category instead of just @issue_category + def find_model_object + super + @category = @object + end + + def find_model_object_contest + super + @category = @object + end + +end diff --git a/app/controllers/issue_relations_controller.rb b/app/controllers/issue_relations_controller.rb index f3689044b..d5c8e04ca 100644 --- a/app/controllers/issue_relations_controller.rb +++ b/app/controllers/issue_relations_controller.rb @@ -1,88 +1,88 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class IssueRelationsController < ApplicationController - before_filter :find_issue, :find_project_from_association, :authorize, :only => [:index, :create] - before_filter :find_relation, :except => [:index, :create] - - accept_api_auth :index, :show, :create, :destroy - - def index - @relations = @issue.relations - - respond_to do |format| - format.html { render :nothing => true } - format.api - end - end - - def show - raise Unauthorized unless @relation.visible? - - respond_to do |format| - format.html { render :nothing => true } - format.api - end - end - - def create - @relation = IssueRelation.new(params[:relation]) - @relation.issue_from = @issue - if params[:relation] && m = params[:relation][:issue_to_id].to_s.strip.match(/^#?(\d+)$/) - @relation.issue_to = Issue.visible.find_by_id(m[1].to_i) - end - saved = @relation.save - - respond_to do |format| - format.html { redirect_to issue_url(@issue) } - format.js { - @relations = @issue.reload.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? } - } - format.api { - if saved - render :action => 'show', :status => :created, :location => relation_url(@relation) - else - render_validation_errors(@relation) - end - } - end - end - - def destroy - raise Unauthorized unless @relation.deletable? - @relation.destroy - - respond_to do |format| - format.html { redirect_to issue_url(@relation.issue_from) } - format.js - format.api { render_api_ok } - end - end - -private - def find_issue - @issue = @object = Issue.find(params[:issue_id]) - rescue ActiveRecord::RecordNotFound - render_404 - end - - def find_relation - @relation = IssueRelation.find(params[:id]) - rescue ActiveRecord::RecordNotFound - render_404 - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class IssueRelationsController < ApplicationController + before_filter :find_issue, :find_project_from_association, :authorize, :only => [:index, :create] + before_filter :find_relation, :except => [:index, :create] + + accept_api_auth :index, :show, :create, :destroy + + def index + @relations = @issue.relations + + respond_to do |format| + format.html { render :nothing => true } + format.api + end + end + + def show + raise Unauthorized unless @relation.visible? + + respond_to do |format| + format.html { render :nothing => true } + format.api + end + end + + def create + @relation = IssueRelation.new(params[:relation]) + @relation.issue_from = @issue + if params[:relation] && m = params[:relation][:issue_to_id].to_s.strip.match(/^#?(\d+)$/) + @relation.issue_to = Issue.visible.find_by_id(m[1].to_i) + end + saved = @relation.save + + respond_to do |format| + format.html { redirect_to issue_url(@issue) } + format.js { + @relations = @issue.reload.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? } + } + format.api { + if saved + render :action => 'show', :status => :created, :location => relation_url(@relation) + else + render_validation_errors(@relation) + end + } + end + end + + def destroy + raise Unauthorized unless @relation.deletable? + @relation.destroy + + respond_to do |format| + format.html { redirect_to issue_url(@relation.issue_from) } + format.js + format.api { render_api_ok } + end + end + +private + def find_issue + @issue = @object = Issue.find(params[:issue_id]) + rescue ActiveRecord::RecordNotFound + render_404 + end + + def find_relation + @relation = IssueRelation.find(params[:id]) + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff --git a/app/controllers/issue_statuses_controller.rb b/app/controllers/issue_statuses_controller.rb index 376eb5b8b..d79df35f4 100644 --- a/app/controllers/issue_statuses_controller.rb +++ b/app/controllers/issue_statuses_controller.rb @@ -1,81 +1,81 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class IssueStatusesController < ApplicationController - layout 'admin' - - before_filter :require_admin, :except => :index - before_filter :require_admin_or_api_request, :only => :index - accept_api_auth :index - - def index - respond_to do |format| - format.html { - @issue_status_pages, @issue_statuses = paginate IssueStatus.sorted, :per_page => 25 - render :action => "index", :layout => false if request.xhr? - } - format.api { - @issue_statuses = IssueStatus.all(:order => 'position') - } - end - end - - def new - @issue_status = IssueStatus.new - end - - def create - @issue_status = IssueStatus.new(params[:issue_status]) - if request.post? && @issue_status.save - flash[:notice] = l(:notice_successful_create) - redirect_to issue_statuses_url - else - render :action => 'new' - end - end - - def edit - @issue_status = IssueStatus.find(params[:id]) - end - - def update - @issue_status = IssueStatus.find(params[:id]) - if request.put? && @issue_status.update_attributes(params[:issue_status]) - flash[:notice] = l(:notice_successful_update) - redirect_to issue_statuses_url - else - render :action => 'edit' - end - end - - def destroy - IssueStatus.find(params[:id]).destroy - redirect_to issue_statuses_url - rescue - flash[:error] = l(:error_unable_delete_issue_status) - redirect_to issue_statuses_url - end - - def update_issue_done_ratio - if request.post? && IssueStatus.update_issue_done_ratios - flash[:notice] = l(:notice_issue_done_ratios_updated) - else - flash[:error] = l(:error_issue_done_ratios_not_updated) - end - redirect_to issue_statuses_url - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class IssueStatusesController < ApplicationController + layout 'admin' + + before_filter :require_admin, :except => :index + before_filter :require_admin_or_api_request, :only => :index + accept_api_auth :index + + def index + respond_to do |format| + format.html { + @issue_status_pages, @issue_statuses = paginate IssueStatus.sorted, :per_page => 25 + render :action => "index", :layout => false if request.xhr? + } + format.api { + @issue_statuses = IssueStatus.all(:order => 'position') + } + end + end + + def new + @issue_status = IssueStatus.new + end + + def create + @issue_status = IssueStatus.new(params[:issue_status]) + if request.post? && @issue_status.save + flash[:notice] = l(:notice_successful_create) + redirect_to issue_statuses_url + else + render :action => 'new' + end + end + + def edit + @issue_status = IssueStatus.find(params[:id]) + end + + def update + @issue_status = IssueStatus.find(params[:id]) + if request.put? && @issue_status.update_attributes(params[:issue_status]) + flash[:notice] = l(:notice_successful_update) + redirect_to issue_statuses_url + else + render :action => 'edit' + end + end + + def destroy + IssueStatus.find(params[:id]).destroy + redirect_to issue_statuses_url + rescue + flash[:error] = l(:error_unable_delete_issue_status) + redirect_to issue_statuses_url + end + + def update_issue_done_ratio + if request.post? && IssueStatus.update_issue_done_ratios + flash[:notice] = l(:notice_issue_done_ratios_updated) + else + flash[:error] = l(:error_issue_done_ratios_not_updated) + end + redirect_to issue_statuses_url + end +end diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index aa68f5867..97c0ce4f6 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -1,481 +1,481 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class IssuesController < ApplicationController - layout 'base_projects'#Added by young - menu_item :new_issue, :only => [:new, :create] - default_search_scope :issues - - before_filter :find_issue, :only => [:show, :edit, :update] - before_filter :find_issues, :only => [:bulk_edit, :bulk_update, :destroy] - before_filter :find_project, :only => [:new, :create, :update_form] - before_filter :authorize, :except => [:index] - before_filter :find_optional_project, :only => [:index] - before_filter :check_for_default_issue_status, :only => [:new, :create] - before_filter :build_new_issue_from_params, :only => [:new, :create, :update_form] - accept_rss_auth :index, :show - accept_api_auth :index, :show, :create, :update, :destroy - - rescue_from Query::StatementInvalid, :with => :query_statement_invalid - - helper :journals - helper :projects - include ProjectsHelper - helper :custom_fields - include CustomFieldsHelper - helper :issue_relations - include IssueRelationsHelper - helper :watchers - include WatchersHelper - helper :attachments - include AttachmentsHelper - helper :queries - include QueriesHelper - helper :repositories - include RepositoriesHelper - helper :sort - include SortHelper - include IssuesHelper - helper :timelog - include Redmine::Export::PDF - helper :project_score - - def index - retrieve_query - sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria) - sort_update(@query.sortable_columns) - @query.sort_criteria = sort_criteria.to_a - - @project_base_tag = (params[:project_id] || @issue.project) ? 'base_projects':'base'#by young - - if @query.valid? - case params[:format] - when 'csv', 'pdf' - @limit = 10#Setting.issues_export_limit.to_i - when 'atom' - @limit = 10#Setting.feeds_limit.to_i - when 'xml', 'json' - @offset, @limit = api_offset_and_limit({:limit => 10}) - else - @limit = 10#per_page_option - end - - @issue_count = @query.issue_count - @issue_pages = Paginator.new @issue_count, @limit, params['page'] - @offset ||= @issue_pages.offset - @issues = @query.issues(:include => [:assigned_to, :tracker, :priority, :category, :fixed_version], - :order => sort_clause, - :offset => @offset, - :limit => @limit) - @issue_count_by_group = @query.issue_count_by_group - - - - - - respond_to do |format| - format.html { render :template => 'issues/index', :layout => @project_base_tag }#by young - format.api { - Issue.load_visible_relations(@issues) if include_in_api_response?('relations') - } - format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") } - format.csv { send_data(query_to_csv(@issues, @query, params), :type => 'text/csv; header=present', :filename => 'issues.csv') } - format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'issues.pdf') } - end - else - respond_to do |format| - format.html { render(:template => 'issues/index', :layout => @project_base_tag) }#by young - format.any(:atom, :csv, :pdf) { render(:nothing => true) } - format.api { render_validation_errors(@query) } - end - end - rescue ActiveRecord::RecordNotFound - render_404 - end - - def show - - @journals = @issue.journals.includes(:user, :details).reorder("#{Journal.table_name}.id ASC").all - @journals.each_with_index {|j,i| j.indice = i+1} - @journals.reject!(&:private_notes?) unless User.current.allowed_to?(:view_private_notes, @issue.project) - @journals.reverse! if User.current.wants_comments_in_reverse_order? - - @changesets = @issue.changesets.visible.all - @changesets.reverse! if User.current.wants_comments_in_reverse_order? - - @relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? } - @allowed_statuses = @issue.new_statuses_allowed_to(User.current) - @edit_allowed = User.current.allowed_to?(:edit_issues, @project) - @priorities = IssuePriority.active - @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project) - - @project_base_tag = (params[:project_id] || @issue.project) ? 'base_projects':'base'#by young - @available_watchers = (@issue.project.users.sort + @issue.watcher_users).uniq - - respond_to do |format| - format.html { - retrieve_previous_and_next_issue_ids - render :template => 'issues/show', :layout => @project_base_tag#by young - } - format.api - 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") - } - end - end - - # Add a new issue - # The new issue will be created from an existing one if copy_from parameter is given - def new - respond_to do |format| - format.html { render :action => 'new', :layout => 'base_projects' } - end - end - - def create - call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue }) - @issue.save_attachments(params[:attachments] || (params[:issue] && params[:issue][:uploads])) - if @issue.save - call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue}) - respond_to do |format| - format.html { - render_attachment_warning_if_needed(@issue) - flash[:notice] = l(:notice_issue_successful_create, :id => view_context.link_to("#{@issue.source_from}", issue_path(@issue), :title => @issue.subject)) - #flash[:notice] = l(:notice_issue_successful_create, :id => view_context.link_to("##{@issue.id}", issue_path(@issue), :title => @issue.subject)) - if params[:continue] - attrs = {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?} - redirect_to new_project_issue_url(@issue.project, :issue => attrs) - else - redirect_to issue_url(@issue) - end - } - format.api { render :action => 'show', :status => :created, :location => issue_url(@issue) } - end - return - else - respond_to do |format| - format.html { render :action => 'new' } - format.api { render_validation_errors(@issue) } - end - end - end - - def edit - return unless update_issue_from_params - - respond_to do |format| - format.html {render :layout => 'base_projects' }#added by young - format.xml { } - end - end - - def update - return unless update_issue_from_params - @issue.save_attachments(params[:attachments] || (params[:issue] && params[:issue][:uploads])) - saved = false - begin - saved = @issue.save_issue_with_child_records(params, @time_entry) - rescue ActiveRecord::StaleObjectError - @conflict = true - if params[:last_journal_id] - @conflict_journals = @issue.journals_after(params[:last_journal_id]).all - @conflict_journals.reject!(&:private_notes?) unless User.current.allowed_to?(:view_private_notes, @issue.project) - end - end - - if saved - - #修改界面增加跟踪者 - watcherlist = @issue.watcher_users - select_users = [] - if params[:issue] - if params[:issue][:watcher_user_ids] - params[:issue][:watcher_user_ids].each do |user_id| - select_users << User.find(user_id) - end - end - end - select_users.each do |user| - if watcherlist.include? user - else - @issue.add_watcher user - end - end - watcherlist.each do |user| - if select_users.include? user - else - @issue.remove_watcher user - end - end - - render_attachment_warning_if_needed(@issue) - reply_id = params[:reference_user_id].to_i - if reply_id > 0 - JournalReply.add_reply(@issue.current_journal.id, reply_id, User.current.id) - end - flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record? - - respond_to do |format| - format.html { redirect_back_or_default issue_path(@issue) } - format.api { render_api_ok } - end - else - respond_to do |format| - format.html { render :action => 'edit' } - format.api { render_validation_errors(@issue) } - end - end - end - - # Updates the issue form when changing the project, status or tracker - # on issue creation/update - def update_form - end - - # Bulk edit/copy a set of issues - def bulk_edit - @issues.sort! - @copy = params[:copy].present? - @notes = params[:notes] - - if User.current.allowed_to?(:move_issues, @projects) - @allowed_projects = Issue.allowed_target_projects_on_move - if params[:issue] - @target_project = @allowed_projects.detect {|p| p.id.to_s == params[:issue][:project_id].to_s} - if @target_project - target_projects = [@target_project] - end - end - end - target_projects ||= @projects - - if @copy - @available_statuses = [IssueStatus.default] - else - @available_statuses = @issues.map(&:new_statuses_allowed_to).reduce(:&) - end - @custom_fields = target_projects.map{|p|p.all_issue_custom_fields}.reduce(:&) - @assignables = target_projects.map(&:assignable_users).reduce(:&) - @trackers = target_projects.map(&:trackers).reduce(:&) - @versions = target_projects.map {|p| p.shared_versions.open}.reduce(:&) - @categories = target_projects.map {|p| p.issue_categories}.reduce(:&) - if @copy - @attachments_present = @issues.detect {|i| i.attachments.any?}.present? - @subtasks_present = @issues.detect {|i| !i.leaf?}.present? - end - - @safe_attributes = @issues.map(&:safe_attribute_names).reduce(:&) - render :layout => false if request.xhr? - end - - def bulk_update - @issues.sort! - @copy = params[:copy].present? - attributes = parse_params_for_bulk_issue_attributes(params) - - unsaved_issue_ids = [] - moved_issues = [] - - if @copy && params[:copy_subtasks].present? - # Descendant issues will be copied with the parent task - # Don't copy them twice - @issues.reject! {|issue| @issues.detect {|other| issue.is_descendant_of?(other)}} - end - - @issues.each do |issue| - issue.reload - if @copy - issue = issue.copy({}, - :attachments => params[:copy_attachments].present?, - :subtasks => params[:copy_subtasks].present? - ) - end - journal = issue.init_journal(User.current, params[:notes]) - issue.safe_attributes = attributes - call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue }) - if issue.save - moved_issues << issue - else - # Keep unsaved issue ids to display them in flash error - unsaved_issue_ids << issue.id - end - end - set_flash_from_bulk_issue_save(@issues, unsaved_issue_ids) - - if params[:follow] - if @issues.size == 1 && moved_issues.size == 1 - redirect_to issue_url(moved_issues.first) - elsif moved_issues.map(&:project).uniq.size == 1 - redirect_to project_issues_url(moved_issues.map(&:project).first) - end - else - redirect_back_or_default _project_issues_path(@project) - end - end - - def destroy - @hours = TimeEntry.sum(:hours, :conditions => ['issue_id IN (?)', @issues]).to_f - if @hours > 0 - case params[:todo] - when 'destroy' - # nothing to do - when 'nullify' - TimeEntry.update_all('issue_id = NULL', ['issue_id IN (?)', @issues]) - when 'reassign' - reassign_to = @project.issues.find_by_id(params[:reassign_to_id]) - if reassign_to.nil? - flash.now[:error] = l(:error_issue_not_found_in_project) - return - else - TimeEntry.update_all("issue_id = #{reassign_to.id}", ['issue_id IN (?)', @issues]) - end - else - # display the destroy form if it's a user request - return unless api_request? - end - end - @issues.each do |issue| - begin - issue.reload.destroy - rescue ::ActiveRecord::RecordNotFound # raised by #reload if issue no longer exists - # nothing to do, issue was already deleted (eg. by a parent) - end - end - respond_to do |format| - format.html { redirect_back_or_default _project_issues_path(@project) } - format.api { render_api_ok } - end - end - - private - - def find_project - project_id = params[:project_id] || (params[:issue] && params[:issue][:project_id]) - @project = Project.find(project_id) - rescue ActiveRecord::RecordNotFound - render_404 - end - - def retrieve_previous_and_next_issue_ids - retrieve_query_from_session - if @query - sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria) - sort_update(@query.sortable_columns, 'issues_index_sort') - limit = 500 - issue_ids = @query.issue_ids(:order => sort_clause, :limit => (limit + 1), :include => [:assigned_to, :tracker, :priority, :category, :fixed_version]) - if (idx = issue_ids.index(@issue.id)) && idx < limit - if issue_ids.size < 500 - @issue_position = idx + 1 - @issue_count = issue_ids.size - end - @prev_issue_id = issue_ids[idx - 1] if idx > 0 - @next_issue_id = issue_ids[idx + 1] if idx < (issue_ids.size - 1) - end - end - end - - # Used by #edit and #update to set some common instance variables - # from the params - # TODO: Refactor, not everything in here is needed by #edit - def update_issue_from_params - @edit_allowed = User.current.allowed_to?(:edit_issues, @project) - @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project) - @time_entry.attributes = params[:time_entry] - - @issue.init_journal(User.current) - - issue_attributes = params[:issue] - if issue_attributes && params[:conflict_resolution] - case params[:conflict_resolution] - when 'overwrite' - issue_attributes = issue_attributes.dup - issue_attributes.delete(:lock_version) - when 'add_notes' - issue_attributes = issue_attributes.slice(:notes) - when 'cancel' - redirect_to issue_url(@issue) - return false - end - end - @issue.safe_attributes = issue_attributes - @priorities = IssuePriority.active - @allowed_statuses = @issue.new_statuses_allowed_to(User.current) - true - end - - # TODO: Refactor, lots of extra code in here - # TODO: Changing tracker on an existing issue should not trigger this - def build_new_issue_from_params - if params[:id].blank? - @issue = Issue.new - if params[:copy_from] - begin - @copy_from = Issue.visible.find(params[:copy_from]) - @copy_attachments = params[:copy_attachments].present? || request.get? - @copy_subtasks = params[:copy_subtasks].present? || request.get? - @issue.copy_from(@copy_from, :attachments => @copy_attachments, :subtasks => @copy_subtasks) - rescue ActiveRecord::RecordNotFound - render_404 - return - end - end - @issue.project = @project - else - @issue = @project.issues.visible.find(params[:id]) - end - - @issue.project = @project - @issue.author ||= User.current - # Tracker must be set before custom field values - @issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first) - if @issue.tracker.nil? - render_error l(:error_no_tracker_in_project) - return false - end - @issue.start_date ||= Date.today if Setting.default_issue_start_date_to_creation_date? - @issue.safe_attributes = params[:issue] - - @priorities = IssuePriority.active - @allowed_statuses = @issue.new_statuses_allowed_to(User.current, true) - @available_watchers = (@issue.project.users.sort + @issue.watcher_users).uniq - end - - def check_for_default_issue_status - if IssueStatus.default.nil? - render_error l(:error_no_default_issue_status) - return false - end - end - - def parse_params_for_bulk_issue_attributes(params) - attributes = (params[:issue] || {}).reject {|k,v| v.blank?} - attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'} - if custom = attributes[:custom_field_values] - custom.reject! {|k,v| v.blank?} - custom.keys.each do |k| - if custom[k].is_a?(Array) - custom[k] << '' if custom[k].delete('__none__') - else - custom[k] = '' if custom[k] == '__none__' - end - end - end - attributes - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class IssuesController < ApplicationController + layout 'base_projects'#Added by young + menu_item :new_issue, :only => [:new, :create] + default_search_scope :issues + + before_filter :find_issue, :only => [:show, :edit, :update] + before_filter :find_issues, :only => [:bulk_edit, :bulk_update, :destroy] + before_filter :find_project, :only => [:new, :create, :update_form] + before_filter :authorize, :except => [:index] + before_filter :find_optional_project, :only => [:index] + before_filter :check_for_default_issue_status, :only => [:new, :create] + before_filter :build_new_issue_from_params, :only => [:new, :create, :update_form] + accept_rss_auth :index, :show + accept_api_auth :index, :show, :create, :update, :destroy + + rescue_from Query::StatementInvalid, :with => :query_statement_invalid + + helper :journals + helper :projects + include ProjectsHelper + helper :custom_fields + include CustomFieldsHelper + helper :issue_relations + include IssueRelationsHelper + helper :watchers + include WatchersHelper + helper :attachments + include AttachmentsHelper + helper :queries + include QueriesHelper + helper :repositories + include RepositoriesHelper + helper :sort + include SortHelper + include IssuesHelper + helper :timelog + include Redmine::Export::PDF + helper :project_score + + def index + retrieve_query + sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria) + sort_update(@query.sortable_columns) + @query.sort_criteria = sort_criteria.to_a + + @project_base_tag = (params[:project_id] || @issue.project) ? 'base_projects':'base'#by young + + if @query.valid? + case params[:format] + when 'csv', 'pdf' + @limit = 10#Setting.issues_export_limit.to_i + when 'atom' + @limit = 10#Setting.feeds_limit.to_i + when 'xml', 'json' + @offset, @limit = api_offset_and_limit({:limit => 10}) + else + @limit = 10#per_page_option + end + + @issue_count = @query.issue_count + @issue_pages = Paginator.new @issue_count, @limit, params['page'] + @offset ||= @issue_pages.offset + @issues = @query.issues(:include => [:assigned_to, :tracker, :priority, :category, :fixed_version], + :order => sort_clause, + :offset => @offset, + :limit => @limit) + @issue_count_by_group = @query.issue_count_by_group + + + + + + respond_to do |format| + format.html { render :template => 'issues/index', :layout => @project_base_tag }#by young + format.api { + Issue.load_visible_relations(@issues) if include_in_api_response?('relations') + } + format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") } + format.csv { send_data(query_to_csv(@issues, @query, params), :type => 'text/csv; header=present', :filename => 'issues.csv') } + format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'issues.pdf') } + end + else + respond_to do |format| + format.html { render(:template => 'issues/index', :layout => @project_base_tag) }#by young + format.any(:atom, :csv, :pdf) { render(:nothing => true) } + format.api { render_validation_errors(@query) } + end + end + rescue ActiveRecord::RecordNotFound + render_404 + end + + def show + + @journals = @issue.journals.includes(:user, :details).reorder("#{Journal.table_name}.id ASC").all + @journals.each_with_index {|j,i| j.indice = i+1} + @journals.reject!(&:private_notes?) unless User.current.allowed_to?(:view_private_notes, @issue.project) + @journals.reverse! if User.current.wants_comments_in_reverse_order? + + @changesets = @issue.changesets.visible.all + @changesets.reverse! if User.current.wants_comments_in_reverse_order? + + @relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? } + @allowed_statuses = @issue.new_statuses_allowed_to(User.current) + @edit_allowed = User.current.allowed_to?(:edit_issues, @project) + @priorities = IssuePriority.active + @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project) + + @project_base_tag = (params[:project_id] || @issue.project) ? 'base_projects':'base'#by young + @available_watchers = (@issue.project.users.sort + @issue.watcher_users).uniq + + respond_to do |format| + format.html { + retrieve_previous_and_next_issue_ids + render :template => 'issues/show', :layout => @project_base_tag#by young + } + format.api + 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") + } + end + end + + # Add a new issue + # The new issue will be created from an existing one if copy_from parameter is given + def new + respond_to do |format| + format.html { render :action => 'new', :layout => 'base_projects' } + end + end + + def create + call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue }) + @issue.save_attachments(params[:attachments] || (params[:issue] && params[:issue][:uploads])) + if @issue.save + call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue}) + respond_to do |format| + format.html { + render_attachment_warning_if_needed(@issue) + flash[:notice] = l(:notice_issue_successful_create, :id => view_context.link_to("#{@issue.source_from}", issue_path(@issue), :title => @issue.subject)) + #flash[:notice] = l(:notice_issue_successful_create, :id => view_context.link_to("##{@issue.id}", issue_path(@issue), :title => @issue.subject)) + if params[:continue] + attrs = {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?} + redirect_to new_project_issue_url(@issue.project, :issue => attrs) + else + redirect_to issue_url(@issue) + end + } + format.api { render :action => 'show', :status => :created, :location => issue_url(@issue) } + end + return + else + respond_to do |format| + format.html { render :action => 'new' } + format.api { render_validation_errors(@issue) } + end + end + end + + def edit + return unless update_issue_from_params + + respond_to do |format| + format.html {render :layout => 'base_projects' }#added by young + format.xml { } + end + end + + def update + return unless update_issue_from_params + @issue.save_attachments(params[:attachments] || (params[:issue] && params[:issue][:uploads])) + saved = false + begin + saved = @issue.save_issue_with_child_records(params, @time_entry) + rescue ActiveRecord::StaleObjectError + @conflict = true + if params[:last_journal_id] + @conflict_journals = @issue.journals_after(params[:last_journal_id]).all + @conflict_journals.reject!(&:private_notes?) unless User.current.allowed_to?(:view_private_notes, @issue.project) + end + end + + if saved + + #修改界面增加跟踪者 + watcherlist = @issue.watcher_users + select_users = [] + if params[:issue] + if params[:issue][:watcher_user_ids] + params[:issue][:watcher_user_ids].each do |user_id| + select_users << User.find(user_id) + end + end + end + select_users.each do |user| + if watcherlist.include? user + else + @issue.add_watcher user + end + end + watcherlist.each do |user| + if select_users.include? user + else + @issue.remove_watcher user + end + end + + render_attachment_warning_if_needed(@issue) + reply_id = params[:reference_user_id].to_i + if reply_id > 0 + JournalReply.add_reply(@issue.current_journal.id, reply_id, User.current.id) + end + flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record? + + respond_to do |format| + format.html { redirect_back_or_default issue_path(@issue) } + format.api { render_api_ok } + end + else + respond_to do |format| + format.html { render :action => 'edit' } + format.api { render_validation_errors(@issue) } + end + end + end + + # Updates the issue form when changing the project, status or tracker + # on issue creation/update + def update_form + end + + # Bulk edit/copy a set of issues + def bulk_edit + @issues.sort! + @copy = params[:copy].present? + @notes = params[:notes] + + if User.current.allowed_to?(:move_issues, @projects) + @allowed_projects = Issue.allowed_target_projects_on_move + if params[:issue] + @target_project = @allowed_projects.detect {|p| p.id.to_s == params[:issue][:project_id].to_s} + if @target_project + target_projects = [@target_project] + end + end + end + target_projects ||= @projects + + if @copy + @available_statuses = [IssueStatus.default] + else + @available_statuses = @issues.map(&:new_statuses_allowed_to).reduce(:&) + end + @custom_fields = target_projects.map{|p|p.all_issue_custom_fields}.reduce(:&) + @assignables = target_projects.map(&:assignable_users).reduce(:&) + @trackers = target_projects.map(&:trackers).reduce(:&) + @versions = target_projects.map {|p| p.shared_versions.open}.reduce(:&) + @categories = target_projects.map {|p| p.issue_categories}.reduce(:&) + if @copy + @attachments_present = @issues.detect {|i| i.attachments.any?}.present? + @subtasks_present = @issues.detect {|i| !i.leaf?}.present? + end + + @safe_attributes = @issues.map(&:safe_attribute_names).reduce(:&) + render :layout => false if request.xhr? + end + + def bulk_update + @issues.sort! + @copy = params[:copy].present? + attributes = parse_params_for_bulk_issue_attributes(params) + + unsaved_issue_ids = [] + moved_issues = [] + + if @copy && params[:copy_subtasks].present? + # Descendant issues will be copied with the parent task + # Don't copy them twice + @issues.reject! {|issue| @issues.detect {|other| issue.is_descendant_of?(other)}} + end + + @issues.each do |issue| + issue.reload + if @copy + issue = issue.copy({}, + :attachments => params[:copy_attachments].present?, + :subtasks => params[:copy_subtasks].present? + ) + end + journal = issue.init_journal(User.current, params[:notes]) + issue.safe_attributes = attributes + call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue }) + if issue.save + moved_issues << issue + else + # Keep unsaved issue ids to display them in flash error + unsaved_issue_ids << issue.id + end + end + set_flash_from_bulk_issue_save(@issues, unsaved_issue_ids) + + if params[:follow] + if @issues.size == 1 && moved_issues.size == 1 + redirect_to issue_url(moved_issues.first) + elsif moved_issues.map(&:project).uniq.size == 1 + redirect_to project_issues_url(moved_issues.map(&:project).first) + end + else + redirect_back_or_default _project_issues_path(@project) + end + end + + def destroy + @hours = TimeEntry.sum(:hours, :conditions => ['issue_id IN (?)', @issues]).to_f + if @hours > 0 + case params[:todo] + when 'destroy' + # nothing to do + when 'nullify' + TimeEntry.update_all('issue_id = NULL', ['issue_id IN (?)', @issues]) + when 'reassign' + reassign_to = @project.issues.find_by_id(params[:reassign_to_id]) + if reassign_to.nil? + flash.now[:error] = l(:error_issue_not_found_in_project) + return + else + TimeEntry.update_all("issue_id = #{reassign_to.id}", ['issue_id IN (?)', @issues]) + end + else + # display the destroy form if it's a user request + return unless api_request? + end + end + @issues.each do |issue| + begin + issue.reload.destroy + rescue ::ActiveRecord::RecordNotFound # raised by #reload if issue no longer exists + # nothing to do, issue was already deleted (eg. by a parent) + end + end + respond_to do |format| + format.html { redirect_back_or_default _project_issues_path(@project) } + format.api { render_api_ok } + end + end + + private + + def find_project + project_id = params[:project_id] || (params[:issue] && params[:issue][:project_id]) + @project = Project.find(project_id) + rescue ActiveRecord::RecordNotFound + render_404 + end + + def retrieve_previous_and_next_issue_ids + retrieve_query_from_session + if @query + sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria) + sort_update(@query.sortable_columns, 'issues_index_sort') + limit = 500 + issue_ids = @query.issue_ids(:order => sort_clause, :limit => (limit + 1), :include => [:assigned_to, :tracker, :priority, :category, :fixed_version]) + if (idx = issue_ids.index(@issue.id)) && idx < limit + if issue_ids.size < 500 + @issue_position = idx + 1 + @issue_count = issue_ids.size + end + @prev_issue_id = issue_ids[idx - 1] if idx > 0 + @next_issue_id = issue_ids[idx + 1] if idx < (issue_ids.size - 1) + end + end + end + + # Used by #edit and #update to set some common instance variables + # from the params + # TODO: Refactor, not everything in here is needed by #edit + def update_issue_from_params + @edit_allowed = User.current.allowed_to?(:edit_issues, @project) + @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project) + @time_entry.attributes = params[:time_entry] + + @issue.init_journal(User.current) + + issue_attributes = params[:issue] + if issue_attributes && params[:conflict_resolution] + case params[:conflict_resolution] + when 'overwrite' + issue_attributes = issue_attributes.dup + issue_attributes.delete(:lock_version) + when 'add_notes' + issue_attributes = issue_attributes.slice(:notes) + when 'cancel' + redirect_to issue_url(@issue) + return false + end + end + @issue.safe_attributes = issue_attributes + @priorities = IssuePriority.active + @allowed_statuses = @issue.new_statuses_allowed_to(User.current) + true + end + + # TODO: Refactor, lots of extra code in here + # TODO: Changing tracker on an existing issue should not trigger this + def build_new_issue_from_params + if params[:id].blank? + @issue = Issue.new + if params[:copy_from] + begin + @copy_from = Issue.visible.find(params[:copy_from]) + @copy_attachments = params[:copy_attachments].present? || request.get? + @copy_subtasks = params[:copy_subtasks].present? || request.get? + @issue.copy_from(@copy_from, :attachments => @copy_attachments, :subtasks => @copy_subtasks) + rescue ActiveRecord::RecordNotFound + render_404 + return + end + end + @issue.project = @project + else + @issue = @project.issues.visible.find(params[:id]) + end + + @issue.project = @project + @issue.author ||= User.current + # Tracker must be set before custom field values + @issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first) + if @issue.tracker.nil? + render_error l(:error_no_tracker_in_project) + return false + end + @issue.start_date ||= Date.today if Setting.default_issue_start_date_to_creation_date? + @issue.safe_attributes = params[:issue] + + @priorities = IssuePriority.active + @allowed_statuses = @issue.new_statuses_allowed_to(User.current, true) + @available_watchers = (@issue.project.users.sort + @issue.watcher_users).uniq + end + + def check_for_default_issue_status + if IssueStatus.default.nil? + render_error l(:error_no_default_issue_status) + return false + end + end + + def parse_params_for_bulk_issue_attributes(params) + attributes = (params[:issue] || {}).reject {|k,v| v.blank?} + attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'} + if custom = attributes[:custom_field_values] + custom.reject! {|k,v| v.blank?} + custom.keys.each do |k| + if custom[k].is_a?(Array) + custom[k] << '' if custom[k].delete('__none__') + else + custom[k] = '' if custom[k] == '__none__' + end + end + end + attributes + end +end diff --git a/app/controllers/journals_controller.rb b/app/controllers/journals_controller.rb index 4ebef9971..f6e17593f 100644 --- a/app/controllers/journals_controller.rb +++ b/app/controllers/journals_controller.rb @@ -1,117 +1,117 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class JournalsController < ApplicationController - before_filter :find_journal, :only => [:edit, :diff, :destroy] - before_filter :find_issue, :only => [:new] - before_filter :find_optional_project, :only => [:index] - before_filter :authorize, :only => [:new, :edit, :diff] - accept_rss_auth :index - menu_item :issues - - helper :issues - helper :custom_fields - helper :queries - include QueriesHelper - helper :sort - include SortHelper - - def index - retrieve_query - sort_init 'id', 'desc' - sort_update(@query.sortable_columns) - - if @query.valid? - @journals = @query.journals(:order => "#{Journal.table_name}.created_on DESC", - :limit => 25) - end - @title = (@project ? @project.name : Setting.app_title) + ": " + (@query.new_record? ? l(:label_changes_details) : @query.name) - render :layout => false, :content_type => 'application/atom+xml' - rescue ActiveRecord::RecordNotFound - render_404 - end - - def diff - @issue = @journal.issue - if params[:detail_id].present? - @detail = @journal.details.find_by_id(params[:detail_id]) - else - @detail = @journal.details.detect {|d| d.prop_key == 'description'} - end - (render_404; return false) unless @issue && @detail - @diff = Redmine::Helpers::Diff.new(@detail.value, @detail.old_value) - respond_to do |format| - format.html { - render :layout => 'project_base' - } - end - end - - def new - @journal = Journal.visible.find(params[:journal_id]) if params[:journal_id] - if @journal - user = @journal.user - text = @journal.notes - else - user = @issue.author - text = @issue.description - end - # Replaces pre blocks with [...] - text = text.to_s.strip.gsub(%r{
((.|\s)*?)}m, '[...]') - @content = "> #{ll(Setting.default_language, :text_user_wrote, user)}\n> " - @content << text.gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n" - @id = user.id - rescue ActiveRecord::RecordNotFound - render_404 - end - - def edit - (render_403; return false) unless @journal.editable_by?(User.current) - if request.post? - @journal.update_attributes(:notes => params[:notes]) if params[:notes] - @journal.destroy if @journal.details.empty? && @journal.notes.blank? - call_hook(:controller_journals_edit_post, { :journal => @journal, :params => params}) - respond_to do |format| - format.html { redirect_to issue_url(@journal.journalized) } - format.js { render :action => 'update' } - end - else - respond_to do |format| - format.html { - # TODO: implement non-JS journal update - render :nothing => true - } - format.js - end - end - end - - # Delete a journals added by young - def destroy - @journal.destroy - redirect_to issue_url(@journal.journalized) - end - - private - - def find_journal - @journal = Journal.visible.find(params[:id]) - @project = @journal.journalized.project - rescue ActiveRecord::RecordNotFound - render_404 - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class JournalsController < ApplicationController + before_filter :find_journal, :only => [:edit, :diff, :destroy] + before_filter :find_issue, :only => [:new] + before_filter :find_optional_project, :only => [:index] + before_filter :authorize, :only => [:new, :edit, :diff] + accept_rss_auth :index + menu_item :issues + + helper :issues + helper :custom_fields + helper :queries + include QueriesHelper + helper :sort + include SortHelper + + def index + retrieve_query + sort_init 'id', 'desc' + sort_update(@query.sortable_columns) + + if @query.valid? + @journals = @query.journals(:order => "#{Journal.table_name}.created_on DESC", + :limit => 25) + end + @title = (@project ? @project.name : Setting.app_title) + ": " + (@query.new_record? ? l(:label_changes_details) : @query.name) + render :layout => false, :content_type => 'application/atom+xml' + rescue ActiveRecord::RecordNotFound + render_404 + end + + def diff + @issue = @journal.issue + if params[:detail_id].present? + @detail = @journal.details.find_by_id(params[:detail_id]) + else + @detail = @journal.details.detect {|d| d.prop_key == 'description'} + end + (render_404; return false) unless @issue && @detail + @diff = Redmine::Helpers::Diff.new(@detail.value, @detail.old_value) + respond_to do |format| + format.html { + render :layout => 'project_base' + } + end + end + + def new + @journal = Journal.visible.find(params[:journal_id]) if params[:journal_id] + if @journal + user = @journal.user + text = @journal.notes + else + user = @issue.author + text = @issue.description + end + # Replaces pre blocks with [...] + text = text.to_s.strip.gsub(%r{
((.|\s)*?)}m, '[...]') + @content = "> #{ll(Setting.default_language, :text_user_wrote, user)}\n> " + @content << text.gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n" + @id = user.id + rescue ActiveRecord::RecordNotFound + render_404 + end + + def edit + (render_403; return false) unless @journal.editable_by?(User.current) + if request.post? + @journal.update_attributes(:notes => params[:notes]) if params[:notes] + @journal.destroy if @journal.details.empty? && @journal.notes.blank? + call_hook(:controller_journals_edit_post, { :journal => @journal, :params => params}) + respond_to do |format| + format.html { redirect_to issue_url(@journal.journalized) } + format.js { render :action => 'update' } + end + else + respond_to do |format| + format.html { + # TODO: implement non-JS journal update + render :nothing => true + } + format.js + end + end + end + + # Delete a journals added by young + def destroy + @journal.destroy + redirect_to issue_url(@journal.journalized) + end + + private + + def find_journal + @journal = Journal.visible.find(params[:id]) + @project = @journal.journalized.project + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff --git a/app/controllers/members_controller.rb b/app/controllers/members_controller.rb index 12d979098..fa19a1a3d 100644 --- a/app/controllers/members_controller.rb +++ b/app/controllers/members_controller.rb @@ -1,326 +1,326 @@ -# -*coding:utf-8 -*- -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class MembersController < ApplicationController - model_object Member - before_filter :find_model_object, :except => [:index, :create, :autocomplete] - #before_filter :find_model_object_contest, :except => [:index, :create, :autocomplete] - before_filter :find_project_from_association, :except => [:index, :create, :autocomplete] - before_filter :find_project_by_project_id, :only => [:index, :create, :autocomplete] - before_filter :authorize - accept_api_auth :index, :show, :create, :update, :destroy - - def index - @offset, @limit = api_offset_and_limit - @member_count = @project.member_principals.count - @member_pages = Paginator.new @member_count, @limit, params['page'] - @offset ||= @member_pages.offset - @members = @project.member_principals.all( - :order => "#{Member.table_name}.id", - :limit => @limit, - :offset => @offset - ) - - respond_to do |format| - format.html { head 406 } - format.api - end - end - - def show - respond_to do |format| - format.html { head 406 } - format.api - end - end - - def create - if params[:refusal_button] - members = [] - applied_members = true - if params[:membership] - if params[:membership][:user_ids] - attrs = params[:membership].dup - user_ids = attrs.delete(:user_ids) - user_ids.each do |user_id| - AppliedProject.deleteappiled(user_id, @project.id) - end - end - end - else - #modify by nwb - #更改课程成员逻辑 - applied_members = false - members = [] - user_grades = [] - if @project - project_info = [] - if params[:membership] - if params[:membership][:user_ids] - attrs = params[:membership].dup - user_ids = attrs.delete(:user_ids) - user_ids.each do |user_id| - members << Member.new(:role_ids => params[:membership][:role_ids], :user_id => user_id) - user_grades << UserGrade.new(:user_id => user_id, :project_id => @project.id) - ## added by nie - - if (params[:membership][:role_ids]) - role = Role.find(params[:membership][:role_ids][0]) - project_info << ProjectInfo.new(:user_id => user_id, :project_id => @project.id) if role.allowed_to?(:is_manager) - # ProjectInfo.create(:name => "test", :user_id => 123) - end - ## end - end - else - members << Member.new(:role_ids => params[:membership][:role_ids], :user_id => params[:membership][:user_id]) - user_grades << UserGrade.new(:user_id => params[:membership][:user_id], :project_id => @project.id) - ## added by nie - if (params[:membership][:role_ids]) - role = Role.find(params[:membership][:role_ids][0]) - project_info << ProjectInfo.new(:project_id => @project.id, :user_id => params[:membership][:user_id]) if role.allowed_to?(:is_manager) - end - ## end - end - @project.members << members - # added by nie - @project.project_infos << project_info - @project.user_grades << user_grades - # end - end - if members.present? && members.all? { |m| m.valid? } - members.each do |member| - AppliedProject.deleteappiled(member.user_id, @project.id) - end - end - respond_to do |format| - format.html { redirect_to_settings_in_projects } - format.js { @members = members; @applied_members = applied_members; } - format.api { - @member = members.first - if @member.valid? - render :action => 'show', :status => :created, :location => membership_url(@member) - else - render_validation_errors(@member) - end - } - end - elsif @course - course_info = [] - if params[:membership] - if params[:membership][:user_ids] - attrs = params[:membership].dup - user_ids = attrs.delete(:user_ids) - user_ids.each do |user_id| - member = Member.new(:role_ids => params[:membership][:role_ids], :user_id => user_id) - role = Role.find_by_id(params[:membership][:role_ids]) - # 这里的判断只能通过角色名,可以弄成常量 - if role.name == "学生" - StudentsForCourse.create(:student_id => user_id, :course_id =>@course.id) - end - members << member - #user_grades << UserGrade.new(:user_id => user_id, :course_id => @course.id) - if (params[:membership][:role_ids]) - role = Role.find(params[:membership][:role_ids][0]) - course_info << CourseInfo.new(:user_id => user_id, :course_id => @course.id) if role.allowed_to?(:is_manager) - end - end - else - members << Member.new(:role_ids => params[:membership][:role_ids], :user_id => params[:membership][:user_id]) - if (params[:membership][:role_ids]) - role = Role.find(params[:membership][:role_ids][0]) - course_info << CourseInfo.new(:course_id => @course.id, :user_id => params[:membership][:user_id]) if role.allowed_to?(:is_manager) - end - end - @course.members << members - @course.course_infos << course_info - end - respond_to do |format| - format.html { redirect_to_settings_in_courses } - format.js { @members = members; @applied_members = applied_members; } - format.api { - @member = members.first - if @member.valid? - render :action => 'show', :status => :created, :location => membership_url(@member) - else - render_validation_errors(@member) - end - } - end - end # end of if @project - - end # end of params[:refusal_button] - - end - - def update - #modify by nwb - #增加对课程成员修改的支持 - if @project - if params[:membership] - @member.role_ids = params[:membership][:role_ids] - - #added by nie - if (params[:membership][:role_ids]) - role = Role.find(params[:membership][:role_ids][0]) - if role.allowed_to?(:is_manager) - @projectInfo = ProjectInfo.new(:user_id => @member.user_id, :project_id => @project.id) - @projectInfo.save - else - user_admin = ProjectInfo.where("user_id = ? and project_id = ?", @member.user_id, @project.id) - if user_admin.size > 0 - user_admin.each do |user| - user.destroy - end - end - end - end - end - - saved = @member.save - respond_to do |format| - format.html { redirect_to_settings_in_projects } - format.js - format.api { - if saved - render_api_ok - else - render_validation_errors(@member) - end - } - end - elsif @course - if params[:membership] - @member.role_ids = params[:membership][:role_ids] - - if (params[:membership][:role_ids]) - role = Role.find(params[:membership][:role_ids][0]) - # 这里的判断只能通过角色名,可以弄成常量 - if role.name == "学生" - StudentsForCourse.create(:student_id => @member.user_id, :course_id =>@course.id) - else - joined = StudentsForCourse.where('student_id = ? and course_id = ?', @member.user_id,@course.id) - joined.each do |join| - join.delete - end - end - if role.allowed_to?(:is_manager) - @courseInfo = CourseInfos.new(:user_id => @member.user_id, :course_id => @course.id) - @courseInfo.save - else - user_admin = CourseInfos.where("user_id = ? and course_id = ?", @member.user_id, @course.id) - if user_admin.size > 0 - user_admin.each do |user| - user.destroy - end - end - end - end - end - - saved = @member.save - respond_to do |format| - format.html { redirect_to_settings_in_courses } - format.js - format.api { - if saved - render_api_ok - else - render_validation_errors(@member) - end - } - end - end - - end - - def destroy - #modify by nwb - #课程成员删除修改 - if @project - if request.delete? && @member.deletable? - @member.destroy - # end - user_admin = ProjectInfo.where("user_id = ? and project_id = ?", @member.user_id, @project.id) - if user_admin.size > 0 - user_admin.each do |user| - user.destroy - end - end - user_grade = UserGrade.where("user_id = ? and project_id = ?", @member.user_id, @project.id) - if user_grade.size > 0 - user_grade.each do |grade| - grade.destroy - end - end - end - respond_to do |format| - format.html { redirect_to_settings_in_projects } - format.js - format.api { - if @member.destroyed? - render_api_ok - else - head :unprocessable_entity - end - } - end - elsif @course - if request.delete? && @member.deletable? - @member.destroy - user_admin = CourseInfos.where("user_id = ? and course_id = ?", @member.user_id, @course.id) - if user_admin.size > 0 - user_admin.each do |user| - user.destroy - end - end - joined = StudentsForCourse.where('student_id = ? and course_id = ?', @member.user_id,@course.id) - joined.each do |join| - join.delete - end - - end - respond_to do |format| - format.html { redirect_to_settings_in_courses } - format.js - format.api { - if @member.destroyed? - render_api_ok - else - head :unprocessable_entity - end - } - end - end - end - - def autocomplete - respond_to do |format| - format.js - end - end - - private - - def redirect_to_settings_in_projects - redirect_to settings_project_url(@project, :tab => 'members') - end - - def redirect_to_settings_in_courses - redirect_to settings_course_url(@course, :tab => 'members') - end -end +# -*coding:utf-8 -*- +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class MembersController < ApplicationController + model_object Member + before_filter :find_model_object, :except => [:index, :create, :autocomplete] + #before_filter :find_model_object_contest, :except => [:index, :create, :autocomplete] + before_filter :find_project_from_association, :except => [:index, :create, :autocomplete] + before_filter :find_project_by_project_id, :only => [:index, :create, :autocomplete] + before_filter :authorize + accept_api_auth :index, :show, :create, :update, :destroy + + def index + @offset, @limit = api_offset_and_limit + @member_count = @project.member_principals.count + @member_pages = Paginator.new @member_count, @limit, params['page'] + @offset ||= @member_pages.offset + @members = @project.member_principals.all( + :order => "#{Member.table_name}.id", + :limit => @limit, + :offset => @offset + ) + + respond_to do |format| + format.html { head 406 } + format.api + end + end + + def show + respond_to do |format| + format.html { head 406 } + format.api + end + end + + def create + if params[:refusal_button] + members = [] + applied_members = true + if params[:membership] + if params[:membership][:user_ids] + attrs = params[:membership].dup + user_ids = attrs.delete(:user_ids) + user_ids.each do |user_id| + AppliedProject.deleteappiled(user_id, @project.id) + end + end + end + else + #modify by nwb + #更改课程成员逻辑 + applied_members = false + members = [] + user_grades = [] + if @project + project_info = [] + if params[:membership] + if params[:membership][:user_ids] + attrs = params[:membership].dup + user_ids = attrs.delete(:user_ids) + user_ids.each do |user_id| + members << Member.new(:role_ids => params[:membership][:role_ids], :user_id => user_id) + user_grades << UserGrade.new(:user_id => user_id, :project_id => @project.id) + ## added by nie + + if (params[:membership][:role_ids]) + role = Role.find(params[:membership][:role_ids][0]) + project_info << ProjectInfo.new(:user_id => user_id, :project_id => @project.id) if role.allowed_to?(:is_manager) + # ProjectInfo.create(:name => "test", :user_id => 123) + end + ## end + end + else + members << Member.new(:role_ids => params[:membership][:role_ids], :user_id => params[:membership][:user_id]) + user_grades << UserGrade.new(:user_id => params[:membership][:user_id], :project_id => @project.id) + ## added by nie + if (params[:membership][:role_ids]) + role = Role.find(params[:membership][:role_ids][0]) + project_info << ProjectInfo.new(:project_id => @project.id, :user_id => params[:membership][:user_id]) if role.allowed_to?(:is_manager) + end + ## end + end + @project.members << members + # added by nie + @project.project_infos << project_info + @project.user_grades << user_grades + # end + end + if members.present? && members.all? { |m| m.valid? } + members.each do |member| + AppliedProject.deleteappiled(member.user_id, @project.id) + end + end + respond_to do |format| + format.html { redirect_to_settings_in_projects } + format.js { @members = members; @applied_members = applied_members; } + format.api { + @member = members.first + if @member.valid? + render :action => 'show', :status => :created, :location => membership_url(@member) + else + render_validation_errors(@member) + end + } + end + elsif @course + course_info = [] + if params[:membership] + if params[:membership][:user_ids] + attrs = params[:membership].dup + user_ids = attrs.delete(:user_ids) + user_ids.each do |user_id| + member = Member.new(:role_ids => params[:membership][:role_ids], :user_id => user_id) + role = Role.find_by_id(params[:membership][:role_ids]) + # 这里的判断只能通过角色名,可以弄成常量 + if role.name == "学生" + StudentsForCourse.create(:student_id => user_id, :course_id =>@course.id) + end + members << member + #user_grades << UserGrade.new(:user_id => user_id, :course_id => @course.id) + if (params[:membership][:role_ids]) + role = Role.find(params[:membership][:role_ids][0]) + course_info << CourseInfo.new(:user_id => user_id, :course_id => @course.id) if role.allowed_to?(:is_manager) + end + end + else + members << Member.new(:role_ids => params[:membership][:role_ids], :user_id => params[:membership][:user_id]) + if (params[:membership][:role_ids]) + role = Role.find(params[:membership][:role_ids][0]) + course_info << CourseInfo.new(:course_id => @course.id, :user_id => params[:membership][:user_id]) if role.allowed_to?(:is_manager) + end + end + @course.members << members + @course.course_infos << course_info + end + respond_to do |format| + format.html { redirect_to_settings_in_courses } + format.js { @members = members; @applied_members = applied_members; } + format.api { + @member = members.first + if @member.valid? + render :action => 'show', :status => :created, :location => membership_url(@member) + else + render_validation_errors(@member) + end + } + end + end # end of if @project + + end # end of params[:refusal_button] + + end + + def update + #modify by nwb + #增加对课程成员修改的支持 + if @project + if params[:membership] + @member.role_ids = params[:membership][:role_ids] + + #added by nie + if (params[:membership][:role_ids]) + role = Role.find(params[:membership][:role_ids][0]) + if role.allowed_to?(:is_manager) + @projectInfo = ProjectInfo.new(:user_id => @member.user_id, :project_id => @project.id) + @projectInfo.save + else + user_admin = ProjectInfo.where("user_id = ? and project_id = ?", @member.user_id, @project.id) + if user_admin.size > 0 + user_admin.each do |user| + user.destroy + end + end + end + end + end + + saved = @member.save + respond_to do |format| + format.html { redirect_to_settings_in_projects } + format.js + format.api { + if saved + render_api_ok + else + render_validation_errors(@member) + end + } + end + elsif @course + if params[:membership] + @member.role_ids = params[:membership][:role_ids] + + if (params[:membership][:role_ids]) + role = Role.find(params[:membership][:role_ids][0]) + # 这里的判断只能通过角色名,可以弄成常量 + if role.name == "学生" + StudentsForCourse.create(:student_id => @member.user_id, :course_id =>@course.id) + else + joined = StudentsForCourse.where('student_id = ? and course_id = ?', @member.user_id,@course.id) + joined.each do |join| + join.delete + end + end + if role.allowed_to?(:is_manager) + @courseInfo = CourseInfos.new(:user_id => @member.user_id, :course_id => @course.id) + @courseInfo.save + else + user_admin = CourseInfos.where("user_id = ? and course_id = ?", @member.user_id, @course.id) + if user_admin.size > 0 + user_admin.each do |user| + user.destroy + end + end + end + end + end + + saved = @member.save + respond_to do |format| + format.html { redirect_to_settings_in_courses } + format.js + format.api { + if saved + render_api_ok + else + render_validation_errors(@member) + end + } + end + end + + end + + def destroy + #modify by nwb + #课程成员删除修改 + if @project + if request.delete? && @member.deletable? + @member.destroy + # end + user_admin = ProjectInfo.where("user_id = ? and project_id = ?", @member.user_id, @project.id) + if user_admin.size > 0 + user_admin.each do |user| + user.destroy + end + end + user_grade = UserGrade.where("user_id = ? and project_id = ?", @member.user_id, @project.id) + if user_grade.size > 0 + user_grade.each do |grade| + grade.destroy + end + end + end + respond_to do |format| + format.html { redirect_to_settings_in_projects } + format.js + format.api { + if @member.destroyed? + render_api_ok + else + head :unprocessable_entity + end + } + end + elsif @course + if request.delete? && @member.deletable? + @member.destroy + user_admin = CourseInfos.where("user_id = ? and course_id = ?", @member.user_id, @course.id) + if user_admin.size > 0 + user_admin.each do |user| + user.destroy + end + end + joined = StudentsForCourse.where('student_id = ? and course_id = ?', @member.user_id,@course.id) + joined.each do |join| + join.delete + end + + end + respond_to do |format| + format.html { redirect_to_settings_in_courses } + format.js + format.api { + if @member.destroyed? + render_api_ok + else + head :unprocessable_entity + end + } + end + end + end + + def autocomplete + respond_to do |format| + format.js + end + end + + private + + def redirect_to_settings_in_projects + redirect_to settings_project_url(@project, :tab => 'members') + end + + def redirect_to_settings_in_courses + redirect_to settings_course_url(@course, :tab => 'members') + end +end diff --git a/app/controllers/memos_controller.rb b/app/controllers/memos_controller.rb index b980331df..9257888dd 100644 --- a/app/controllers/memos_controller.rb +++ b/app/controllers/memos_controller.rb @@ -1,207 +1,207 @@ -class MemosController < ApplicationController - default_search_scope :memos - before_filter :find_forum, :only => [:new, :create, :preview] - before_filter :find_attachments, :only => [:preview] - before_filter :find_memo, :except => [:new, :create, :preview] - before_filter :authenticate_user_edit, :only => [:edit, :update] - before_filter :authenticate_user_destroy, :only => [:destroy] - before_filter :require_login, :only => [:new, :create] - - helper :attachments - include AttachmentsHelper - include ApplicationHelper - - layout 'base_memos' - - def quote - @subject = @memo.subject - @subject = "RE: #{@subject}" unless @subject.starts_with?('RE:') - - @content = "#{ll(Setting.default_language, :text_user_wrote, @memo.author)}
((.|\s)*?)}m, '[...]').gsub(/(\r?\n|\r\n?)/, "\n") + "\n\n
" << @content - #@content = "> #{ll(Setting.default_language, :text_user_wrote, @memo.author)}\n> " - #@content << @memo.content.to_s.strip.gsub(%r{\n\n((.|\s)*?)}m, '[...]').gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n" - #@content_html = textilizable(@content) - @temp = Memo.new - @temp.content = @content - end - - def new - @memo = Memo.new - @memo.forum_id = @forum.id - - respond_to do |format| - format.html { - render action: :new ,layout: 'base' - } - format.json { render json: @memo } - end - end - - def create - - if params[:quote].nil? - @quote = "" - else - @quote = params[:quote] - end - - #unless params[:quote].nil? - # @quote = params[:quote][:quote] - #end - - @memo = Memo.new(params[:memo]) - @memo.forum_id = params[:forum_id] - @memo.author_id = User.current.id - - @memo.save_attachments(params[:attachments] || (params[:memo] && params[:memo][:uploads])) - @memo.content = @quote + @memo.content - respond_to do |format| - if @memo.save - format.html { redirect_to back_memo_url, notice: "#{l :label_memo_create_succ}" } - format.json { render json: @memo, status: :created, location: @memo } - else - flash.now[:error] = "#{l :label_memo_create_fail}: #{@memo.errors.full_messages[0]}" - # back_error_page = @memo.parent_id.nil? ? forum_path(@forum) : forum_memo_path(@forum, @memo.parent_id) - pre_count = REPLIES_PER_PAGE - - @memo_new = @memo.dup - @memo = @memo.root # 取出楼主,防止输入帖子id让回复作为主贴显示 - unless @memo.new_record? - @memo.update_column(:viewed_count, (@memo.viewed_count.to_i + 1)) - end - - - page = params[:page] - if params[:r] && page.nil? - offset = @memo.children.where("#{Memo.table_name}.id < ?", params[:r].to_i).count - page = 1 + offset / pre_count - else - - end - @reply_count = @memo.children.count - @reply_pages = Paginator.new @reply_count, pre_count, page - @replies = @memo.children. - includes(:author, :attachments). - reorder("#{Memo.table_name}.created_at DESC"). - limit(@reply_pages.per_page). - offset(@reply_pages.offset). - all - if @memo.new_record? - format.html { render :new,:layout=>'base'} - else - format.html { render action: :show } - format.json { render json: @memo.errors, status: :unprocessable_entity } - end - - end - end - end - - REPLIES_PER_PAGE = 20 unless const_defined?(:REPLIES_PER_PAGE) - def show - pre_count = REPLIES_PER_PAGE - - @memo = @memo.root # 取出楼主,防止输入帖子id让回复作为主贴显示 - @memo.update_column(:viewed_count, (@memo.viewed_count.to_i + 1)) - - page = params[:page] - if params[:r] && page.nil? - offset = @memo.children.where("#{Memo.table_name}.id < ?", params[:r].to_i).count - page = 1 + offset / pre_count - else - - end - @reply_count = @memo.children.count - @reply_pages = Paginator.new @reply_count, pre_count, page - @replies = @memo.children. - includes(:author, :attachments). - reorder("#{Memo.table_name}.created_at DESC"). - limit(@reply_pages.per_page). - offset(@reply_pages.offset). - all - - @memo_new = Memo.new - - - # @memo = Memo.find_by_id(params[:id]) - # @forum = Forum.find(params[:forum_id]) - # @replies = @memo.replies - # @mome_new = Memo.new - - respond_to do |format| - format.html # show.html.erb - format.json { render json: @memo } - format.xml { render xml: @memo } - end - end - - def edit - @replying = false - end - - def update - respond_to do |format| - if( @memo.update_column(:subject, params[:memo][:subject]) && - @memo.update_column(:content, params[:memo][:content]) && - @memo.update_column(:sticky, params[:memo][:sticky]) && - @memo.update_column(:lock, params[:memo][:lock])) - @memo.save_attachments(params[:attachments] || (params[:memo] && params[:memo][:uploads])) - @memo.save - # @memo.root.update_attribute(:updated_at, @memo.updated_at) - format.html {redirect_to back_memo_url, notice: "#{l :label_memo_create_succ}"} - else - format.html { render action: "edit" } - format.json { render json: @person.errors, status: :unprocessable_entity } - end - end - end - - def destroy - @memo.destroy - - respond_to do |format| - # format.html { redirect_to @back_url } - format.html { redirect_to back_memo_or_forum_url } - format.json { head :no_content } - end - end - - private - - def find_memo - return unless find_forum - #@memo = @forum.memos.find(params[:id]) - @memo = Memo.find(params[:id]) - rescue ActiveRecord::RecordNotFound - render_404 - nil - end - - def find_forum - @forum = Forum.find(params[:forum_id]) - rescue ActiveRecord::RecordNotFound - render_404 - nil - end - - def authenticate_user_edit - find_memo - render_403 unless @memo.editable_by? User.current - end - - def authenticate_user_destroy - find_memo - render_403 unless @memo.destroyable_by? User.current - end - - def back_memo_url - forum_memo_path(@forum, (@memo.parent_id.nil? ? @memo : @memo.parent_id)) - end - - def back_memo_or_forum_url - @memo.parent_id.nil? ? forum_url(@forum) : forum_memo_url(@forum, @memo.parent_id) - end - -end +class MemosController < ApplicationController + default_search_scope :memos + before_filter :find_forum, :only => [:new, :create, :preview] + before_filter :find_attachments, :only => [:preview] + before_filter :find_memo, :except => [:new, :create, :preview] + before_filter :authenticate_user_edit, :only => [:edit, :update] + before_filter :authenticate_user_destroy, :only => [:destroy] + before_filter :require_login, :only => [:new, :create] + + helper :attachments + include AttachmentsHelper + include ApplicationHelper + + layout 'base_memos' + + def quote + @subject = @memo.subject + @subject = "RE: #{@subject}" unless @subject.starts_with?('RE:') + + @content = "#{ll(Setting.default_language, :text_user_wrote, @memo.author)}
" + @content << @memo.content.to_s.strip.gsub(%r{((.|\s)*?)}m, '[...]').gsub(/(\r?\n|\r\n?)/, "\n") + "
" << @content + #@content = "> #{ll(Setting.default_language, :text_user_wrote, @memo.author)}\n> " + #@content << @memo.content.to_s.strip.gsub(%r{((.|\s)*?)}m, '[...]').gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n" + #@content_html = textilizable(@content) + @temp = Memo.new + @temp.content = @content + end + + def new + @memo = Memo.new + @memo.forum_id = @forum.id + + respond_to do |format| + format.html { + render action: :new ,layout: 'base' + } + format.json { render json: @memo } + end + end + + def create + + if params[:quote].nil? + @quote = "" + else + @quote = params[:quote] + end + + #unless params[:quote].nil? + # @quote = params[:quote][:quote] + #end + + @memo = Memo.new(params[:memo]) + @memo.forum_id = params[:forum_id] + @memo.author_id = User.current.id + + @memo.save_attachments(params[:attachments] || (params[:memo] && params[:memo][:uploads])) + @memo.content = @quote + @memo.content + respond_to do |format| + if @memo.save + format.html { redirect_to back_memo_url, notice: "#{l :label_memo_create_succ}" } + format.json { render json: @memo, status: :created, location: @memo } + else + flash.now[:error] = "#{l :label_memo_create_fail}: #{@memo.errors.full_messages[0]}" + # back_error_page = @memo.parent_id.nil? ? forum_path(@forum) : forum_memo_path(@forum, @memo.parent_id) + pre_count = REPLIES_PER_PAGE + + @memo_new = @memo.dup + @memo = @memo.root # 取出楼主,防止输入帖子id让回复作为主贴显示 + unless @memo.new_record? + @memo.update_column(:viewed_count, (@memo.viewed_count.to_i + 1)) + end + + + page = params[:page] + if params[:r] && page.nil? + offset = @memo.children.where("#{Memo.table_name}.id < ?", params[:r].to_i).count + page = 1 + offset / pre_count + else + + end + @reply_count = @memo.children.count + @reply_pages = Paginator.new @reply_count, pre_count, page + @replies = @memo.children. + includes(:author, :attachments). + reorder("#{Memo.table_name}.created_at DESC"). + limit(@reply_pages.per_page). + offset(@reply_pages.offset). + all + if @memo.new_record? + format.html { render :new,:layout=>'base'} + else + format.html { render action: :show } + format.json { render json: @memo.errors, status: :unprocessable_entity } + end + + end + end + end + + REPLIES_PER_PAGE = 20 unless const_defined?(:REPLIES_PER_PAGE) + def show + pre_count = REPLIES_PER_PAGE + + @memo = @memo.root # 取出楼主,防止输入帖子id让回复作为主贴显示 + @memo.update_column(:viewed_count, (@memo.viewed_count.to_i + 1)) + + page = params[:page] + if params[:r] && page.nil? + offset = @memo.children.where("#{Memo.table_name}.id < ?", params[:r].to_i).count + page = 1 + offset / pre_count + else + + end + @reply_count = @memo.children.count + @reply_pages = Paginator.new @reply_count, pre_count, page + @replies = @memo.children. + includes(:author, :attachments). + reorder("#{Memo.table_name}.created_at DESC"). + limit(@reply_pages.per_page). + offset(@reply_pages.offset). + all + + @memo_new = Memo.new + + + # @memo = Memo.find_by_id(params[:id]) + # @forum = Forum.find(params[:forum_id]) + # @replies = @memo.replies + # @mome_new = Memo.new + + respond_to do |format| + format.html # show.html.erb + format.json { render json: @memo } + format.xml { render xml: @memo } + end + end + + def edit + @replying = false + end + + def update + respond_to do |format| + if( @memo.update_column(:subject, params[:memo][:subject]) && + @memo.update_column(:content, params[:memo][:content]) && + @memo.update_column(:sticky, params[:memo][:sticky]) && + @memo.update_column(:lock, params[:memo][:lock])) + @memo.save_attachments(params[:attachments] || (params[:memo] && params[:memo][:uploads])) + @memo.save + # @memo.root.update_attribute(:updated_at, @memo.updated_at) + format.html {redirect_to back_memo_url, notice: "#{l :label_memo_create_succ}"} + else + format.html { render action: "edit" } + format.json { render json: @person.errors, status: :unprocessable_entity } + end + end + end + + def destroy + @memo.destroy + + respond_to do |format| + # format.html { redirect_to @back_url } + format.html { redirect_to back_memo_or_forum_url } + format.json { head :no_content } + end + end + + private + + def find_memo + return unless find_forum + #@memo = @forum.memos.find(params[:id]) + @memo = Memo.find(params[:id]) + rescue ActiveRecord::RecordNotFound + render_404 + nil + end + + def find_forum + @forum = Forum.find(params[:forum_id]) + rescue ActiveRecord::RecordNotFound + render_404 + nil + end + + def authenticate_user_edit + find_memo + render_403 unless @memo.editable_by? User.current + end + + def authenticate_user_destroy + find_memo + render_403 unless @memo.destroyable_by? User.current + end + + def back_memo_url + forum_memo_path(@forum, (@memo.parent_id.nil? ? @memo : @memo.parent_id)) + end + + def back_memo_or_forum_url + @memo.parent_id.nil? ? forum_url(@forum) : forum_memo_url(@forum, @memo.parent_id) + end + +end diff --git a/app/controllers/my_controller.rb b/app/controllers/my_controller.rb index 4e23fc41b..73565a5ba 100644 --- a/app/controllers/my_controller.rb +++ b/app/controllers/my_controller.rb @@ -1,282 +1,282 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -#+ -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class MyController < ApplicationController - layout "users_base" - before_filter :require_login - - helper :issues - helper :users - helper :custom_fields - - BLOCKS = { 'issuesassignedtome' => :label_assigned_to_me_issues, - 'issuesreportedbyme' => :label_reported_issues, - 'issueswatched' => :label_watched_issues, - 'news' => :label_news_latest, - 'calendar' => :label_calendar, - 'documents' => :label_document_plural, - 'timelog' => :label_spent_time - }.merge(Redmine::Views::MyPage::Block.additional_blocks).freeze - - DEFAULT_LAYOUT = { 'left' => ['issuesassignedtome'], - 'right' => ['issuesreportedbyme'] - }.freeze - - def index - - page - render :action => 'page' - end - - # Show user's page - def page - @user = User.current - @Issues= Issue.visible.open. - where(:assigned_to_id => ([User.current.id] + User.current.group_ids)) - @limit = 10 - @feedback_count = @Issues.count - @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] - @offset ||= @feedback_pages.offset - @curse_attachments = @Issues[@offset, @limit] - - @blocks = @user.pref[:my_page_layout] || DEFAULT_LAYOUT - end - - def page2 - @limit = 10 - @user = User.current - @Issues= Issue.visible.open. - where(:assigned_to_id => ([User.current.id] + User.current.group_ids)) - @feedback_count = @Issues.count - @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] - @offset ||= @feedback_pages.offset - @curse_attachments = @Issues[@offset, @limit] - @state = false - @blocks = @user.pref[:my_page_layout] || DEFAULT_LAYOUT - respond_to do |format| - format.js - end - end - - # Edit user's account - def account - @user = User.current - lg=@user.login - @pref = @user.pref - diskfile = disk_filename('User', @user.id) - diskfile1 = diskfile + 'temp' - if request.post? - @user.safe_attributes = params[:user] - @user.pref.attributes = params[:pref] - @user.pref[:no_self_notified] = (params[:no_self_notified] == '1') - @user.login = params[:login] - unless @user.user_extensions.nil? - if @user.user_extensions.identity == 2 - @user.firstname = params[:enterprise_name] - end - end - - @se = @user.extensions - @se.school_id = params[:occupation] if params[:occupation] - @se.gender = params[:gender] - @se.location = params[:province] if params[:province] - @se.location_city = params[:city] if params[:city] - @se.identity = params[:identity].to_i if params[:identity] - @se.technical_title = params[:technical_title] if params[:technical_title] - @se.student_id = params[:no] if params[:no] - - if @user.save && @se.save - # 头像保存 - if File.exist?(diskfile1) - if File.exist?(diskfile) - File.delete(diskfile) - end - File.open(diskfile1, "rb") do |f| - buffer = f.read(10) - if buffer != "DELETE" - File.open(diskfile1, "rb") do |f1| - File.open(diskfile, "wb") do |f| - buffer = "" - while (buffer = f1.read(8192)) - f.write(buffer) - end - end - end - - # File.rename(diskfile + 'temp',diskfile); - end - end - end - - # 确保文件被删除 - if File.exist?(diskfile1) - File.delete(diskfile1) - end - - @user.pref.save - @user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : []) - set_language_if_valid @user.language - flash.now[:notice] = l(:notice_account_updated) - redirect_to user_url(@user) - return - else - # 确保文件被删除 - if File.exist?(diskfile1) - File.delete(diskfile1) - end - @user.login = lg - end - else - # 确保文件被删除 - if File.exist?(diskfile1) - File.delete(diskfile1) - end - end - end - - # Destroys user's account - def destroy - @user = User.current - unless @user.own_account_deletable? - redirect_to my_account_url - return - end - - if request.post? && params[:confirm] - @user.destroy - if @user.destroyed? - logout_user - flash.now[:notice] = l(:notice_account_deleted) - end - redirect_to home_url - end - end - - # Manage user's password - def password - @user = User.current - unless @user.change_password_allowed? - flash.now[:error] = l(:notice_can_t_change_password) - redirect_to my_account_url - return - end - if request.post? - if @user.check_password?(params[:password]) - @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation] - - if @user.save - flash.now[:notice] = l(:notice_account_password_updated) - redirect_to my_account_url - end - else - flash.now[:error] = l(:notice_account_wrong_password) - end - end - end - - # Create a new feeds key - def reset_rss_key - if request.post? - if User.current.rss_token - User.current.rss_token.destroy - User.current.reload - end - User.current.rss_key - flash[:notice] = l(:notice_feeds_access_key_reseted) - end - redirect_to my_account_url - end - - # Create a new API key - def reset_api_key - if request.post? - if User.current.api_token - User.current.api_token.destroy - User.current.reload - end - User.current.api_key - flash[:notice] = l(:notice_api_access_key_reseted) - end - redirect_to my_account_url - end - - # User's page layout configuration - def page_layout - @user = User.current - @blocks = @user.pref[:my_page_layout] || DEFAULT_LAYOUT.dup - @block_options = [] - BLOCKS.each do |k, v| - unless %w(top left right).detect {|f| (@blocks[f] ||= []).include?(k)} - @block_options << [l("my.blocks.#{v}", :default => [v, v.to_s.humanize]), k.dasherize] - end - end - end - - # Add a block to user's page - # The block is added on top of the page - # params[:block] : id of the block to add - def add_block - block = params[:block].to_s.underscore - if block.present? && BLOCKS.key?(block) - @user = User.current - layout = @user.pref[:my_page_layout] || {} - # remove if already present in a group - %w(top left right).each {|f| (layout[f] ||= []).delete block } - # add it on top - layout['top'].unshift block - @user.pref[:my_page_layout] = layout - @user.pref.save - end - redirect_to my_page_layout_url - end - - # Remove a block to user's page - # params[:block] : id of the block to remove - def remove_block - block = params[:block].to_s.underscore - @user = User.current - # remove block in all groups - layout = @user.pref[:my_page_layout] || {} - %w(top left right).each {|f| (layout[f] ||= []).delete block } - @user.pref[:my_page_layout] = layout - @user.pref.save - redirect_to my_page_layout_url - end - - # Change blocks order on user's page - # params[:group] : group to order (top, left or right) - # params[:list-(top|left|right)] : array of block ids of the group - def order_blocks - group = params[:group] - @user = User.current - if group.is_a?(String) - group_items = (params["blocks"] || []).collect(&:underscore) - group_items.each {|s| s.sub!(/^block_/, '')} - if group_items and group_items.is_a? Array - layout = @user.pref[:my_page_layout] || {} - # remove group blocks if they are presents in other groups - %w(top left right).each {|f| - layout[f] = (layout[f] || []) - group_items - } - layout[group] = group_items - @user.pref[:my_page_layout] = layout - @user.pref.save - end - end - render :nothing => true - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +#+ +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class MyController < ApplicationController + layout "users_base" + before_filter :require_login + + helper :issues + helper :users + helper :custom_fields + + BLOCKS = { 'issuesassignedtome' => :label_assigned_to_me_issues, + 'issuesreportedbyme' => :label_reported_issues, + 'issueswatched' => :label_watched_issues, + 'news' => :label_news_latest, + 'calendar' => :label_calendar, + 'documents' => :label_document_plural, + 'timelog' => :label_spent_time + }.merge(Redmine::Views::MyPage::Block.additional_blocks).freeze + + DEFAULT_LAYOUT = { 'left' => ['issuesassignedtome'], + 'right' => ['issuesreportedbyme'] + }.freeze + + def index + + page + render :action => 'page' + end + + # Show user's page + def page + @user = User.current + @Issues= Issue.visible.open. + where(:assigned_to_id => ([User.current.id] + User.current.group_ids)) + @limit = 10 + @feedback_count = @Issues.count + @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] + @offset ||= @feedback_pages.offset + @curse_attachments = @Issues[@offset, @limit] + + @blocks = @user.pref[:my_page_layout] || DEFAULT_LAYOUT + end + + def page2 + @limit = 10 + @user = User.current + @Issues= Issue.visible.open. + where(:assigned_to_id => ([User.current.id] + User.current.group_ids)) + @feedback_count = @Issues.count + @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] + @offset ||= @feedback_pages.offset + @curse_attachments = @Issues[@offset, @limit] + @state = false + @blocks = @user.pref[:my_page_layout] || DEFAULT_LAYOUT + respond_to do |format| + format.js + end + end + + # Edit user's account + def account + @user = User.current + lg=@user.login + @pref = @user.pref + diskfile = disk_filename('User', @user.id) + diskfile1 = diskfile + 'temp' + if request.post? + @user.safe_attributes = params[:user] + @user.pref.attributes = params[:pref] + @user.pref[:no_self_notified] = (params[:no_self_notified] == '1') + @user.login = params[:login] + unless @user.user_extensions.nil? + if @user.user_extensions.identity == 2 + @user.firstname = params[:enterprise_name] + end + end + + @se = @user.extensions + @se.school_id = params[:occupation] if params[:occupation] + @se.gender = params[:gender] + @se.location = params[:province] if params[:province] + @se.location_city = params[:city] if params[:city] + @se.identity = params[:identity].to_i if params[:identity] + @se.technical_title = params[:technical_title] if params[:technical_title] + @se.student_id = params[:no] if params[:no] + + if @user.save && @se.save + # 头像保存 + if File.exist?(diskfile1) + if File.exist?(diskfile) + File.delete(diskfile) + end + File.open(diskfile1, "rb") do |f| + buffer = f.read(10) + if buffer != "DELETE" + File.open(diskfile1, "rb") do |f1| + File.open(diskfile, "wb") do |f| + buffer = "" + while (buffer = f1.read(8192)) + f.write(buffer) + end + end + end + + # File.rename(diskfile + 'temp',diskfile); + end + end + end + + # 确保文件被删除 + if File.exist?(diskfile1) + File.delete(diskfile1) + end + + @user.pref.save + @user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : []) + set_language_if_valid @user.language + flash.now[:notice] = l(:notice_account_updated) + redirect_to user_url(@user) + return + else + # 确保文件被删除 + if File.exist?(diskfile1) + File.delete(diskfile1) + end + @user.login = lg + end + else + # 确保文件被删除 + if File.exist?(diskfile1) + File.delete(diskfile1) + end + end + end + + # Destroys user's account + def destroy + @user = User.current + unless @user.own_account_deletable? + redirect_to my_account_url + return + end + + if request.post? && params[:confirm] + @user.destroy + if @user.destroyed? + logout_user + flash.now[:notice] = l(:notice_account_deleted) + end + redirect_to home_url + end + end + + # Manage user's password + def password + @user = User.current + unless @user.change_password_allowed? + flash.now[:error] = l(:notice_can_t_change_password) + redirect_to my_account_url + return + end + if request.post? + if @user.check_password?(params[:password]) + @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation] + + if @user.save + flash.now[:notice] = l(:notice_account_password_updated) + redirect_to my_account_url + end + else + flash.now[:error] = l(:notice_account_wrong_password) + end + end + end + + # Create a new feeds key + def reset_rss_key + if request.post? + if User.current.rss_token + User.current.rss_token.destroy + User.current.reload + end + User.current.rss_key + flash[:notice] = l(:notice_feeds_access_key_reseted) + end + redirect_to my_account_url + end + + # Create a new API key + def reset_api_key + if request.post? + if User.current.api_token + User.current.api_token.destroy + User.current.reload + end + User.current.api_key + flash[:notice] = l(:notice_api_access_key_reseted) + end + redirect_to my_account_url + end + + # User's page layout configuration + def page_layout + @user = User.current + @blocks = @user.pref[:my_page_layout] || DEFAULT_LAYOUT.dup + @block_options = [] + BLOCKS.each do |k, v| + unless %w(top left right).detect {|f| (@blocks[f] ||= []).include?(k)} + @block_options << [l("my.blocks.#{v}", :default => [v, v.to_s.humanize]), k.dasherize] + end + end + end + + # Add a block to user's page + # The block is added on top of the page + # params[:block] : id of the block to add + def add_block + block = params[:block].to_s.underscore + if block.present? && BLOCKS.key?(block) + @user = User.current + layout = @user.pref[:my_page_layout] || {} + # remove if already present in a group + %w(top left right).each {|f| (layout[f] ||= []).delete block } + # add it on top + layout['top'].unshift block + @user.pref[:my_page_layout] = layout + @user.pref.save + end + redirect_to my_page_layout_url + end + + # Remove a block to user's page + # params[:block] : id of the block to remove + def remove_block + block = params[:block].to_s.underscore + @user = User.current + # remove block in all groups + layout = @user.pref[:my_page_layout] || {} + %w(top left right).each {|f| (layout[f] ||= []).delete block } + @user.pref[:my_page_layout] = layout + @user.pref.save + redirect_to my_page_layout_url + end + + # Change blocks order on user's page + # params[:group] : group to order (top, left or right) + # params[:list-(top|left|right)] : array of block ids of the group + def order_blocks + group = params[:group] + @user = User.current + if group.is_a?(String) + group_items = (params["blocks"] || []).collect(&:underscore) + group_items.each {|s| s.sub!(/^block_/, '')} + if group_items and group_items.is_a? Array + layout = @user.pref[:my_page_layout] || {} + # remove group blocks if they are presents in other groups + %w(top left right).each {|f| + layout[f] = (layout[f] || []) - group_items + } + layout[group] = group_items + @user.pref[:my_page_layout] = layout + @user.pref.save + end + end + render :nothing => true + end +end diff --git a/app/controllers/news_controller.rb b/app/controllers/news_controller.rb index ce06ea199..f1d97cbe7 100644 --- a/app/controllers/news_controller.rb +++ b/app/controllers/news_controller.rb @@ -1,176 +1,176 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class NewsController < ApplicationController - layout 'base_projects'# by young - default_search_scope :news - model_object News - before_filter :find_model_object, :except => [:new, :create, :index] - before_filter :find_project_from_association, :except => [:new, :create, :index] - before_filter :find_project_by_project_id, :only => [:new, :create] - before_filter :authorize, :except => [:index] - before_filter :find_optional_project, :only => :index - accept_rss_auth :index - accept_api_auth :index - - helper :watchers - helper :attachments - helper :project_score - - def index - case params[:format] - when 'xml', 'json' - @offset, @limit = api_offset_and_limit - else - @limit = 10 - end - - # modify by nwb - if params[:course_id] && @course==nil - @course = Course.find(params[:course_id]) - end - if @project - scope = @project ? @project.news.visible : News.visible - - @news_count = scope.count - @news_pages = Paginator.new @news_count, @limit, params['page'] - @offset ||= @news_pages.offset - @newss = scope.all(:include => [:author, :project], - :order => "#{News.table_name}.created_on DESC", - :offset => @offset, - :limit => @limit) - - respond_to do |format| - format.html { - @news = News.new # for adding news inline - # huang - - render :layout => false if request.xhr? - } - format.api - format.atom { render_feed(@newss, :title => (@project ? @project.name : Setting.app_title) + ": #{l(:label_news_plural)}") } - end - elsif @course - scope = @course ? @course.news.course_visible : News.course_visible - - @news_count = scope.count - @news_pages = Paginator.new @news_count, @limit, params['page'] - @offset ||= @news_pages.offset - @newss = scope.all(:include => [:author, :course], - :order => "#{News.table_name}.created_on DESC", - :offset => @offset, - :limit => @limit) - - respond_to do |format| - format.html { - @news = News.new - render :layout => 'base_courses' - } - format.api - format.atom { render_feed(@newss, :title => (@course ? @course.name : Setting.app_title) + ": #{l(:label_news_plural)}") } - end - end - end - - def show - @comments = @news.comments - @comments.reverse! if User.current.wants_comments_in_reverse_order? - #modify by nwb - if @news.course_id - @course = Course.find(@news.course_id) - if @course - render :layout => 'base_courses' - end - end - end - - def new - #modify by nwb - if @project - @news = News.new(:project => @project, :author => User.current) - elsif @course - @news = News.new(:course => @course, :author => User.current) - render :layout => 'base_courses' - end - end - - def create - #modify by nwb - if @project - @news = News.new(:project => @project, :author => User.current) - @news.safe_attributes = params[:news] - @news.save_attachments(params[:attachments]) - if @news.save - render_attachment_warning_if_needed(@news) - flash[:notice] = l(:notice_successful_create) - redirect_to project_news_index_url(@project) - else - layout_file = @project ? 'base_projects' : 'base_courses' - render :action => 'new', :layout => layout_file - end - elsif @course - @news = News.new(:course => @course, :author => User.current) - @news.safe_attributes = params[:news] - @news.save_attachments(params[:attachments]) - if @news.save - render_attachment_warning_if_needed(@news) - flash[:notice] = l(:notice_successful_create) - redirect_to course_news_index_url(@course) - else - layout_file = 'base_courses' - render :action => 'new', :layout => layout_file - end - end - end - - def edit - end - - def update - @news.safe_attributes = params[:news] - @news.save_attachments(params[:attachments]) - if @news.save - render_attachment_warning_if_needed(@news) - flash[:notice] = l(:notice_successful_update) - redirect_to news_url(@news) - else - #flash[:error] = l(:notice_successful_update) - redirect_to news_url(@news) - end - end - - def destroy - @news.destroy - # modify by nwb - if @project - redirect_to project_news_index_url(@project) - elsif @course - redirect_to course_news_index_url(@course) - end - - end - - private - - def find_optional_project - return true unless params[:project_id] - @project = Project.find(params[:project_id]) - authorize - rescue ActiveRecord::RecordNotFound - render_404 - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class NewsController < ApplicationController + layout 'base_projects'# by young + default_search_scope :news + model_object News + before_filter :find_model_object, :except => [:new, :create, :index] + before_filter :find_project_from_association, :except => [:new, :create, :index] + before_filter :find_project_by_project_id, :only => [:new, :create] + before_filter :authorize, :except => [:index] + before_filter :find_optional_project, :only => :index + accept_rss_auth :index + accept_api_auth :index + + helper :watchers + helper :attachments + helper :project_score + + def index + case params[:format] + when 'xml', 'json' + @offset, @limit = api_offset_and_limit + else + @limit = 10 + end + + # modify by nwb + if params[:course_id] && @course==nil + @course = Course.find(params[:course_id]) + end + if @project + scope = @project ? @project.news.visible : News.visible + + @news_count = scope.count + @news_pages = Paginator.new @news_count, @limit, params['page'] + @offset ||= @news_pages.offset + @newss = scope.all(:include => [:author, :project], + :order => "#{News.table_name}.created_on DESC", + :offset => @offset, + :limit => @limit) + + respond_to do |format| + format.html { + @news = News.new # for adding news inline + # huang + + render :layout => false if request.xhr? + } + format.api + format.atom { render_feed(@newss, :title => (@project ? @project.name : Setting.app_title) + ": #{l(:label_news_plural)}") } + end + elsif @course + scope = @course ? @course.news.course_visible : News.course_visible + + @news_count = scope.count + @news_pages = Paginator.new @news_count, @limit, params['page'] + @offset ||= @news_pages.offset + @newss = scope.all(:include => [:author, :course], + :order => "#{News.table_name}.created_on DESC", + :offset => @offset, + :limit => @limit) + + respond_to do |format| + format.html { + @news = News.new + render :layout => 'base_courses' + } + format.api + format.atom { render_feed(@newss, :title => (@course ? @course.name : Setting.app_title) + ": #{l(:label_news_plural)}") } + end + end + end + + def show + @comments = @news.comments + @comments.reverse! if User.current.wants_comments_in_reverse_order? + #modify by nwb + if @news.course_id + @course = Course.find(@news.course_id) + if @course + render :layout => 'base_courses' + end + end + end + + def new + #modify by nwb + if @project + @news = News.new(:project => @project, :author => User.current) + elsif @course + @news = News.new(:course => @course, :author => User.current) + render :layout => 'base_courses' + end + end + + def create + #modify by nwb + if @project + @news = News.new(:project => @project, :author => User.current) + @news.safe_attributes = params[:news] + @news.save_attachments(params[:attachments]) + if @news.save + render_attachment_warning_if_needed(@news) + flash[:notice] = l(:notice_successful_create) + redirect_to project_news_index_url(@project) + else + layout_file = @project ? 'base_projects' : 'base_courses' + render :action => 'new', :layout => layout_file + end + elsif @course + @news = News.new(:course => @course, :author => User.current) + @news.safe_attributes = params[:news] + @news.save_attachments(params[:attachments]) + if @news.save + render_attachment_warning_if_needed(@news) + flash[:notice] = l(:notice_successful_create) + redirect_to course_news_index_url(@course) + else + layout_file = 'base_courses' + render :action => 'new', :layout => layout_file + end + end + end + + def edit + end + + def update + @news.safe_attributes = params[:news] + @news.save_attachments(params[:attachments]) + if @news.save + render_attachment_warning_if_needed(@news) + flash[:notice] = l(:notice_successful_update) + redirect_to news_url(@news) + else + #flash[:error] = l(:notice_successful_update) + redirect_to news_url(@news) + end + end + + def destroy + @news.destroy + # modify by nwb + if @project + redirect_to project_news_index_url(@project) + elsif @course + redirect_to course_news_index_url(@course) + end + + end + + private + + def find_optional_project + return true unless params[:project_id] + @project = Project.find(params[:project_id]) + authorize + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff --git a/app/controllers/notificationcomments_controller.rb b/app/controllers/notificationcomments_controller.rb index 86345e9c6..9b7e5b249 100644 --- a/app/controllers/notificationcomments_controller.rb +++ b/app/controllers/notificationcomments_controller.rb @@ -1,36 +1,36 @@ -class NotificationcommentsController < ApplicationController - def show - - end - # default_search_scope :contestnotifications - # model_object Contestnotifications - # before_filter :authorize - - def create - #raise Unauthorized unless @contestnotifications.notificationcommentable? - @contest = Contest.find(params[:contest_id]) - @contestnotification = Contestnotification.find(params[:contestnotification_id]) - - # @notificaioncomment = Notificationcomment.new - # @notificaioncomment.safe_attributes = params[:notificationcomment] - # @notificaioncomment.author = User.current - comment = @contestnotification.notificationcomments.new(params[:notificationcomment].merge(author_id: User.current.id)) - if comment.save - flash[:notice] = l(:label_comment_added) - end - - redirect_to contest_contestnotification_url(@contest, @contestnotification) - end - - def destroy - @contest = Contest.find(params[:contest_id]) - @contestnotification = Contestnotification.find(params[:contestnotification_id]) - notificaioncomments = Notificationcomment.find(params[:id]) - notificaioncomments.destroy if notificaioncomments - #@contestnotifications = notificaioncomments.Contestnotification - #@contest = @contestnotifications.contest - #@contestnotifications.notificaioncomments.find(params[:notificaioncomment_id]).destroy - redirect_to contest_contestnotification_url(@contest,@contestnotification) - end - -end +class NotificationcommentsController < ApplicationController + def show + + end + # default_search_scope :contestnotifications + # model_object Contestnotifications + # before_filter :authorize + + def create + #raise Unauthorized unless @contestnotifications.notificationcommentable? + @contest = Contest.find(params[:contest_id]) + @contestnotification = Contestnotification.find(params[:contestnotification_id]) + + # @notificaioncomment = Notificationcomment.new + # @notificaioncomment.safe_attributes = params[:notificationcomment] + # @notificaioncomment.author = User.current + comment = @contestnotification.notificationcomments.new(params[:notificationcomment].merge(author_id: User.current.id)) + if comment.save + flash[:notice] = l(:label_comment_added) + end + + redirect_to contest_contestnotification_url(@contest, @contestnotification) + end + + def destroy + @contest = Contest.find(params[:contest_id]) + @contestnotification = Contestnotification.find(params[:contestnotification_id]) + notificaioncomments = Notificationcomment.find(params[:id]) + notificaioncomments.destroy if notificaioncomments + #@contestnotifications = notificaioncomments.Contestnotification + #@contest = @contestnotifications.contest + #@contestnotifications.notificaioncomments.find(params[:notificaioncomment_id]).destroy + redirect_to contest_contestnotification_url(@contest,@contestnotification) + end + +end diff --git a/app/controllers/open_source_projects_controller.rb b/app/controllers/open_source_projects_controller.rb index d4ac4027a..975bd669d 100644 --- a/app/controllers/open_source_projects_controller.rb +++ b/app/controllers/open_source_projects_controller.rb @@ -1,262 +1,262 @@ -class OpenSourceProjectsController < ApplicationController - - before_filter :find_osp, :only => [:master_apply, :accept_master_apply, :refuse_master_apply] - before_filter :require_master, :only => [:master_apply, :accept_master_apply, :refuse_master_apply] - - helper :sort - include SortHelper - helper :apply_project_masters - include ApplyProjectMastersHelper - helper :no_uses - include NoUsesHelper - # GET /open_source_projects - # GET /open_source_projects.json - def index - - @app_dir = params[:app_dir] - @language = params[:language] - @created_at = params[:created_at] - per_page_option = 10 - - @open_source_projects = OpenSourceProject.filter(@app_dir, @language, @created_at) - @open_source_projects = @open_source_projects.like(params[:name]) if params[:name].present? - - @os_project_count = @open_source_projects.count - @os_project_pages = Paginator.new @os_project_count, per_page_option, params['page'] - - @open_source_projects = @open_source_projects.offset(@os_project_pages.offset).limit(@os_project_pages.per_page) - - @bugs = BugToOsp.order('created_at desc').limit(8) - - # @open_source_projects = OpenSourceProject.all - - respond_to do |format| - format.html # index.html.erb - format.json { render json: @open_source_projects } - end - end - - def master_apply - @apply = @open_source_project.apply_tips - @applicants = @open_source_project.applicants - - respond_to do |format| - format.html { - render :layout => "base_opensource_p" - } - format.json { render json: @open_source_project } - end - end - - # GET /open_source_projects/1 - # GET /open_source_projects/1.json - def show - @open_source_project = OpenSourceProject.find(params[:id]) - - sort_init 'updated_at', 'desc' - sort_update 'created_at' => "#{RelativeMemo.table_name}.created_at", - 'replies' => "#{RelativeMemo.table_name}.replies_count", - 'updated_at' => "COALESCE (last_replies_relative_memos.created_at, #{RelativeMemo.table_name}.created_at)" - - @memo = RelativeMemo.new(:open_source_project => @open_source_project) - @topic_count = @open_source_project.topics.count - @topic_pages = Paginator.new @topic_count, 10, params['page'] - @memos = @open_source_project.topics. - reorder("#{RelativeMemo.table_name}.sticky DESC"). - includes(:last_reply). - limit(@topic_pages.per_page). - offset(@topic_pages.offset). - order(sort_clause). - all - - @bugs = @open_source_project.bugs.limit(6) - - respond_to do |format| - format.html { - render :layout => "base_opensource_p" - } - format.json { render json: @open_source_project } - end - end - - def allbug - @bugs = BugToOsp.visible - - @bug_count = @bugs.count - @bug_pages = Paginator.new @bug_count, per_page_option, params['page'] - @bugs = @bugs.includes(:bug).reorder("#{RelativeMemo.table_name}.created_at DESC").limit(@bug_pages.per_page).offset(@bug_pages.offset).all - - respond_to do |format| - format.html - format.json { render json: @open_source_project } - end - end - - def search - - end - - def showbug - @open_source_project = OpenSourceProject.find(params[:id]) - - sort_init 'updated_at', 'desc' - sort_update 'created_at' => "#{RelativeMemo.table_name}.created_at", - 'replies' => "#{RelativeMemo.table_name}.replies_count", - 'updated_at' => "COALESCE (last_replies_relative_memos.created_at, #{RelativeMemo.table_name}.created_at)" - - @memo = RelativeMemo.new(:open_source_project => @open_source_project) - @topic_count = @open_source_project.bugs.count - @topic_pages = Paginator.new @topic_count, per_page_option, params['page'] - @memos = @open_source_project.bugs. - reorder("#{RelativeMemo.table_name}.sticky DESC"). - includes(:last_reply). - limit(@topic_pages.per_page). - offset(@topic_pages.offset). - order(sort_clause). - all - - respond_to do |format| - format.html { - render :layout => "base_opensource_p" - } - format.json { render json: @open_source_project } - end - end - - # added by yiang 暴力添加,请绕道 - def showmemo - @open_source_project = OpenSourceProject.find(params[:id]) - - sort_init 'updated_at', 'desc' - sort_update 'created_at' => "#{RelativeMemo.table_name}.created_at", - 'replies' => "#{RelativeMemo.table_name}.replies_count", - 'updated_at' => "COALESCE (last_replies_relative_memos.created_at, #{RelativeMemo.table_name}.created_at)" - - @memo = RelativeMemo.new(:open_source_project => @open_source_project) - @topic_count = @open_source_project.topics.count - @topic_pages = Paginator.new @topic_count, per_page_option, params['page'] - @memos = @open_source_project.topics. - reorder("#{RelativeMemo.table_name}.sticky DESC"). - includes(:last_reply). - limit(@topic_pages.per_page). - offset(@topic_pages.offset). - order(sort_clause). - all - - respond_to do |format| - format.html { - render :layout => "base_opensource_p" - } - format.json { render json: @open_source_project } - end - end - - # GET /open_source_projects/new - # GET /open_source_projects/new.json - def new - @open_source_project = OpenSourceProject.new - - respond_to do |format| - format.html # new.html.erb - format.json { render json: @open_source_project } - end - end - - # GET /open_source_projects/1/edit - def edit - @open_source_project = OpenSourceProject.find(params[:id]) - end - - # POST /open_source_projects - # POST /open_source_projects.json - def create - @open_source_project = OpenSourceProject.new(params[:open_source_project]) - - respond_to do |format| - if @open_source_project.save - format.html { redirect_to @open_source_project, notice: 'Open source project was successfully created.' } - format.json { render json: @open_source_project, status: :created, location: @open_source_project } - else - format.html { render action: "new" } - format.json { render json: @open_source_project.errors, status: :unprocessable_entity } - end - end - end - - # PUT /open_source_projects/1 - # PUT /open_source_projects/1.json - def update - @open_source_project = OpenSourceProject.find(params[:id]) - - respond_to do |format| - if @open_source_project.update_attributes(params[:open_source_project]) - format.html { redirect_to @open_source_project, notice: 'Open source project was successfully updated.' } - format.json { head :no_content } - else - format.html { render action: "edit" } - format.json { render json: @open_source_project.errors, status: :unprocessable_entity } - end - end - end - - # DELETE /open_source_projects/1 - # DELETE /open_source_projects/1.json - def destroy - @open_source_project = OpenSourceProject.find(params[:id]) - @open_source_project.destroy - - respond_to do |format| - format.html { redirect_to open_source_projects_url } - format.json { head :no_content } - end - end - - def remove_condition - @app_dir = params[:app_dir] - @language = params[:language] - @created_at = params[:created_at] - redirect_to open_source_projects_url(:app_dir => @app_dir, :language => @language, :created_at => @created_at, :name => params[:name]) - end - - def search - # per_page_option = 10 - # - # @open_source_projects = OpenSourceProject.filter(@app_dir, @language, @created_at) - # @open_source_projects = @open_source_projects.like(params[:name]) if params[:name].present? - # - # @os_project_count = @open_source_projects.count - # @os_project_pages = Paginator.new @os_project_count, per_page_option, params['page'] - # - # @open_source_projects = @open_source_projects.offset(@os_project_pages.offset).limit(@os_project_pages.per_page) - - redirect_to open_source_projects_url(:name => params[:name]) - - end - - def refuse_master_apply - @apply = ApplyProjectMaster.where("user_id = ? and apply_id = ? and apply_type = 'OpenSourceProject'", params[:user_id], @open_source_project.id) - @apply.first.destory - - redirect_to master_apply_open_source_project_url - end - - def accept_master_apply - @apply = ApplyProjectMaster.where("user_id = ? and apply_id = ? and apply_type = 'OpenSourceProject'", params[:user_id], @open_source_project.id) - if @apply.count == 1 - @apply.first.update_attributes(:status => 2) - end - - redirect_to master_apply_open_source_project_url - end - - private - - def require_master - render_403 unless @open_source_project.admin?(User.current) - end - - def find_osp - @open_source_project = OpenSourceProject.find(params[:id]) - render_404 unless @open_source_project.present? - end -end +class OpenSourceProjectsController < ApplicationController + + before_filter :find_osp, :only => [:master_apply, :accept_master_apply, :refuse_master_apply] + before_filter :require_master, :only => [:master_apply, :accept_master_apply, :refuse_master_apply] + + helper :sort + include SortHelper + helper :apply_project_masters + include ApplyProjectMastersHelper + helper :no_uses + include NoUsesHelper + # GET /open_source_projects + # GET /open_source_projects.json + def index + + @app_dir = params[:app_dir] + @language = params[:language] + @created_at = params[:created_at] + per_page_option = 10 + + @open_source_projects = OpenSourceProject.filter(@app_dir, @language, @created_at) + @open_source_projects = @open_source_projects.like(params[:name]) if params[:name].present? + + @os_project_count = @open_source_projects.count + @os_project_pages = Paginator.new @os_project_count, per_page_option, params['page'] + + @open_source_projects = @open_source_projects.offset(@os_project_pages.offset).limit(@os_project_pages.per_page) + + @bugs = BugToOsp.order('created_at desc').limit(8) + + # @open_source_projects = OpenSourceProject.all + + respond_to do |format| + format.html # index.html.erb + format.json { render json: @open_source_projects } + end + end + + def master_apply + @apply = @open_source_project.apply_tips + @applicants = @open_source_project.applicants + + respond_to do |format| + format.html { + render :layout => "base_opensource_p" + } + format.json { render json: @open_source_project } + end + end + + # GET /open_source_projects/1 + # GET /open_source_projects/1.json + def show + @open_source_project = OpenSourceProject.find(params[:id]) + + sort_init 'updated_at', 'desc' + sort_update 'created_at' => "#{RelativeMemo.table_name}.created_at", + 'replies' => "#{RelativeMemo.table_name}.replies_count", + 'updated_at' => "COALESCE (last_replies_relative_memos.created_at, #{RelativeMemo.table_name}.created_at)" + + @memo = RelativeMemo.new(:open_source_project => @open_source_project) + @topic_count = @open_source_project.topics.count + @topic_pages = Paginator.new @topic_count, 10, params['page'] + @memos = @open_source_project.topics. + reorder("#{RelativeMemo.table_name}.sticky DESC"). + includes(:last_reply). + limit(@topic_pages.per_page). + offset(@topic_pages.offset). + order(sort_clause). + all + + @bugs = @open_source_project.bugs.limit(6) + + respond_to do |format| + format.html { + render :layout => "base_opensource_p" + } + format.json { render json: @open_source_project } + end + end + + def allbug + @bugs = BugToOsp.visible + + @bug_count = @bugs.count + @bug_pages = Paginator.new @bug_count, per_page_option, params['page'] + @bugs = @bugs.includes(:bug).reorder("#{RelativeMemo.table_name}.created_at DESC").limit(@bug_pages.per_page).offset(@bug_pages.offset).all + + respond_to do |format| + format.html + format.json { render json: @open_source_project } + end + end + + def search + + end + + def showbug + @open_source_project = OpenSourceProject.find(params[:id]) + + sort_init 'updated_at', 'desc' + sort_update 'created_at' => "#{RelativeMemo.table_name}.created_at", + 'replies' => "#{RelativeMemo.table_name}.replies_count", + 'updated_at' => "COALESCE (last_replies_relative_memos.created_at, #{RelativeMemo.table_name}.created_at)" + + @memo = RelativeMemo.new(:open_source_project => @open_source_project) + @topic_count = @open_source_project.bugs.count + @topic_pages = Paginator.new @topic_count, per_page_option, params['page'] + @memos = @open_source_project.bugs. + reorder("#{RelativeMemo.table_name}.sticky DESC"). + includes(:last_reply). + limit(@topic_pages.per_page). + offset(@topic_pages.offset). + order(sort_clause). + all + + respond_to do |format| + format.html { + render :layout => "base_opensource_p" + } + format.json { render json: @open_source_project } + end + end + + # added by yiang 暴力添加,请绕道 + def showmemo + @open_source_project = OpenSourceProject.find(params[:id]) + + sort_init 'updated_at', 'desc' + sort_update 'created_at' => "#{RelativeMemo.table_name}.created_at", + 'replies' => "#{RelativeMemo.table_name}.replies_count", + 'updated_at' => "COALESCE (last_replies_relative_memos.created_at, #{RelativeMemo.table_name}.created_at)" + + @memo = RelativeMemo.new(:open_source_project => @open_source_project) + @topic_count = @open_source_project.topics.count + @topic_pages = Paginator.new @topic_count, per_page_option, params['page'] + @memos = @open_source_project.topics. + reorder("#{RelativeMemo.table_name}.sticky DESC"). + includes(:last_reply). + limit(@topic_pages.per_page). + offset(@topic_pages.offset). + order(sort_clause). + all + + respond_to do |format| + format.html { + render :layout => "base_opensource_p" + } + format.json { render json: @open_source_project } + end + end + + # GET /open_source_projects/new + # GET /open_source_projects/new.json + def new + @open_source_project = OpenSourceProject.new + + respond_to do |format| + format.html # new.html.erb + format.json { render json: @open_source_project } + end + end + + # GET /open_source_projects/1/edit + def edit + @open_source_project = OpenSourceProject.find(params[:id]) + end + + # POST /open_source_projects + # POST /open_source_projects.json + def create + @open_source_project = OpenSourceProject.new(params[:open_source_project]) + + respond_to do |format| + if @open_source_project.save + format.html { redirect_to @open_source_project, notice: 'Open source project was successfully created.' } + format.json { render json: @open_source_project, status: :created, location: @open_source_project } + else + format.html { render action: "new" } + format.json { render json: @open_source_project.errors, status: :unprocessable_entity } + end + end + end + + # PUT /open_source_projects/1 + # PUT /open_source_projects/1.json + def update + @open_source_project = OpenSourceProject.find(params[:id]) + + respond_to do |format| + if @open_source_project.update_attributes(params[:open_source_project]) + format.html { redirect_to @open_source_project, notice: 'Open source project was successfully updated.' } + format.json { head :no_content } + else + format.html { render action: "edit" } + format.json { render json: @open_source_project.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /open_source_projects/1 + # DELETE /open_source_projects/1.json + def destroy + @open_source_project = OpenSourceProject.find(params[:id]) + @open_source_project.destroy + + respond_to do |format| + format.html { redirect_to open_source_projects_url } + format.json { head :no_content } + end + end + + def remove_condition + @app_dir = params[:app_dir] + @language = params[:language] + @created_at = params[:created_at] + redirect_to open_source_projects_url(:app_dir => @app_dir, :language => @language, :created_at => @created_at, :name => params[:name]) + end + + def search + # per_page_option = 10 + # + # @open_source_projects = OpenSourceProject.filter(@app_dir, @language, @created_at) + # @open_source_projects = @open_source_projects.like(params[:name]) if params[:name].present? + # + # @os_project_count = @open_source_projects.count + # @os_project_pages = Paginator.new @os_project_count, per_page_option, params['page'] + # + # @open_source_projects = @open_source_projects.offset(@os_project_pages.offset).limit(@os_project_pages.per_page) + + redirect_to open_source_projects_url(:name => params[:name]) + + end + + def refuse_master_apply + @apply = ApplyProjectMaster.where("user_id = ? and apply_id = ? and apply_type = 'OpenSourceProject'", params[:user_id], @open_source_project.id) + @apply.first.destory + + redirect_to master_apply_open_source_project_url + end + + def accept_master_apply + @apply = ApplyProjectMaster.where("user_id = ? and apply_id = ? and apply_type = 'OpenSourceProject'", params[:user_id], @open_source_project.id) + if @apply.count == 1 + @apply.first.update_attributes(:status => 2) + end + + redirect_to master_apply_open_source_project_url + end + + private + + def require_master + render_403 unless @open_source_project.admin?(User.current) + end + + def find_osp + @open_source_project = OpenSourceProject.find(params[:id]) + render_404 unless @open_source_project.present? + end +end diff --git a/app/controllers/project_enumerations_controller.rb b/app/controllers/project_enumerations_controller.rb index 0534deed6..bb84dd2be 100644 --- a/app/controllers/project_enumerations_controller.rb +++ b/app/controllers/project_enumerations_controller.rb @@ -1,42 +1,42 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class ProjectEnumerationsController < ApplicationController - before_filter :find_project_by_project_id - before_filter :authorize - - def update - if request.put? && params[:enumerations] - Project.transaction do - params[:enumerations].each do |id, activity| - @project.update_or_create_time_entry_activity(id, activity) - end - end - flash[:notice] = l(:notice_successful_update) - end - - redirect_to settings_project_url(@project, :tab => 'activities') - end - - def destroy - @project.time_entry_activities.each do |time_entry_activity| - time_entry_activity.destroy(time_entry_activity.parent) - end - flash[:notice] = l(:notice_successful_update) - redirect_to settings_project_url(@project, :tab => 'activities') - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class ProjectEnumerationsController < ApplicationController + before_filter :find_project_by_project_id + before_filter :authorize + + def update + if request.put? && params[:enumerations] + Project.transaction do + params[:enumerations].each do |id, activity| + @project.update_or_create_time_entry_activity(id, activity) + end + end + flash[:notice] = l(:notice_successful_update) + end + + redirect_to settings_project_url(@project, :tab => 'activities') + end + + def destroy + @project.time_entry_activities.each do |time_entry_activity| + time_entry_activity.destroy(time_entry_activity.parent) + end + flash[:notice] = l(:notice_successful_update) + redirect_to settings_project_url(@project, :tab => 'activities') + end +end diff --git a/app/controllers/queries_controller.rb b/app/controllers/queries_controller.rb index d9a933c68..de1fa2a21 100644 --- a/app/controllers/queries_controller.rb +++ b/app/controllers/queries_controller.rb @@ -1,106 +1,106 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class QueriesController < ApplicationController - menu_item :issues - before_filter :find_query, :except => [:new, :create, :index] - before_filter :find_optional_project, :only => [:new, :create] - - accept_api_auth :index - - include QueriesHelper - - def index - case params[:format] - when 'xml', 'json' - @offset, @limit = api_offset_and_limit - else - @limit = per_page_option - end - - @query_count = IssueQuery.visible.count - @query_pages = Paginator.new @query_count, @limit, params['page'] - @queries = IssueQuery.visible.all(:limit => @limit, :offset => @offset, :order => "#{Query.table_name}.name") - - respond_to do |format| - format.api - end - end - - def new - @query = IssueQuery.new - @query.user = User.current - @query.project = @project - @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin? - @query.build_from_params(params) - end - - def create - @query = IssueQuery.new(params[:query]) - @query.user = User.current - @query.project = params[:query_is_for_all] ? nil : @project - @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin? - @query.build_from_params(params) - @query.column_names = nil if params[:default_columns] - - if @query.save - flash[:notice] = l(:notice_successful_create) - redirect_to _project_issues_url(@project, :query_id => @query) - else - render :action => 'new', :layout => !request.xhr? - end - end - - def edit - end - - def update - @query.attributes = params[:query] - @query.project = nil if params[:query_is_for_all] - @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin? - @query.build_from_params(params) - @query.column_names = nil if params[:default_columns] - - if @query.save - flash[:notice] = l(:notice_successful_update) - redirect_to _project_issues_url(@project, :query_id => @query) - else - render :action => 'edit' - end - end - - def destroy - @query.destroy - redirect_to _project_issues_url(@project, :set_filter => 1) - end - -private - def find_query - @query = IssueQuery.find(params[:id]) - @project = @query.project - render_403 unless @query.editable_by?(User.current) - rescue ActiveRecord::RecordNotFound - render_404 - end - - def find_optional_project - @project = Project.find(params[:project_id]) if params[:project_id] - render_403 unless User.current.allowed_to?(:save_queries, @project, :global => true) - rescue ActiveRecord::RecordNotFound - render_404 - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class QueriesController < ApplicationController + menu_item :issues + before_filter :find_query, :except => [:new, :create, :index] + before_filter :find_optional_project, :only => [:new, :create] + + accept_api_auth :index + + include QueriesHelper + + def index + case params[:format] + when 'xml', 'json' + @offset, @limit = api_offset_and_limit + else + @limit = per_page_option + end + + @query_count = IssueQuery.visible.count + @query_pages = Paginator.new @query_count, @limit, params['page'] + @queries = IssueQuery.visible.all(:limit => @limit, :offset => @offset, :order => "#{Query.table_name}.name") + + respond_to do |format| + format.api + end + end + + def new + @query = IssueQuery.new + @query.user = User.current + @query.project = @project + @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin? + @query.build_from_params(params) + end + + def create + @query = IssueQuery.new(params[:query]) + @query.user = User.current + @query.project = params[:query_is_for_all] ? nil : @project + @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin? + @query.build_from_params(params) + @query.column_names = nil if params[:default_columns] + + if @query.save + flash[:notice] = l(:notice_successful_create) + redirect_to _project_issues_url(@project, :query_id => @query) + else + render :action => 'new', :layout => !request.xhr? + end + end + + def edit + end + + def update + @query.attributes = params[:query] + @query.project = nil if params[:query_is_for_all] + @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin? + @query.build_from_params(params) + @query.column_names = nil if params[:default_columns] + + if @query.save + flash[:notice] = l(:notice_successful_update) + redirect_to _project_issues_url(@project, :query_id => @query) + else + render :action => 'edit' + end + end + + def destroy + @query.destroy + redirect_to _project_issues_url(@project, :set_filter => 1) + end + +private + def find_query + @query = IssueQuery.find(params[:id]) + @project = @query.project + render_403 unless @query.editable_by?(User.current) + rescue ActiveRecord::RecordNotFound + render_404 + end + + def find_optional_project + @project = Project.find(params[:project_id]) if params[:project_id] + render_403 unless User.current.allowed_to?(:save_queries, @project, :global => true) + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff --git a/app/controllers/roles_controller.rb b/app/controllers/roles_controller.rb index 5d1ab45d9..20ad4a7f3 100644 --- a/app/controllers/roles_controller.rb +++ b/app/controllers/roles_controller.rb @@ -1,108 +1,108 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class RolesController < ApplicationController - layout 'admin' - - before_filter :require_admin, :except => [:index, :show] - before_filter :require_admin_or_api_request, :only => [:index, :show] - before_filter :find_role, :only => [:show, :edit, :update, :destroy] - accept_api_auth :index, :show - - def index - respond_to do |format| - format.html { - @role_pages, @roles = paginate Role.sorted, :per_page => 25 - render :action => "index", :layout => false if request.xhr? - } - format.api { - @roles = Role.givable.all - } - end - end - - def show - respond_to do |format| - format.api - end - end - - def new - # Prefills the form with 'Non member' role permissions by default - @role = Role.new(params[:role] || {:permissions => Role.non_member.permissions}) - if params[:copy].present? && @copy_from = Role.find_by_id(params[:copy]) - @role.copy_from(@copy_from) - end - @roles = Role.sorted.all - end - - def create - @role = Role.new(params[:role]) - if request.post? && @role.save - # workflow copy - if !params[:copy_workflow_from].blank? && (copy_from = Role.find_by_id(params[:copy_workflow_from])) - @role.workflow_rules.copy(copy_from) - end - flash[:notice] = l(:notice_successful_create) - redirect_to roles_url - else - @roles = Role.sorted.all - render :action => 'new' - end - end - - def edit - end - - def update - if request.put? and @role.update_attributes(params[:role]) - flash[:notice] = l(:notice_successful_update) - redirect_to roles_url - else - render :action => 'edit' - end - end - - def destroy - @role.destroy - redirect_to roles_url - rescue - flash[:error] = l(:error_can_not_remove_role) - redirect_to roles_url - end - - def permissions - @roles = Role.sorted.all - @permissions = Redmine::AccessControl.permissions.select { |p| !p.public? } - if request.post? - @roles.each do |role| - role.permissions = params[:permissions][role.id.to_s] - role.save - end - flash[:notice] = l(:notice_successful_update) - redirect_to roles_url - end - end - - private - - def find_role - @role = Role.find(params[:id]) - rescue ActiveRecord::RecordNotFound - render_404 - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class RolesController < ApplicationController + layout 'admin' + + before_filter :require_admin, :except => [:index, :show] + before_filter :require_admin_or_api_request, :only => [:index, :show] + before_filter :find_role, :only => [:show, :edit, :update, :destroy] + accept_api_auth :index, :show + + def index + respond_to do |format| + format.html { + @role_pages, @roles = paginate Role.sorted, :per_page => 25 + render :action => "index", :layout => false if request.xhr? + } + format.api { + @roles = Role.givable.all + } + end + end + + def show + respond_to do |format| + format.api + end + end + + def new + # Prefills the form with 'Non member' role permissions by default + @role = Role.new(params[:role] || {:permissions => Role.non_member.permissions}) + if params[:copy].present? && @copy_from = Role.find_by_id(params[:copy]) + @role.copy_from(@copy_from) + end + @roles = Role.sorted.all + end + + def create + @role = Role.new(params[:role]) + if request.post? && @role.save + # workflow copy + if !params[:copy_workflow_from].blank? && (copy_from = Role.find_by_id(params[:copy_workflow_from])) + @role.workflow_rules.copy(copy_from) + end + flash[:notice] = l(:notice_successful_create) + redirect_to roles_url + else + @roles = Role.sorted.all + render :action => 'new' + end + end + + def edit + end + + def update + if request.put? and @role.update_attributes(params[:role]) + flash[:notice] = l(:notice_successful_update) + redirect_to roles_url + else + render :action => 'edit' + end + end + + def destroy + @role.destroy + redirect_to roles_url + rescue + flash[:error] = l(:error_can_not_remove_role) + redirect_to roles_url + end + + def permissions + @roles = Role.sorted.all + @permissions = Redmine::AccessControl.permissions.select { |p| !p.public? } + if request.post? + @roles.each do |role| + role.permissions = params[:permissions][role.id.to_s] + role.save + end + flash[:notice] = l(:notice_successful_update) + redirect_to roles_url + end + end + + private + + def find_role + @role = Role.find(params[:id]) + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index 112bc173e..67b80dbe9 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -1,111 +1,111 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class SearchController < ApplicationController - before_filter :find_optional_project - - def index - @question = params[:q] || "" - @question.strip! - @all_words = params[:all_words] ? params[:all_words].present? : true - @titles_only = params[:titles_only] ? params[:titles_only].present? : false - - projects_to_search = - case params[:scope] - when 'all' - nil - when 'my_projects' - User.current.memberships.collect(&:project) - when 'subprojects' - @project ? (@project.self_and_descendants.active.all) : nil - else - @project - end - - offset = nil - begin; offset = params[:offset].to_time if params[:offset]; rescue; end - - # quick jump to an issue - if (m = @question.match(/^#?(\d+)$/)) && (issue = Issue.visible.find_by_id(m[1].to_i)) - redirect_to issue_url(issue) - return - end - - @object_types = Redmine::Search.available_search_types.dup - if projects_to_search.is_a? Project - # don't search projects - @object_types.delete('projects') - # only show what the user is allowed to view - @object_types = @object_types.select {|o| User.current.allowed_to?("view_#{o}".to_sym, projects_to_search)} - end - - @scope = @object_types.select {|t| params[t]} - @scope = @object_types if @scope.empty? - - # extract tokens from the question - # eg. hello "bye bye" => ["hello", "bye bye"] - @tokens = @question.scan(%r{((\s|^)"[\s\w]+"(\s|$)|\S+)}).collect {|m| m.first.gsub(%r{(^\s*"\s*|\s*"\s*$)}, '')} - # tokens must be at least 2 characters long - @tokens = @tokens.uniq.select {|w| w.length > 1 } - - if !@tokens.empty? - # no more than 5 tokens to search for - @tokens.slice! 5..-1 if @tokens.size > 5 - - @results = [] - @results_by_type = Hash.new {|h,k| h[k] = 0} - - limit = 10 - @scope.each do |s| - r, c = s.singularize.camelcase.constantize.search(@tokens, projects_to_search, - :all_words => @all_words, - :titles_only => @titles_only, - :limit => (limit+1), - :offset => offset, - :before => params[:previous].nil?) - @results += r - @results_by_type[s] += c - end - @results = @results.sort {|a,b| b.event_datetime <=> a.event_datetime} - if params[:previous].nil? - @pagination_previous_date = @results[0].event_datetime if offset && @results[0] - if @results.size > limit - @pagination_next_date = @results[limit-1].event_datetime - @results = @results[0, limit] - end - else - @pagination_next_date = @results[-1].event_datetime if offset && @results[-1] - if @results.size > limit - @pagination_previous_date = @results[-(limit)].event_datetime - @results = @results[-(limit), limit] - end - end - else - @question = "" - end - render :layout => false if request.xhr? - end - -private - def find_optional_project - return true unless params[:id] - @project = Project.find(params[:id]) - check_project_privacy - rescue ActiveRecord::RecordNotFound - render_404 - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class SearchController < ApplicationController + before_filter :find_optional_project + + def index + @question = params[:q] || "" + @question.strip! + @all_words = params[:all_words] ? params[:all_words].present? : true + @titles_only = params[:titles_only] ? params[:titles_only].present? : false + + projects_to_search = + case params[:scope] + when 'all' + nil + when 'my_projects' + User.current.memberships.collect(&:project) + when 'subprojects' + @project ? (@project.self_and_descendants.active.all) : nil + else + @project + end + + offset = nil + begin; offset = params[:offset].to_time if params[:offset]; rescue; end + + # quick jump to an issue + if (m = @question.match(/^#?(\d+)$/)) && (issue = Issue.visible.find_by_id(m[1].to_i)) + redirect_to issue_url(issue) + return + end + + @object_types = Redmine::Search.available_search_types.dup + if projects_to_search.is_a? Project + # don't search projects + @object_types.delete('projects') + # only show what the user is allowed to view + @object_types = @object_types.select {|o| User.current.allowed_to?("view_#{o}".to_sym, projects_to_search)} + end + + @scope = @object_types.select {|t| params[t]} + @scope = @object_types if @scope.empty? + + # extract tokens from the question + # eg. hello "bye bye" => ["hello", "bye bye"] + @tokens = @question.scan(%r{((\s|^)"[\s\w]+"(\s|$)|\S+)}).collect {|m| m.first.gsub(%r{(^\s*"\s*|\s*"\s*$)}, '')} + # tokens must be at least 2 characters long + @tokens = @tokens.uniq.select {|w| w.length > 1 } + + if !@tokens.empty? + # no more than 5 tokens to search for + @tokens.slice! 5..-1 if @tokens.size > 5 + + @results = [] + @results_by_type = Hash.new {|h,k| h[k] = 0} + + limit = 10 + @scope.each do |s| + r, c = s.singularize.camelcase.constantize.search(@tokens, projects_to_search, + :all_words => @all_words, + :titles_only => @titles_only, + :limit => (limit+1), + :offset => offset, + :before => params[:previous].nil?) + @results += r + @results_by_type[s] += c + end + @results = @results.sort {|a,b| b.event_datetime <=> a.event_datetime} + if params[:previous].nil? + @pagination_previous_date = @results[0].event_datetime if offset && @results[0] + if @results.size > limit + @pagination_next_date = @results[limit-1].event_datetime + @results = @results[0, limit] + end + else + @pagination_next_date = @results[-1].event_datetime if offset && @results[-1] + if @results.size > limit + @pagination_previous_date = @results[-(limit)].event_datetime + @results = @results[-(limit), limit] + end + end + else + @question = "" + end + render :layout => false if request.xhr? + end + +private + def find_optional_project + return true unless params[:id] + @project = Project.find(params[:id]) + check_project_privacy + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff --git a/app/controllers/settings_controller.rb b/app/controllers/settings_controller.rb index a3f07e21a..c60d1bd8f 100644 --- a/app/controllers/settings_controller.rb +++ b/app/controllers/settings_controller.rb @@ -1,73 +1,73 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class SettingsController < ApplicationController - layout 'admin' - menu_item :plugins, :only => :plugin - - helper :queries - - before_filter :require_admin - - def index - edit - render :action => 'edit' - end - - def edit - @notifiables = Redmine::Notifiable.all - if request.post? && params[:settings] && params[:settings].is_a?(Hash) - settings = (params[:settings] || {}).dup.symbolize_keys - settings.each do |name, value| - # remove blank values in array settings - value.delete_if {|v| v.blank? } if value.is_a?(Array) - Setting[name] = value - end - flash[:notice] = l(:notice_successful_update) - redirect_to settings_url(:tab => params[:tab]) - else - @options = {} - user_format = User::USER_FORMATS.collect{|key, value| [key, value[:setting_order]]}.sort{|a, b| a[1] <=> b[1]} - @options[:user_format] = user_format.collect{|f| [User.current.name(f[0]), f[0].to_s]} - @deliveries = ActionMailer::Base.perform_deliveries - - @guessed_host_and_path = request.host_with_port.dup - @guessed_host_and_path << ('/'+ Redmine::Utils.relative_url_root.gsub(%r{^\/}, '')) unless Redmine::Utils.relative_url_root.blank? - - Redmine::Themes.rescan - end - end - - def plugin - @plugin = Redmine::Plugin.find(params[:id]) - unless @plugin.configurable? - render_404 - return - end - - if request.post? - Setting.send "plugin_#{@plugin.id}=", params[:settings] - flash[:notice] = l(:notice_successful_update) - redirect_to plugin_settings_url(@plugin) - else - @partial = @plugin.settings[:partial] - @settings = Setting.send "plugin_#{@plugin.id}" - end - rescue Redmine::PluginNotFound - render_404 - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class SettingsController < ApplicationController + layout 'admin' + menu_item :plugins, :only => :plugin + + helper :queries + + before_filter :require_admin + + def index + edit + render :action => 'edit' + end + + def edit + @notifiables = Redmine::Notifiable.all + if request.post? && params[:settings] && params[:settings].is_a?(Hash) + settings = (params[:settings] || {}).dup.symbolize_keys + settings.each do |name, value| + # remove blank values in array settings + value.delete_if {|v| v.blank? } if value.is_a?(Array) + Setting[name] = value + end + flash[:notice] = l(:notice_successful_update) + redirect_to settings_url(:tab => params[:tab]) + else + @options = {} + user_format = User::USER_FORMATS.collect{|key, value| [key, value[:setting_order]]}.sort{|a, b| a[1] <=> b[1]} + @options[:user_format] = user_format.collect{|f| [User.current.name(f[0]), f[0].to_s]} + @deliveries = ActionMailer::Base.perform_deliveries + + @guessed_host_and_path = request.host_with_port.dup + @guessed_host_and_path << ('/'+ Redmine::Utils.relative_url_root.gsub(%r{^\/}, '')) unless Redmine::Utils.relative_url_root.blank? + + Redmine::Themes.rescan + end + end + + def plugin + @plugin = Redmine::Plugin.find(params[:id]) + unless @plugin.configurable? + render_404 + return + end + + if request.post? + Setting.send "plugin_#{@plugin.id}=", params[:settings] + flash[:notice] = l(:notice_successful_update) + redirect_to plugin_settings_url(@plugin) + else + @partial = @plugin.settings[:partial] + @settings = Setting.send "plugin_#{@plugin.id}" + end + rescue Redmine::PluginNotFound + render_404 + end +end diff --git a/app/controllers/softapplications_controller.rb b/app/controllers/softapplications_controller.rb index 5d87bebb6..0c7e2ade1 100644 --- a/app/controllers/softapplications_controller.rb +++ b/app/controllers/softapplications_controller.rb @@ -1,356 +1,356 @@ -class SoftapplicationsController < ApplicationController - layout "contest_base" - before_filter :find_softapplication, only: [:edit, :update, :destroy] - before_filter :editable, only: [:edit, :update] - before_filter :destroyable, only: :destroy - - # GET /softapplications - # GET /softapplications.json - def index - @softapplications = Softapplication.all - - #new added fenyefunction - @limit = 5 - @softapplication_count = @softapplications.count - @softapplication_pages = Paginator.new @softapplication_count, @limit, params['page'] - @offset ||= @softapplication_pages.offset - #@softapplications = @softapplications[@offset,@limit] - #new added end - - #new added sort - if params[:softapplication_sort_type].present? - case params[:softapplication_sort_type] - when '0' - @softapplications = @softapplications[@offset, @limit] - @s_state = 0 - when '1' - @softapplications = @softapplications.sort { |x, y| y[:created_at] <=> x[:created_at]}[@offset, @limit] - @s_state = 1 - end - else - @softapplications = @softapplications.sort { |x, y| y[:created_at] <=> x[:created_at]}[@offset, @limit] - @s_state = 1 - end - #new added end - - respond_to do |format| - format.html # index.html.erb - format.json { render json: @softapplications } - end - end - - # GET /softapplications/1 - # GET /softapplications/1.json - - def percent_of(num, percent) - num.to_f / percent.to_f * 100.0 - end - - def show - @softapplication = Softapplication.find(params[:id]) - @project = @softapplication.project - # 打分统计 - stars_reates = @softapplication. - rates(:quality) - stars_reates_count = stars_reates.count == 0 ? 1 : stars_reates.count - stars_status = stars_reates.select("stars, count(*) as scount"). - group("stars") - - @stars_status_map = Hash.new(0.0) - stars_status.each do |star_status| - percent = percent_of(star_status.scount, stars_reates_count).to_f - percent_m = format("%.2f", percent) - @stars_status_map["star#{star_status.stars.to_i}".to_sym] = - percent_m.to_s + "%" - end - @jours = @softapplication.journals_for_messages.order('created_on DESC') - @image_results = [] - @softapplication.attachments.each do |f| - f.image? ? @image_results << f : @image_results - end - @app_items = [] - @softapplication.attachments.each do |f| - f.pack? ? @app_items << f : @app_items - end - @limit = 10 - @feedback_count = @jours.count - @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] - @offset ||= @feedback_pages.offset - @jour = @jours[@offset, @limit] - @state = false - respond_to do |format| - format.html # show.html.erb - format.json { render json: @softapplication } - end - end - - # GET /softapplications/new - # GET /softapplications/new.json - def new - @softapplication = Softapplication.new - - #添加当前用户创建过的项目作为托管项目(下拉项目列表) - project = Project.find(params[:user_id]) - #end - - respond_to do |format| - format.html # new.html.erb - format.json { render json: @softapplication } - end - end - - # GET /softapplications/1/edit - def edit - @softapplication = Softapplication.find(params[:id]) - - @membership = User.current.memberships.all(:conditions => Project.visible_condition(User.current)) - @option = [] - # @contesting_project_count = @contesting_project_all.count - # @contesting_project_pages = Paginator.new @contesting_project_count, per_page_option, params['page'] - @membership.each do |membership| - unless(membership.project.project_type==1) - #拥有编辑项目权限的可操作该项目 - if User.current.allowed_to?(:quote_project,membership.project) - @option << membership.project - end - end - end - - end - - # POST /softapplications - # POST /softapplications.json - # def create - # @softapplication = Softapplication.new(params[:softapplication]) - # @softapplication.user = User.current - # @softapplication.save_attachments(params[:attachments]) - # respond_to do |format| - # if @softapplication.save - # format.js - # format.html { redirect_to @softapplication, notice: 'Softapplication was successfully created.' } - # # format.json { render json: @softapplication, status: :created, location: @softapplication } - # else - # format.js { render status: 406 } - # format.html { render action: "new" } - # # format.json { render json: @softapplication.errors, status: :unprocessable_entity } - # end - # end - # end - - -#new changed created function - def create - #options = params[:softapplication] - #options[:app_type_name] = params[:other_input] if options[:app_type_name] == "其他" && params[:other_input] - @softapplication = Softapplication.new(params[:softapplication]) - @softapplication.user = User.current - #@softapplication.deposit_project = params[:project] - @softapplication.project = Project.find_by_id(params[:project]) - @softapplication.app_type_name = params[:other_input] if params[:other_input] != "" - @softapplication.save_attachments(params[:attachments]) - respond_to do |format| - if @softapplication.save - ContestingSoftapplication.create(:contest_id => params[:contest_id], :softapplication_id => @softapplication.id) - #ProjectingSoftapplication.create_softapplication_projecting(:project_id => params[:project_id], :softapplication_id => @softapplication.id) - #ProjectingSoftapplication.create_softapplication_projecting(@project.id, softapplication.id) - format.html { redirect_to show_attendingcontest_contest_url(:id => params[:contest_id]), notice: l(:notice_attendingcontest_work_successfully_created) } - # format.json { render json: @softapplication, status: :created, location: @softapplication } - else - #format.js { render status: 406 } - format.html { render action: "contests/show_attendingcontest" } - # format.json { render json: @softapplication.errors, status: :unprocessable_entity } - end - end - #关联新建的参赛作品 - - # @contesting_softapplication = paginateHelper @contest.contesting_softapplications - - - - end - # PUT /softapplications/1 - # PUT /softapplications/1.json - def update - # @softapplication = Softapplication.find(params[:id]) - #@softapplication.attachments.map{|attach| attach.destroy } - @softapplication.save_attachments(params[:attachments]) if params[:attachments] - #@softapplication.deposit_project = params[:project] - @softapplication.project = Project.find_by_id(params[:project]) - - @softapplication.name = params[:softapplication][:name] - @softapplication.android_min_version_available = params[:softapplication][:android_min_version_available] - @softapplication.app_type_name = params[:other_input] == "" ? params[:softapplication][:app_type_name] : params[:other_input] - @softapplication.description = params[:softapplication][:description] - @softapplication.application_developers = params[:softapplication][:application_developers] - #@softapplication.app_type_name = params[:other_input] if params[:other_input] != "" - respond_to do |format| - #if @softapplication.update_attributes(params[:softapplication]) - if @softapplication.save - format.html { redirect_to @softapplication, notice: l(:notice_softapplication_was_successfully_updated) } - format.json { head :no_content } - else - format.html { render action: "edit" } - format.json { render json: @softapplication.errors, status: :unprocessable_entity } - end - end - end - - def add_attach - @softapplication = Softapplication.find(params[:id]) - @softapplication.save_attachments(params[:attachments]) - end - - # DELETE /softapplications/1 - # DELETE /softapplications/1.json - def destroy - # @softapplication = Softapplication.find(params[:id]) - @softapplication.destroy - - respond_to do |format| - format.html { redirect_to home_url } - format.json { head :no_content } - end - end - - #应用评价涉及到的方法 - def new_message - @jour = JournalsForMessage.find(params[:journal_id]) if params[:journal_id] - if @jour - user = @jour.user - text = @jour.notes - else - user = @softapplication.user - text = @softapplication.description - end - text = text.to_s.strip.gsub(%r{((.|\s)*?)}m, '[...]') - @content = "> #{ll(User.current.language, :text_user_wrote, user)}\n> " - @content << text.gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n" - @id = user.id - rescue ActiveRecord::RecordNotFound - render_404 - end - - #新建评价 - def create_message - - if params[:reference_content] - message = params[:softapplication_message][:message] + "\n" + params[:reference_content] - else - message = params[:softapplication_message][:message] - end - refer_user_id = params[:softapplication_message][:reference_user_id].to_i - @softapplication = Softapplication.find(params[:id]) - @softapplication.add_jour(User.current, message, refer_user_id) - - - @user = @softapplication.user - @jours = @softapplication.journals_for_messages.where('m_parent_id IS NULL').order('created_on DESC') - - @limit = 10 - @feedback_count = @jours.count - @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] - @offset ||= @feedback_pages.offset - @jour = @jours[@offset, @limit] - #@softapplication.set_commit(@feedback_count) - - respond_to do |format| - format.js - end - - end - - ##删除评价 - def destroy_message - @user = @softapplication.user - if User.current.admin? || User.current.id == @user.id - JournalsForMessage.delete_message(params[:object_id]) - end - @jours = @softapplication.journals_for_messages.reverse - @limit = 10 - @feedback_count = @jours.count - @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] - @offset ||= @feedback_pages.offset - @jour = @jours[@offset, @limit] - - @softapplication.set_commit(@feedback_count) - respond_to do |format| - format.js - end - end - - # - def more - @jour = @softapplication.journals_for_messages - @jour.each_with_index {|j,i| j.indice = i+1} - @state = true - - respond_to do |format| - format.html { redirect_to :back } - format.js - #format.api { render_api_ok } - end - end - - # - def back - @jour = @softapplication.journals_for_messages - @jour.each_with_index {|j,i| j.indice = i+1} - @state = false - - respond_to do |format| - format.html { redirect_to :back } - format.js - #format.api { render_api_ok } - end - end - - def search - @softapplications = Softapplication.where("name like '%#{params[:name]}%'") - - #new added fenyefunction - @limit = 5 - @softapplication_count = @softapplications.count - @softapplication_pages = Paginator.new @softapplication_count, @limit, params['page'] - @offset ||= @softapplication_pages.offset - - #new added sort - if params[:softapplication_sort_type].present? - case params[:softapplication_sort_type] - when '0' - @softapplications = @softapplications[@offset, @limit] - @s_state = 0 - when '1' - @softapplications = @softapplications.sort { |x, y| y[:created_at] <=> x[:created_at]}[@offset, @limit] - @s_state = 1 - end - else - @softapplications = @softapplications.sort { |x, y| y[:created_at] <=> x[:created_at]}[@offset, @limit] - @s_state = 1 - end - #new added end - - respond_to do |format| - format.html - end - end - - private - def find_softapplication - @softapplication = Softapplication.find_by_id(params[:id]) - end - - def editable - unless @softapplication.editable_by? User.current - render_403 - return false - end - end - - def destroyable - unless @softapplication.destroyable_by? User.current - render_403 - return false - end - end - -end +class SoftapplicationsController < ApplicationController + layout "contest_base" + before_filter :find_softapplication, only: [:edit, :update, :destroy] + before_filter :editable, only: [:edit, :update] + before_filter :destroyable, only: :destroy + + # GET /softapplications + # GET /softapplications.json + def index + @softapplications = Softapplication.all + + #new added fenyefunction + @limit = 5 + @softapplication_count = @softapplications.count + @softapplication_pages = Paginator.new @softapplication_count, @limit, params['page'] + @offset ||= @softapplication_pages.offset + #@softapplications = @softapplications[@offset,@limit] + #new added end + + #new added sort + if params[:softapplication_sort_type].present? + case params[:softapplication_sort_type] + when '0' + @softapplications = @softapplications[@offset, @limit] + @s_state = 0 + when '1' + @softapplications = @softapplications.sort { |x, y| y[:created_at] <=> x[:created_at]}[@offset, @limit] + @s_state = 1 + end + else + @softapplications = @softapplications.sort { |x, y| y[:created_at] <=> x[:created_at]}[@offset, @limit] + @s_state = 1 + end + #new added end + + respond_to do |format| + format.html # index.html.erb + format.json { render json: @softapplications } + end + end + + # GET /softapplications/1 + # GET /softapplications/1.json + + def percent_of(num, percent) + num.to_f / percent.to_f * 100.0 + end + + def show + @softapplication = Softapplication.find(params[:id]) + @project = @softapplication.project + # 打分统计 + stars_reates = @softapplication. + rates(:quality) + stars_reates_count = stars_reates.count == 0 ? 1 : stars_reates.count + stars_status = stars_reates.select("stars, count(*) as scount"). + group("stars") + + @stars_status_map = Hash.new(0.0) + stars_status.each do |star_status| + percent = percent_of(star_status.scount, stars_reates_count).to_f + percent_m = format("%.2f", percent) + @stars_status_map["star#{star_status.stars.to_i}".to_sym] = + percent_m.to_s + "%" + end + @jours = @softapplication.journals_for_messages.order('created_on DESC') + @image_results = [] + @softapplication.attachments.each do |f| + f.image? ? @image_results << f : @image_results + end + @app_items = [] + @softapplication.attachments.each do |f| + f.pack? ? @app_items << f : @app_items + end + @limit = 10 + @feedback_count = @jours.count + @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] + @offset ||= @feedback_pages.offset + @jour = @jours[@offset, @limit] + @state = false + respond_to do |format| + format.html # show.html.erb + format.json { render json: @softapplication } + end + end + + # GET /softapplications/new + # GET /softapplications/new.json + def new + @softapplication = Softapplication.new + + #添加当前用户创建过的项目作为托管项目(下拉项目列表) + project = Project.find(params[:user_id]) + #end + + respond_to do |format| + format.html # new.html.erb + format.json { render json: @softapplication } + end + end + + # GET /softapplications/1/edit + def edit + @softapplication = Softapplication.find(params[:id]) + + @membership = User.current.memberships.all(:conditions => Project.visible_condition(User.current)) + @option = [] + # @contesting_project_count = @contesting_project_all.count + # @contesting_project_pages = Paginator.new @contesting_project_count, per_page_option, params['page'] + @membership.each do |membership| + unless(membership.project.project_type==1) + #拥有编辑项目权限的可操作该项目 + if User.current.allowed_to?(:quote_project,membership.project) + @option << membership.project + end + end + end + + end + + # POST /softapplications + # POST /softapplications.json + # def create + # @softapplication = Softapplication.new(params[:softapplication]) + # @softapplication.user = User.current + # @softapplication.save_attachments(params[:attachments]) + # respond_to do |format| + # if @softapplication.save + # format.js + # format.html { redirect_to @softapplication, notice: 'Softapplication was successfully created.' } + # # format.json { render json: @softapplication, status: :created, location: @softapplication } + # else + # format.js { render status: 406 } + # format.html { render action: "new" } + # # format.json { render json: @softapplication.errors, status: :unprocessable_entity } + # end + # end + # end + + +#new changed created function + def create + #options = params[:softapplication] + #options[:app_type_name] = params[:other_input] if options[:app_type_name] == "其他" && params[:other_input] + @softapplication = Softapplication.new(params[:softapplication]) + @softapplication.user = User.current + #@softapplication.deposit_project = params[:project] + @softapplication.project = Project.find_by_id(params[:project]) + @softapplication.app_type_name = params[:other_input] if params[:other_input] != "" + @softapplication.save_attachments(params[:attachments]) + respond_to do |format| + if @softapplication.save + ContestingSoftapplication.create(:contest_id => params[:contest_id], :softapplication_id => @softapplication.id) + #ProjectingSoftapplication.create_softapplication_projecting(:project_id => params[:project_id], :softapplication_id => @softapplication.id) + #ProjectingSoftapplication.create_softapplication_projecting(@project.id, softapplication.id) + format.html { redirect_to show_attendingcontest_contest_url(:id => params[:contest_id]), notice: l(:notice_attendingcontest_work_successfully_created) } + # format.json { render json: @softapplication, status: :created, location: @softapplication } + else + #format.js { render status: 406 } + format.html { render action: "contests/show_attendingcontest" } + # format.json { render json: @softapplication.errors, status: :unprocessable_entity } + end + end + #关联新建的参赛作品 + + # @contesting_softapplication = paginateHelper @contest.contesting_softapplications + + + + end + # PUT /softapplications/1 + # PUT /softapplications/1.json + def update + # @softapplication = Softapplication.find(params[:id]) + #@softapplication.attachments.map{|attach| attach.destroy } + @softapplication.save_attachments(params[:attachments]) if params[:attachments] + #@softapplication.deposit_project = params[:project] + @softapplication.project = Project.find_by_id(params[:project]) + + @softapplication.name = params[:softapplication][:name] + @softapplication.android_min_version_available = params[:softapplication][:android_min_version_available] + @softapplication.app_type_name = params[:other_input] == "" ? params[:softapplication][:app_type_name] : params[:other_input] + @softapplication.description = params[:softapplication][:description] + @softapplication.application_developers = params[:softapplication][:application_developers] + #@softapplication.app_type_name = params[:other_input] if params[:other_input] != "" + respond_to do |format| + #if @softapplication.update_attributes(params[:softapplication]) + if @softapplication.save + format.html { redirect_to @softapplication, notice: l(:notice_softapplication_was_successfully_updated) } + format.json { head :no_content } + else + format.html { render action: "edit" } + format.json { render json: @softapplication.errors, status: :unprocessable_entity } + end + end + end + + def add_attach + @softapplication = Softapplication.find(params[:id]) + @softapplication.save_attachments(params[:attachments]) + end + + # DELETE /softapplications/1 + # DELETE /softapplications/1.json + def destroy + # @softapplication = Softapplication.find(params[:id]) + @softapplication.destroy + + respond_to do |format| + format.html { redirect_to home_url } + format.json { head :no_content } + end + end + + #应用评价涉及到的方法 + def new_message + @jour = JournalsForMessage.find(params[:journal_id]) if params[:journal_id] + if @jour + user = @jour.user + text = @jour.notes + else + user = @softapplication.user + text = @softapplication.description + end + text = text.to_s.strip.gsub(%r{((.|\s)*?)}m, '[...]') + @content = "> #{ll(User.current.language, :text_user_wrote, user)}\n> " + @content << text.gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n" + @id = user.id + rescue ActiveRecord::RecordNotFound + render_404 + end + + #新建评价 + def create_message + + if params[:reference_content] + message = params[:softapplication_message][:message] + "\n" + params[:reference_content] + else + message = params[:softapplication_message][:message] + end + refer_user_id = params[:softapplication_message][:reference_user_id].to_i + @softapplication = Softapplication.find(params[:id]) + @softapplication.add_jour(User.current, message, refer_user_id) + + + @user = @softapplication.user + @jours = @softapplication.journals_for_messages.where('m_parent_id IS NULL').order('created_on DESC') + + @limit = 10 + @feedback_count = @jours.count + @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] + @offset ||= @feedback_pages.offset + @jour = @jours[@offset, @limit] + #@softapplication.set_commit(@feedback_count) + + respond_to do |format| + format.js + end + + end + + ##删除评价 + def destroy_message + @user = @softapplication.user + if User.current.admin? || User.current.id == @user.id + JournalsForMessage.delete_message(params[:object_id]) + end + @jours = @softapplication.journals_for_messages.reverse + @limit = 10 + @feedback_count = @jours.count + @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] + @offset ||= @feedback_pages.offset + @jour = @jours[@offset, @limit] + + @softapplication.set_commit(@feedback_count) + respond_to do |format| + format.js + end + end + + # + def more + @jour = @softapplication.journals_for_messages + @jour.each_with_index {|j,i| j.indice = i+1} + @state = true + + respond_to do |format| + format.html { redirect_to :back } + format.js + #format.api { render_api_ok } + end + end + + # + def back + @jour = @softapplication.journals_for_messages + @jour.each_with_index {|j,i| j.indice = i+1} + @state = false + + respond_to do |format| + format.html { redirect_to :back } + format.js + #format.api { render_api_ok } + end + end + + def search + @softapplications = Softapplication.where("name like '%#{params[:name]}%'") + + #new added fenyefunction + @limit = 5 + @softapplication_count = @softapplications.count + @softapplication_pages = Paginator.new @softapplication_count, @limit, params['page'] + @offset ||= @softapplication_pages.offset + + #new added sort + if params[:softapplication_sort_type].present? + case params[:softapplication_sort_type] + when '0' + @softapplications = @softapplications[@offset, @limit] + @s_state = 0 + when '1' + @softapplications = @softapplications.sort { |x, y| y[:created_at] <=> x[:created_at]}[@offset, @limit] + @s_state = 1 + end + else + @softapplications = @softapplications.sort { |x, y| y[:created_at] <=> x[:created_at]}[@offset, @limit] + @s_state = 1 + end + #new added end + + respond_to do |format| + format.html + end + end + + private + def find_softapplication + @softapplication = Softapplication.find_by_id(params[:id]) + end + + def editable + unless @softapplication.editable_by? User.current + render_403 + return false + end + end + + def destroyable + unless @softapplication.destroyable_by? User.current + render_403 + return false + end + end + +end diff --git a/app/controllers/timelog_controller.rb b/app/controllers/timelog_controller.rb index e26608cf5..b80f47d72 100644 --- a/app/controllers/timelog_controller.rb +++ b/app/controllers/timelog_controller.rb @@ -1,315 +1,315 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class TimelogController < ApplicationController - layout 'base_projects'#added by young - menu_item :issues - - before_filter :find_project_for_new_time_entry, :only => [:create] - before_filter :find_time_entry, :only => [:show, :edit, :update] - before_filter :find_time_entries, :only => [:bulk_edit, :bulk_update, :destroy] - before_filter :authorize, :except => [:new, :index, :report] - - before_filter :find_optional_project, :only => [:index, :report] - before_filter :find_optional_project_for_new_time_entry, :only => [:new] - before_filter :authorize_global, :only => [:new, :index, :report] - - accept_rss_auth :index - accept_api_auth :index, :show, :create, :update, :destroy - - rescue_from Query::StatementInvalid, :with => :query_statement_invalid - - helper :sort - include SortHelper - helper :issues - include TimelogHelper - helper :custom_fields - include CustomFieldsHelper - helper :queries - include QueriesHelper - - def index - @query = TimeEntryQuery.build_from_params(params, :project => @project, :name => '_') - scope = time_entry_scope - - sort_init(@query.sort_criteria.empty? ? [['spent_on', 'desc']] : @query.sort_criteria) - sort_update(@query.sortable_columns) - - respond_to do |format| - format.html { - # Paginate results - @entry_count = scope.count - @entry_pages = Paginator.new @entry_count, per_page_option, params['page'] - @entries = scope.all( - :include => [:project, :activity, :user, {:issue => :tracker}], - :order => sort_clause, - :limit => @entry_pages.per_page, - :offset => @entry_pages.offset - ) - @total_hours = scope.sum(:hours).to_f - - render :layout => !request.xhr? - } - format.api { - @entry_count = scope.count - @offset, @limit = api_offset_and_limit - @entries = scope.all( - :include => [:project, :activity, :user, {:issue => :tracker}], - :order => sort_clause, - :limit => @limit, - :offset => @offset - ) - } - format.atom { - entries = scope.all( - :include => [:project, :activity, :user, {:issue => :tracker}], - :order => "#{TimeEntry.table_name}.created_on DESC", - :limit => Setting.feeds_limit.to_i - ) - render_feed(entries, :title => l(:label_spent_time)) - } - format.csv { - # Export all entries - @entries = scope.all( - :include => [:project, :activity, :user, {:issue => [:tracker, :assigned_to, :priority]}], - :order => sort_clause - ) - send_data(query_to_csv(@entries, @query, params), :type => 'text/csv; header=present', :filename => 'timelog.csv') - } - end - end - - def report - @query = TimeEntryQuery.build_from_params(params, :project => @project, :name => '_') - scope = time_entry_scope - - @report = Redmine::Helpers::TimeReport.new(@project, @issue, params[:criteria], params[:columns], scope) - - respond_to do |format| - format.html { render :layout => !request.xhr? } - format.csv { send_data(report_to_csv(@report), :type => 'text/csv; header=present', :filename => 'timelog.csv') } - end - end - - def show - respond_to do |format| - # TODO: Implement html response - format.html { render :nothing => true, :status => 406 } - format.api - end - end - - def new - @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today) - @time_entry.safe_attributes = params[:time_entry] - end - - def create - @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today) - @time_entry.safe_attributes = params[:time_entry] - - call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) - - if @time_entry.save - respond_to do |format| - format.html { - flash[:notice] = l(:notice_successful_create) - if params[:continue] - if params[:project_id] - options = { - :time_entry => {:issue_id => @time_entry.issue_id, :activity_id => @time_entry.activity_id}, - :back_url => params[:back_url] - } - if @time_entry.issue - redirect_to new_project_issue_time_entry_url(@time_entry.project, @time_entry.issue, options) - else - redirect_to new_project_time_entry_url(@time_entry.project, options) - end - else - options = { - :time_entry => {:project_id => @time_entry.project_id, :issue_id => @time_entry.issue_id, :activity_id => @time_entry.activity_id}, - :back_url => params[:back_url] - } - redirect_to new_time_entry_url(options) - end - else - redirect_back_or_default project_time_entries_path(@time_entry.project) - end - } - format.api { render :action => 'show', :status => :created, :location => time_entry_url(@time_entry) } - end - else - respond_to do |format| - format.html { render :action => 'new' } - format.api { render_validation_errors(@time_entry) } - end - end - end - - def edit - @time_entry.safe_attributes = params[:time_entry] - end - - def update - @time_entry.safe_attributes = params[:time_entry] - - call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) - - if @time_entry.save - respond_to do |format| - format.html { - flash[:notice] = l(:notice_successful_update) - redirect_back_or_default project_time_entries_path(@time_entry.project) - } - format.api { render_api_ok } - end - else - respond_to do |format| - format.html { render :action => 'edit' } - format.api { render_validation_errors(@time_entry) } - end - end - end - - def bulk_edit - @available_activities = TimeEntryActivity.shared.active - @custom_fields = TimeEntry.first.available_custom_fields - end - - def bulk_update - attributes = parse_params_for_bulk_time_entry_attributes(params) - - unsaved_time_entry_ids = [] - @time_entries.each do |time_entry| - time_entry.reload - time_entry.safe_attributes = attributes - call_hook(:controller_time_entries_bulk_edit_before_save, { :params => params, :time_entry => time_entry }) - unless time_entry.save - # Keep unsaved time_entry ids to display them in flash error - unsaved_time_entry_ids << time_entry.id - end - end - set_flash_from_bulk_time_entry_save(@time_entries, unsaved_time_entry_ids) - redirect_back_or_default project_time_entries_path(@projects.first) - end - - def destroy - destroyed = TimeEntry.transaction do - @time_entries.each do |t| - unless t.destroy && t.destroyed? - raise ActiveRecord::Rollback - end - end - end - - respond_to do |format| - format.html { - if destroyed - flash[:notice] = l(:notice_successful_delete) - else - flash[:error] = l(:notice_unable_delete_time_entry) - end - redirect_back_or_default project_time_entries_path(@projects.first) - } - format.api { - if destroyed - render_api_ok - else - render_validation_errors(@time_entries) - end - } - end - end - -private - def find_time_entry - @time_entry = TimeEntry.find(params[:id]) - unless @time_entry.editable_by?(User.current) - render_403 - return false - end - @project = @time_entry.project - rescue ActiveRecord::RecordNotFound - render_404 - end - - def find_time_entries - @time_entries = TimeEntry.find_all_by_id(params[:id] || params[:ids]) - raise ActiveRecord::RecordNotFound if @time_entries.empty? - @projects = @time_entries.collect(&:project).compact.uniq - @project = @projects.first if @projects.size == 1 - rescue ActiveRecord::RecordNotFound - render_404 - end - - def set_flash_from_bulk_time_entry_save(time_entries, unsaved_time_entry_ids) - if unsaved_time_entry_ids.empty? - flash[:notice] = l(:notice_successful_update) unless time_entries.empty? - else - flash[:error] = l(:notice_failed_to_save_time_entries, - :count => unsaved_time_entry_ids.size, - :total => time_entries.size, - :ids => '#' + unsaved_time_entry_ids.join(', #')) - end - end - - def find_optional_project_for_new_time_entry - if (project_id = (params[:project_id] || params[:time_entry] && params[:time_entry][:project_id])).present? - @project = Project.find(project_id) - end - if (issue_id = (params[:issue_id] || params[:time_entry] && params[:time_entry][:issue_id])).present? - @issue = Issue.find(issue_id) - @project ||= @issue.project - end - rescue ActiveRecord::RecordNotFound - render_404 - end - - def find_project_for_new_time_entry - find_optional_project_for_new_time_entry - if @project.nil? - render_404 - end - end - - def find_optional_project - if !params[:issue_id].blank? - @issue = Issue.find(params[:issue_id]) - @project = @issue.project - elsif !params[:project_id].blank? - @project = Project.find(params[:project_id]) - end - end - - # Returns the TimeEntry scope for index and report actions - def time_entry_scope - scope = TimeEntry.visible.where(@query.statement) - if @issue - scope = scope.on_issue(@issue) - elsif @project - scope = scope.on_project(@project, Setting.display_subprojects_issues?) - end - scope - end - - def parse_params_for_bulk_time_entry_attributes(params) - attributes = (params[:time_entry] || {}).reject {|k,v| v.blank?} - attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'} - attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values] - attributes - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class TimelogController < ApplicationController + layout 'base_projects'#added by young + menu_item :issues + + before_filter :find_project_for_new_time_entry, :only => [:create] + before_filter :find_time_entry, :only => [:show, :edit, :update] + before_filter :find_time_entries, :only => [:bulk_edit, :bulk_update, :destroy] + before_filter :authorize, :except => [:new, :index, :report] + + before_filter :find_optional_project, :only => [:index, :report] + before_filter :find_optional_project_for_new_time_entry, :only => [:new] + before_filter :authorize_global, :only => [:new, :index, :report] + + accept_rss_auth :index + accept_api_auth :index, :show, :create, :update, :destroy + + rescue_from Query::StatementInvalid, :with => :query_statement_invalid + + helper :sort + include SortHelper + helper :issues + include TimelogHelper + helper :custom_fields + include CustomFieldsHelper + helper :queries + include QueriesHelper + + def index + @query = TimeEntryQuery.build_from_params(params, :project => @project, :name => '_') + scope = time_entry_scope + + sort_init(@query.sort_criteria.empty? ? [['spent_on', 'desc']] : @query.sort_criteria) + sort_update(@query.sortable_columns) + + respond_to do |format| + format.html { + # Paginate results + @entry_count = scope.count + @entry_pages = Paginator.new @entry_count, per_page_option, params['page'] + @entries = scope.all( + :include => [:project, :activity, :user, {:issue => :tracker}], + :order => sort_clause, + :limit => @entry_pages.per_page, + :offset => @entry_pages.offset + ) + @total_hours = scope.sum(:hours).to_f + + render :layout => !request.xhr? + } + format.api { + @entry_count = scope.count + @offset, @limit = api_offset_and_limit + @entries = scope.all( + :include => [:project, :activity, :user, {:issue => :tracker}], + :order => sort_clause, + :limit => @limit, + :offset => @offset + ) + } + format.atom { + entries = scope.all( + :include => [:project, :activity, :user, {:issue => :tracker}], + :order => "#{TimeEntry.table_name}.created_on DESC", + :limit => Setting.feeds_limit.to_i + ) + render_feed(entries, :title => l(:label_spent_time)) + } + format.csv { + # Export all entries + @entries = scope.all( + :include => [:project, :activity, :user, {:issue => [:tracker, :assigned_to, :priority]}], + :order => sort_clause + ) + send_data(query_to_csv(@entries, @query, params), :type => 'text/csv; header=present', :filename => 'timelog.csv') + } + end + end + + def report + @query = TimeEntryQuery.build_from_params(params, :project => @project, :name => '_') + scope = time_entry_scope + + @report = Redmine::Helpers::TimeReport.new(@project, @issue, params[:criteria], params[:columns], scope) + + respond_to do |format| + format.html { render :layout => !request.xhr? } + format.csv { send_data(report_to_csv(@report), :type => 'text/csv; header=present', :filename => 'timelog.csv') } + end + end + + def show + respond_to do |format| + # TODO: Implement html response + format.html { render :nothing => true, :status => 406 } + format.api + end + end + + def new + @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today) + @time_entry.safe_attributes = params[:time_entry] + end + + def create + @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today) + @time_entry.safe_attributes = params[:time_entry] + + call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) + + if @time_entry.save + respond_to do |format| + format.html { + flash[:notice] = l(:notice_successful_create) + if params[:continue] + if params[:project_id] + options = { + :time_entry => {:issue_id => @time_entry.issue_id, :activity_id => @time_entry.activity_id}, + :back_url => params[:back_url] + } + if @time_entry.issue + redirect_to new_project_issue_time_entry_url(@time_entry.project, @time_entry.issue, options) + else + redirect_to new_project_time_entry_url(@time_entry.project, options) + end + else + options = { + :time_entry => {:project_id => @time_entry.project_id, :issue_id => @time_entry.issue_id, :activity_id => @time_entry.activity_id}, + :back_url => params[:back_url] + } + redirect_to new_time_entry_url(options) + end + else + redirect_back_or_default project_time_entries_path(@time_entry.project) + end + } + format.api { render :action => 'show', :status => :created, :location => time_entry_url(@time_entry) } + end + else + respond_to do |format| + format.html { render :action => 'new' } + format.api { render_validation_errors(@time_entry) } + end + end + end + + def edit + @time_entry.safe_attributes = params[:time_entry] + end + + def update + @time_entry.safe_attributes = params[:time_entry] + + call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) + + if @time_entry.save + respond_to do |format| + format.html { + flash[:notice] = l(:notice_successful_update) + redirect_back_or_default project_time_entries_path(@time_entry.project) + } + format.api { render_api_ok } + end + else + respond_to do |format| + format.html { render :action => 'edit' } + format.api { render_validation_errors(@time_entry) } + end + end + end + + def bulk_edit + @available_activities = TimeEntryActivity.shared.active + @custom_fields = TimeEntry.first.available_custom_fields + end + + def bulk_update + attributes = parse_params_for_bulk_time_entry_attributes(params) + + unsaved_time_entry_ids = [] + @time_entries.each do |time_entry| + time_entry.reload + time_entry.safe_attributes = attributes + call_hook(:controller_time_entries_bulk_edit_before_save, { :params => params, :time_entry => time_entry }) + unless time_entry.save + # Keep unsaved time_entry ids to display them in flash error + unsaved_time_entry_ids << time_entry.id + end + end + set_flash_from_bulk_time_entry_save(@time_entries, unsaved_time_entry_ids) + redirect_back_or_default project_time_entries_path(@projects.first) + end + + def destroy + destroyed = TimeEntry.transaction do + @time_entries.each do |t| + unless t.destroy && t.destroyed? + raise ActiveRecord::Rollback + end + end + end + + respond_to do |format| + format.html { + if destroyed + flash[:notice] = l(:notice_successful_delete) + else + flash[:error] = l(:notice_unable_delete_time_entry) + end + redirect_back_or_default project_time_entries_path(@projects.first) + } + format.api { + if destroyed + render_api_ok + else + render_validation_errors(@time_entries) + end + } + end + end + +private + def find_time_entry + @time_entry = TimeEntry.find(params[:id]) + unless @time_entry.editable_by?(User.current) + render_403 + return false + end + @project = @time_entry.project + rescue ActiveRecord::RecordNotFound + render_404 + end + + def find_time_entries + @time_entries = TimeEntry.find_all_by_id(params[:id] || params[:ids]) + raise ActiveRecord::RecordNotFound if @time_entries.empty? + @projects = @time_entries.collect(&:project).compact.uniq + @project = @projects.first if @projects.size == 1 + rescue ActiveRecord::RecordNotFound + render_404 + end + + def set_flash_from_bulk_time_entry_save(time_entries, unsaved_time_entry_ids) + if unsaved_time_entry_ids.empty? + flash[:notice] = l(:notice_successful_update) unless time_entries.empty? + else + flash[:error] = l(:notice_failed_to_save_time_entries, + :count => unsaved_time_entry_ids.size, + :total => time_entries.size, + :ids => '#' + unsaved_time_entry_ids.join(', #')) + end + end + + def find_optional_project_for_new_time_entry + if (project_id = (params[:project_id] || params[:time_entry] && params[:time_entry][:project_id])).present? + @project = Project.find(project_id) + end + if (issue_id = (params[:issue_id] || params[:time_entry] && params[:time_entry][:issue_id])).present? + @issue = Issue.find(issue_id) + @project ||= @issue.project + end + rescue ActiveRecord::RecordNotFound + render_404 + end + + def find_project_for_new_time_entry + find_optional_project_for_new_time_entry + if @project.nil? + render_404 + end + end + + def find_optional_project + if !params[:issue_id].blank? + @issue = Issue.find(params[:issue_id]) + @project = @issue.project + elsif !params[:project_id].blank? + @project = Project.find(params[:project_id]) + end + end + + # Returns the TimeEntry scope for index and report actions + def time_entry_scope + scope = TimeEntry.visible.where(@query.statement) + if @issue + scope = scope.on_issue(@issue) + elsif @project + scope = scope.on_project(@project, Setting.display_subprojects_issues?) + end + scope + end + + def parse_params_for_bulk_time_entry_attributes(params) + attributes = (params[:time_entry] || {}).reject {|k,v| v.blank?} + attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'} + attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values] + attributes + end +end diff --git a/app/controllers/trackers_controller.rb b/app/controllers/trackers_controller.rb index 988f03952..01bc47a2f 100644 --- a/app/controllers/trackers_controller.rb +++ b/app/controllers/trackers_controller.rb @@ -1,108 +1,108 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class TrackersController < ApplicationController - layout 'admin' - helper "project_score" - before_filter :require_admin, :except => :index - before_filter :require_admin_or_api_request, :only => :index - accept_api_auth :index - include CoursesHelper - def index - respond_to do |format| - format.html { - @tracker_pages, @trackers = paginate Tracker.sorted, :per_page => 25 - render :action => "index", :layout => false if request.xhr? - } - format.api { - @trackers = Tracker.sorted.all - } - end - end - - def new - @tracker ||= Tracker.new(params[:tracker]) - @trackers = Tracker.sorted.all - @projects = Project.where("project_type = #{Project::ProjectType_project}").all - @courses = Course.all - @course_activity_count=Hash.new - @courses.each do |course| - @course_activity_count[course.id]=0 - end - @course_activity_count=get_course_activity @courses,@course_activity_count - end - - def create - @tracker = Tracker.new(params[:tracker]) - if @tracker.save - # workflow copy - if !params[:copy_workflow_from].blank? && (copy_from = Tracker.find_by_id(params[:copy_workflow_from])) - @tracker.workflow_rules.copy(copy_from) - end - flash[:notice] = l(:notice_successful_create) - redirect_to trackers_url - return - end - new - render :action => 'new' - end - - def edit - @tracker ||= Tracker.find(params[:id]) - @projects = Project.where("project_type = #{Project::ProjectType_project}").all - @courses = Course.all - end - - def update - @tracker = Tracker.find(params[:id]) - if @tracker.update_attributes(params[:tracker]) - flash[:notice] = l(:notice_successful_update) - redirect_to trackers_url - return - end - edit - render :action => 'edit' - end - - def destroy - @tracker = Tracker.find(params[:id]) - unless @tracker.issues.empty? - flash[:error] = l(:error_can_not_delete_tracker) - else - @tracker.destroy - end - redirect_to trackers_url - end - - def fields - if request.post? && params[:trackers] - params[:trackers].each do |tracker_id, tracker_params| - tracker = Tracker.find_by_id(tracker_id) - if tracker - tracker.core_fields = tracker_params[:core_fields] - tracker.custom_field_ids = tracker_params[:custom_field_ids] - tracker.save - end - end - flash[:notice] = l(:notice_successful_update) - redirect_to fields_trackers_url - return - end - @trackers = Tracker.sorted.all - @custom_fields = IssueCustomField.all.sort - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class TrackersController < ApplicationController + layout 'admin' + helper "project_score" + before_filter :require_admin, :except => :index + before_filter :require_admin_or_api_request, :only => :index + accept_api_auth :index + include CoursesHelper + def index + respond_to do |format| + format.html { + @tracker_pages, @trackers = paginate Tracker.sorted, :per_page => 25 + render :action => "index", :layout => false if request.xhr? + } + format.api { + @trackers = Tracker.sorted.all + } + end + end + + def new + @tracker ||= Tracker.new(params[:tracker]) + @trackers = Tracker.sorted.all + @projects = Project.where("project_type = #{Project::ProjectType_project}").all + @courses = Course.all + @course_activity_count=Hash.new + @courses.each do |course| + @course_activity_count[course.id]=0 + end + @course_activity_count=get_course_activity @courses,@course_activity_count + end + + def create + @tracker = Tracker.new(params[:tracker]) + if @tracker.save + # workflow copy + if !params[:copy_workflow_from].blank? && (copy_from = Tracker.find_by_id(params[:copy_workflow_from])) + @tracker.workflow_rules.copy(copy_from) + end + flash[:notice] = l(:notice_successful_create) + redirect_to trackers_url + return + end + new + render :action => 'new' + end + + def edit + @tracker ||= Tracker.find(params[:id]) + @projects = Project.where("project_type = #{Project::ProjectType_project}").all + @courses = Course.all + end + + def update + @tracker = Tracker.find(params[:id]) + if @tracker.update_attributes(params[:tracker]) + flash[:notice] = l(:notice_successful_update) + redirect_to trackers_url + return + end + edit + render :action => 'edit' + end + + def destroy + @tracker = Tracker.find(params[:id]) + unless @tracker.issues.empty? + flash[:error] = l(:error_can_not_delete_tracker) + else + @tracker.destroy + end + redirect_to trackers_url + end + + def fields + if request.post? && params[:trackers] + params[:trackers].each do |tracker_id, tracker_params| + tracker = Tracker.find_by_id(tracker_id) + if tracker + tracker.core_fields = tracker_params[:core_fields] + tracker.custom_field_ids = tracker_params[:custom_field_ids] + tracker.save + end + end + flash[:notice] = l(:notice_successful_update) + redirect_to fields_trackers_url + return + end + @trackers = Tracker.sorted.all + @custom_fields = IssueCustomField.all.sort + end +end diff --git a/app/controllers/web_footer_companies_controller.rb b/app/controllers/web_footer_companies_controller.rb index 0fa076c2f..fdc037be2 100644 --- a/app/controllers/web_footer_companies_controller.rb +++ b/app/controllers/web_footer_companies_controller.rb @@ -1,52 +1,52 @@ -class WebFooterCompaniesController < ApplicationController - layout 'admin' - menu_item :projects, :only => :projects - menu_item :plugins, :only => :plugins - menu_item :info, :only => :info - before_filter :require_admin - - def index - @companys = WebFooterCompany.all - end - - def new - @company ||= WebFooterCompany.new - end - - def create - @company = WebFooterCompany.new(params[:web_footer_company]) - if @company.save - flash[:notice] = l(:notice_successful_create) - redirect_to web_footer_companies_url - else - flash[:error] = "#{l :web_footer_company_create_fail}: #{@company.errors.full_messages[0]}" - respond_to do |format| - format.html { render :action => 'new'} - format.api { render_validation_errors(@company) } - end - - end - end - - def destroy - @company = WebFooterCompany.find(params[:id]) - @company.destroy - redirect_to web_footer_companies_url - end - - def edit - @company = WebFooterCompany.find(params[:id]) - end - - def update - @company = WebFooterCompany.find(params[:id]) - if @company.update_attributes(params[:web_footer_company]) - flash[:notice] = l(:notice_successful_update) - redirect_to web_footer_companies_url - else - flash[:error] = "#{l :web_footer_company_update_fail}: #{@company.errors.full_messages[0]}" - render :action => 'edit' - end - end - -end +class WebFooterCompaniesController < ApplicationController + layout 'admin' + menu_item :projects, :only => :projects + menu_item :plugins, :only => :plugins + menu_item :info, :only => :info + before_filter :require_admin + + def index + @companys = WebFooterCompany.all + end + + def new + @company ||= WebFooterCompany.new + end + + def create + @company = WebFooterCompany.new(params[:web_footer_company]) + if @company.save + flash[:notice] = l(:notice_successful_create) + redirect_to web_footer_companies_url + else + flash[:error] = "#{l :web_footer_company_create_fail}: #{@company.errors.full_messages[0]}" + respond_to do |format| + format.html { render :action => 'new'} + format.api { render_validation_errors(@company) } + end + + end + end + + def destroy + @company = WebFooterCompany.find(params[:id]) + @company.destroy + redirect_to web_footer_companies_url + end + + def edit + @company = WebFooterCompany.find(params[:id]) + end + + def update + @company = WebFooterCompany.find(params[:id]) + if @company.update_attributes(params[:web_footer_company]) + flash[:notice] = l(:notice_successful_update) + redirect_to web_footer_companies_url + else + flash[:error] = "#{l :web_footer_company_update_fail}: #{@company.errors.full_messages[0]}" + render :action => 'edit' + end + end + +end diff --git a/app/controllers/wiki_controller.rb b/app/controllers/wiki_controller.rb index de9e53554..f74fbb04d 100644 --- a/app/controllers/wiki_controller.rb +++ b/app/controllers/wiki_controller.rb @@ -1,358 +1,358 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -require 'diff' - -# The WikiController follows the Rails REST controller pattern but with -# a few differences -# -# * index - shows a list of WikiPages grouped by page or date -# * new - not used -# * create - not used -# * show - will also show the form for creating a new wiki page -# * edit - used to edit an existing or new page -# * update - used to save a wiki page update to the database, including new pages -# * destroy - normal -# -# Other member and collection methods are also used -# -# TODO: still being worked on -class WikiController < ApplicationController - layout 'base_projects'#by young - default_search_scope :wiki_pages - before_filter :find_wiki, :authorize - before_filter :find_existing_or_new_page, :only => [:show, :edit, :update] - before_filter :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy, :destroy_version] - accept_api_auth :index, :show, :update, :destroy - before_filter :find_attachments, :only => [:preview] - - helper :attachments - include AttachmentsHelper - helper :watchers - include Redmine::Export::PDF - helper :project_score - - # List of pages, sorted alphabetically and by parent (hierarchy) - def index - load_pages_for_index - - respond_to do |format| - format.html { - @pages_by_parent_id = @pages.group_by(&:parent_id) - } - format.api - end - end - - # List of page, by last update - def date_index - load_pages_for_index - @pages_by_date = @pages.group_by {|p| p.updated_on.to_date} - end - - # display a page (in editing mode if it doesn't exist) - def show - if @page.new_record? - if User.current.allowed_to?(:edit_wiki_pages, @project) && editable? && !api_request? - edit - render :action => 'edit' - else - render_404 - end - return - end - if params[:version] && !User.current.allowed_to?(:view_wiki_edits, @project) - deny_access - return - end - @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") - return - elsif params[:format] == 'html' - export = render_to_string :action => 'export', :layout => false - send_data(export, :type => 'text/html', :filename => "#{@page.title}.html") - return - elsif params[:format] == 'txt' - send_data(@content.text, :type => 'text/plain', :filename => "#{@page.title}.txt") - return - end - end - @editable = editable? - @sections_editable = @editable && User.current.allowed_to?(:edit_wiki_pages, @page.project) && - @content.current_version? && - Redmine::WikiFormatting.supports_section_edit? - - respond_to do |format| - format.html - format.api - end - end - - # edit an existing page or a new one - def edit - return render_403 unless editable? - if @page.new_record? - @page.content = WikiContent.new(:page => @page) - if params[:parent].present? - @page.parent = @page.wiki.find_page(params[:parent].to_s) - end - end - - @content = @page.content_for_version(params[:version]) - @content.text = initial_page_content(@page) if @content.text.blank? - # don't keep previous comment - @content.comments = nil - - # To prevent StaleObjectError exception when reverting to a previous version - @content.version = @page.content.version - - @text = @content.text - if params[:section].present? && Redmine::WikiFormatting.supports_section_edit? - @section = params[:section].to_i - @text, @section_hash = Redmine::WikiFormatting.formatter.new(@text).get_section(@section) - render_404 if @text.blank? - end - end - - # Creates a new page or updates an existing one - def update - return render_403 unless editable? - was_new_page = @page.new_record? - @page.content = WikiContent.new(:page => @page) if @page.new_record? - @page.safe_attributes = params[:wiki_page] - - @content = @page.content - content_params = params[:content] - if content_params.nil? && params[:wiki_page].is_a?(Hash) - content_params = params[:wiki_page].slice(:text, :comments, :version) - end - content_params ||= {} - - @content.comments = content_params[:comments] - @text = content_params[:text] - if params[:section].present? && Redmine::WikiFormatting.supports_section_edit? - @section = params[:section].to_i - @section_hash = params[:section_hash] - @content.text = Redmine::WikiFormatting.formatter.new(@content.text).update_section(params[:section].to_i, @text, @section_hash) - else - @content.version = content_params[:version] if content_params[:version] - @content.text = @text - end - @content.author = User.current - - if @page.save_with_content - attachments = Attachment.attach_files(@page, params[:attachments]) - render_attachment_warning_if_needed(@page) - call_hook(:controller_wiki_edit_after_save, { :params => params, :page => @page}) - - respond_to do |format| - format.html { redirect_to project_wiki_page_url(@project, @page.title) } - format.api { - if was_new_page - render :action => 'show', :status => :created, :location => project_wiki_page_path(@project, @page.title) - else - render_api_ok - end - } - end - else - respond_to do |format| - format.html { render :action => 'edit' } - format.api { render_validation_errors(@content) } - end - end - - rescue ActiveRecord::StaleObjectError, Redmine::WikiFormatting::StaleSectionError - # Optimistic locking exception - respond_to do |format| - format.html { - flash.now[:error] = l(:notice_locking_conflict) - render :action => 'edit' - } - format.api { render_api_head :conflict } - end - rescue ActiveRecord::RecordNotSaved - respond_to do |format| - format.html { render :action => 'edit' } - format.api { render_validation_errors(@content) } - end - end - - # rename a page - def rename - return render_403 unless editable? - @page.redirect_existing_links = true - # used to display the *original* title if some AR validation errors occur - @original_title = @page.pretty_title - if request.post? && @page.update_attributes(params[:wiki_page]) - flash[:notice] = l(:notice_successful_update) - redirect_to project_wiki_page_url(@project, @page.title) - end - end - - def protect - @page.update_attribute :protected, params[:protected] - redirect_to project_wiki_page_url(@project, @page.title) - end - - # show page history - def history - @version_count = @page.content.versions.count - @version_pages = Paginator.new @version_count, per_page_option, params['page'] - # don't load text - @versions = @page.content.versions. - select("id, author_id, comments, updated_on, version"). - reorder('version DESC'). - limit(@version_pages.per_page + 1). - offset(@version_pages.offset). - all - - render :layout => false if request.xhr? - end - - def diff - @diff = @page.diff(params[:version], params[:version_from]) - render_404 unless @diff - end - - def annotate - @annotate = @page.annotate(params[:version]) - render_404 unless @annotate - end - - # Removes a wiki page and its history - # Children can be either set as root pages, removed or reassigned to another parent page - def destroy - return render_403 unless editable? - - @descendants_count = @page.descendants.size - if @descendants_count > 0 - case params[:todo] - when 'nullify' - # Nothing to do - when 'destroy' - # Removes all its descendants - @page.descendants.each(&:destroy) - when 'reassign' - # Reassign children to another parent page - reassign_to = @wiki.pages.find_by_id(params[:reassign_to_id].to_i) - return unless reassign_to - @page.children.each do |child| - child.update_attribute(:parent, reassign_to) - end - else - @reassignable_to = @wiki.pages - @page.self_and_descendants - # display the destroy form if it's a user request - return unless api_request? - end - end - @page.destroy - respond_to do |format| - format.html { redirect_to project_wiki_index_url(@project) } - format.api { render_api_ok } - end - end - - def destroy_version - return render_403 unless editable? - - @content = @page.content_for_version(params[:version]) - @content.destroy - redirect_to_referer_or history_project_wiki_page_url(@project, @page.title) - end - - # Export wiki to a single pdf or html file - def export - @pages = @wiki.pages.all(:order => 'title', :include => [:content, {:attachments => :author}]) - respond_to do |format| - format.html { - export = render_to_string :action => 'export_multiple', :layout => false - 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") - } - end - end - - def preview - page = @wiki.find_page(params[:id]) - # page is nil when previewing a new page - return render_403 unless page.nil? || editable?(page) - if page - @attachments += page.attachments - @previewed = page.content - end - @text = params[:content][:text] - render :partial => 'common/preview' - end - - def add_attachment - return render_403 unless editable? - attachments = Attachment.attach_files(@page, params[:attachments]) - render_attachment_warning_if_needed(@page) - redirect_to :action => 'show', :id => @page.title, :project_id => @project - end - -private - - def find_wiki - @project = Project.find(params[:project_id]) - @wiki = @project.wiki - render_404 unless @wiki - rescue ActiveRecord::RecordNotFound - render_404 - end - - # Finds the requested page or a new page if it doesn't exist - def find_existing_or_new_page - @page = @wiki.find_or_new_page(params[:id]) - if @wiki.page_found_with_redirect? - redirect_to params.update(:id => @page.title) - end - end - - # Finds the requested page and returns a 404 error if it doesn't exist - def find_existing_page - @page = @wiki.find_page(params[:id]) - if @page.nil? - render_404 - return - end - if @wiki.page_found_with_redirect? - redirect_to params.update(:id => @page.title) - end - end - - # Returns true if the current user is allowed to edit the page, otherwise false - def editable?(page = @page) - page.editable_by?(User.current) - end - - # Returns the default content of a new wiki page - def initial_page_content(page) - helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting) - extend helper unless self.instance_of?(helper) - helper.instance_method(:initial_page_content).bind(self).call(page) - end - - def load_pages_for_index - @pages = @wiki.pages.with_updated_on.reorder("#{WikiPage.table_name}.title").includes(:wiki => :project).includes(:parent).all - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'diff' + +# The WikiController follows the Rails REST controller pattern but with +# a few differences +# +# * index - shows a list of WikiPages grouped by page or date +# * new - not used +# * create - not used +# * show - will also show the form for creating a new wiki page +# * edit - used to edit an existing or new page +# * update - used to save a wiki page update to the database, including new pages +# * destroy - normal +# +# Other member and collection methods are also used +# +# TODO: still being worked on +class WikiController < ApplicationController + layout 'base_projects'#by young + default_search_scope :wiki_pages + before_filter :find_wiki, :authorize + before_filter :find_existing_or_new_page, :only => [:show, :edit, :update] + before_filter :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy, :destroy_version] + accept_api_auth :index, :show, :update, :destroy + before_filter :find_attachments, :only => [:preview] + + helper :attachments + include AttachmentsHelper + helper :watchers + include Redmine::Export::PDF + helper :project_score + + # List of pages, sorted alphabetically and by parent (hierarchy) + def index + load_pages_for_index + + respond_to do |format| + format.html { + @pages_by_parent_id = @pages.group_by(&:parent_id) + } + format.api + end + end + + # List of page, by last update + def date_index + load_pages_for_index + @pages_by_date = @pages.group_by {|p| p.updated_on.to_date} + end + + # display a page (in editing mode if it doesn't exist) + def show + if @page.new_record? + if User.current.allowed_to?(:edit_wiki_pages, @project) && editable? && !api_request? + edit + render :action => 'edit' + else + render_404 + end + return + end + if params[:version] && !User.current.allowed_to?(:view_wiki_edits, @project) + deny_access + return + end + @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") + return + elsif params[:format] == 'html' + export = render_to_string :action => 'export', :layout => false + send_data(export, :type => 'text/html', :filename => "#{@page.title}.html") + return + elsif params[:format] == 'txt' + send_data(@content.text, :type => 'text/plain', :filename => "#{@page.title}.txt") + return + end + end + @editable = editable? + @sections_editable = @editable && User.current.allowed_to?(:edit_wiki_pages, @page.project) && + @content.current_version? && + Redmine::WikiFormatting.supports_section_edit? + + respond_to do |format| + format.html + format.api + end + end + + # edit an existing page or a new one + def edit + return render_403 unless editable? + if @page.new_record? + @page.content = WikiContent.new(:page => @page) + if params[:parent].present? + @page.parent = @page.wiki.find_page(params[:parent].to_s) + end + end + + @content = @page.content_for_version(params[:version]) + @content.text = initial_page_content(@page) if @content.text.blank? + # don't keep previous comment + @content.comments = nil + + # To prevent StaleObjectError exception when reverting to a previous version + @content.version = @page.content.version + + @text = @content.text + if params[:section].present? && Redmine::WikiFormatting.supports_section_edit? + @section = params[:section].to_i + @text, @section_hash = Redmine::WikiFormatting.formatter.new(@text).get_section(@section) + render_404 if @text.blank? + end + end + + # Creates a new page or updates an existing one + def update + return render_403 unless editable? + was_new_page = @page.new_record? + @page.content = WikiContent.new(:page => @page) if @page.new_record? + @page.safe_attributes = params[:wiki_page] + + @content = @page.content + content_params = params[:content] + if content_params.nil? && params[:wiki_page].is_a?(Hash) + content_params = params[:wiki_page].slice(:text, :comments, :version) + end + content_params ||= {} + + @content.comments = content_params[:comments] + @text = content_params[:text] + if params[:section].present? && Redmine::WikiFormatting.supports_section_edit? + @section = params[:section].to_i + @section_hash = params[:section_hash] + @content.text = Redmine::WikiFormatting.formatter.new(@content.text).update_section(params[:section].to_i, @text, @section_hash) + else + @content.version = content_params[:version] if content_params[:version] + @content.text = @text + end + @content.author = User.current + + if @page.save_with_content + attachments = Attachment.attach_files(@page, params[:attachments]) + render_attachment_warning_if_needed(@page) + call_hook(:controller_wiki_edit_after_save, { :params => params, :page => @page}) + + respond_to do |format| + format.html { redirect_to project_wiki_page_url(@project, @page.title) } + format.api { + if was_new_page + render :action => 'show', :status => :created, :location => project_wiki_page_path(@project, @page.title) + else + render_api_ok + end + } + end + else + respond_to do |format| + format.html { render :action => 'edit' } + format.api { render_validation_errors(@content) } + end + end + + rescue ActiveRecord::StaleObjectError, Redmine::WikiFormatting::StaleSectionError + # Optimistic locking exception + respond_to do |format| + format.html { + flash.now[:error] = l(:notice_locking_conflict) + render :action => 'edit' + } + format.api { render_api_head :conflict } + end + rescue ActiveRecord::RecordNotSaved + respond_to do |format| + format.html { render :action => 'edit' } + format.api { render_validation_errors(@content) } + end + end + + # rename a page + def rename + return render_403 unless editable? + @page.redirect_existing_links = true + # used to display the *original* title if some AR validation errors occur + @original_title = @page.pretty_title + if request.post? && @page.update_attributes(params[:wiki_page]) + flash[:notice] = l(:notice_successful_update) + redirect_to project_wiki_page_url(@project, @page.title) + end + end + + def protect + @page.update_attribute :protected, params[:protected] + redirect_to project_wiki_page_url(@project, @page.title) + end + + # show page history + def history + @version_count = @page.content.versions.count + @version_pages = Paginator.new @version_count, per_page_option, params['page'] + # don't load text + @versions = @page.content.versions. + select("id, author_id, comments, updated_on, version"). + reorder('version DESC'). + limit(@version_pages.per_page + 1). + offset(@version_pages.offset). + all + + render :layout => false if request.xhr? + end + + def diff + @diff = @page.diff(params[:version], params[:version_from]) + render_404 unless @diff + end + + def annotate + @annotate = @page.annotate(params[:version]) + render_404 unless @annotate + end + + # Removes a wiki page and its history + # Children can be either set as root pages, removed or reassigned to another parent page + def destroy + return render_403 unless editable? + + @descendants_count = @page.descendants.size + if @descendants_count > 0 + case params[:todo] + when 'nullify' + # Nothing to do + when 'destroy' + # Removes all its descendants + @page.descendants.each(&:destroy) + when 'reassign' + # Reassign children to another parent page + reassign_to = @wiki.pages.find_by_id(params[:reassign_to_id].to_i) + return unless reassign_to + @page.children.each do |child| + child.update_attribute(:parent, reassign_to) + end + else + @reassignable_to = @wiki.pages - @page.self_and_descendants + # display the destroy form if it's a user request + return unless api_request? + end + end + @page.destroy + respond_to do |format| + format.html { redirect_to project_wiki_index_url(@project) } + format.api { render_api_ok } + end + end + + def destroy_version + return render_403 unless editable? + + @content = @page.content_for_version(params[:version]) + @content.destroy + redirect_to_referer_or history_project_wiki_page_url(@project, @page.title) + end + + # Export wiki to a single pdf or html file + def export + @pages = @wiki.pages.all(:order => 'title', :include => [:content, {:attachments => :author}]) + respond_to do |format| + format.html { + export = render_to_string :action => 'export_multiple', :layout => false + 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") + } + end + end + + def preview + page = @wiki.find_page(params[:id]) + # page is nil when previewing a new page + return render_403 unless page.nil? || editable?(page) + if page + @attachments += page.attachments + @previewed = page.content + end + @text = params[:content][:text] + render :partial => 'common/preview' + end + + def add_attachment + return render_403 unless editable? + attachments = Attachment.attach_files(@page, params[:attachments]) + render_attachment_warning_if_needed(@page) + redirect_to :action => 'show', :id => @page.title, :project_id => @project + end + +private + + def find_wiki + @project = Project.find(params[:project_id]) + @wiki = @project.wiki + render_404 unless @wiki + rescue ActiveRecord::RecordNotFound + render_404 + end + + # Finds the requested page or a new page if it doesn't exist + def find_existing_or_new_page + @page = @wiki.find_or_new_page(params[:id]) + if @wiki.page_found_with_redirect? + redirect_to params.update(:id => @page.title) + end + end + + # Finds the requested page and returns a 404 error if it doesn't exist + def find_existing_page + @page = @wiki.find_page(params[:id]) + if @page.nil? + render_404 + return + end + if @wiki.page_found_with_redirect? + redirect_to params.update(:id => @page.title) + end + end + + # Returns true if the current user is allowed to edit the page, otherwise false + def editable?(page = @page) + page.editable_by?(User.current) + end + + # Returns the default content of a new wiki page + def initial_page_content(page) + helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting) + extend helper unless self.instance_of?(helper) + helper.instance_method(:initial_page_content).bind(self).call(page) + end + + def load_pages_for_index + @pages = @wiki.pages.with_updated_on.reorder("#{WikiPage.table_name}.title").includes(:wiki => :project).includes(:parent).all + end +end diff --git a/app/controllers/wikis_controller.rb b/app/controllers/wikis_controller.rb index d600efe78..a8205710f 100644 --- a/app/controllers/wikis_controller.rb +++ b/app/controllers/wikis_controller.rb @@ -1,36 +1,36 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class WikisController < ApplicationController - menu_item :settings - before_filter :find_project, :authorize - - # Create or update a project's wiki - def edit - @wiki = @project.wiki || Wiki.new(:project => @project) - @wiki.safe_attributes = params[:wiki] - @wiki.save if request.post? - end - - # Delete a project's wiki - def destroy - if request.post? && params[:confirm] && @project.wiki - @project.wiki.destroy - redirect_to settings_project_url(@project, :tab => 'wiki') - end - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class WikisController < ApplicationController + menu_item :settings + before_filter :find_project, :authorize + + # Create or update a project's wiki + def edit + @wiki = @project.wiki || Wiki.new(:project => @project) + @wiki.safe_attributes = params[:wiki] + @wiki.save if request.post? + end + + # Delete a project's wiki + def destroy + if request.post? && params[:confirm] && @project.wiki + @project.wiki.destroy + redirect_to settings_project_url(@project, :tab => 'wiki') + end + end +end diff --git a/app/controllers/words_controller.rb b/app/controllers/words_controller.rb index 7752b530b..e6ba74874 100644 --- a/app/controllers/words_controller.rb +++ b/app/controllers/words_controller.rb @@ -1,283 +1,283 @@ -# encoding: utf-8 -#####leave message fq -class WordsController < ApplicationController - - before_filter :find_user, :only => [:new, :create, :destroy, :more, :back] - def create - if params[:new_form][:user_message].size>0 - unless params[:user_id].nil? - if params[:reference_content] - message = params[:new_form][:user_message] + "\n" + params[:reference_content] - else - message = params[:new_form][:user_message] - end - refer_user_id = params[:new_form][:reference_user_id].to_i - - @user.add_jour(User.current, message, refer_user_id) - unless refer_user_id == 0 || refer_user_id == User.current.id - User.find(refer_user_id).add_jour(User.current, message, refer_user_id) - end - @user.count_new_jour - # if a_message.size > 5 - # @message = a_message[-5, 5] - # else - # @message = a_message - # end - # @message_count = a_message.count - end - end - @jours = @user.journals_for_messages.where('m_parent_id IS NULL').reverse - @limit = 10 - @feedback_count = @jours.count - @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] - @offset ||= @feedback_pages.offset - @jour = @jours[@offset, @limit] - - respond_to do |format| - # format.html { redirect_to_referer_or {render :text => 'Watcher added.', :layout => true}} - format.js - #format.api { render_api_ok } - end - end - - - def create_reply - # 这里是创建回复所使用的方法,此方法只针对回复,每一个新的留言并不在此方法管理范围内。 - # 由于多个地方用到了留言,而之前的表设计也有jour_type/jour_id这类信息 - # 所以在方法 add_reply_adapter 中判断所有调用此方法的来源页面, - # 为了保证兼容以往所有的代码,保证以往的方法可以调用,在返回页面中都做了各式各样的判断。 - # 页面保证 render new_respond/journal_reply - # 修改 add_reply_adapter 中可以确保留言创建成功 - # 删除留言功能要调用destroy,也记得在destroy.js中修改 - - # deny api. api useless - parent_id = params[:reference_id] - author_id = User.current.id - reply_user_id = params[:reference_user_id] - reply_id = params[:reference_message_id] # 暂时不实现 - content = params[:user_notes] - options = {:user_id => author_id, - :status => true, - :m_parent_id => parent_id, - :m_reply_id => reply_id, - :reply_id => reply_user_id, - :notes => content, - :is_readed => false} - @jfm = add_reply_adapter options - - respond_to do |format| - # format.html { - # if @jfm.errors.empty? - # flash.now.notice = l(:label_feedback_success) - # else - # flash.now.errors = l(:label_feedback_fail) - # end - # render 'test/index' - # } - format.js{ - @save_succ = true if @jfm.errors.empty? - } - end - end - - def destroy - @journal_destroyed = JournalsForMessage.delete_message(params[:object_id]) - - respond_to do |format| - format.js - #format.api { render_api_ok } - end - end - - def destroyJournal - @journalP=JournalsForMessage.find(params[:object_id]) - @journalP.destroy - - @page = params[:page] - @page = @page.to_i - @project = Project.find params[:project_id] - # Find the page of the requested reply - @jours = @project.journals_for_messages.where('m_parent_id IS NULL').order('created_on DESC') - @limit = 10 - - offset = @jours.count(:conditions => ["#{JournalsForMessage.table_name}.id > ?", params[:r].to_i]) - page = 1 + offset / @limit - if params[:r] && @page.nil? - @page = page - end - - if @page < 0 - @page = 1 - end - if @page > page - @page = page - end - - @feedback_count = @jours.count - @feedback_pages = Paginator.new @feedback_count, @limit, @page - @offset ||= @feedback_pages.offset - @jour = @jours[@offset, @limit] - @state = false - @base_courses_tag = @project.project_type - - respond_to do |format| - format.js - end - end - - def new - @jour = JournalsForMessage.find(params[:journal_id]) if params[:journal_id] - if @jour - user = @jour.user - text = @jour.notes - else - user = @user - text = [] - end - # Replaces pre blocks with [...] - text = text.to_s.strip.gsub(%r{((.|\s)*?)}m, '[...]') - @content = "> #{ll(User.current.language, :text_user_wrote, user)}\n> " - @content << text.gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n" - - # @content << text.gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n" - # @content = "> #{ll(Setting.default_language, :text_user_wrote, user)}\n> " - - @id = user.id - rescue ActiveRecord::RecordNotFound - render_404 - end - - def more - @jours = @user.journals_for_messages.reverse - @limit = 10 - @feedback_count = @jours.count - @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] - @offset ||= @feedback_pages.offset - @jour = @jours[@offset, @limit] - @state = true - - respond_to do |format| - format.html { redirect_to :back } - format.js - #format.api { render_api_ok } - end - end - - def back - @jours = @user.journals_for_messages.reverse - @limit = 10 - @feedback_count = @jours.count - @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] - @offset ||= @feedback_pages.offset - @jour = @jours[@offset, @limit] - @state = false - - respond_to do |format| - format.html { redirect_to :back } - format.js - #format.api { render_api_ok } - end - end - - def add_project_respond - user = User.current - message = params[:new_form][:project_message] - Project.add_jour(user, message) - - redirect_to project_feedback_url('trustie') - # redirect_to signin_path - end - - def leave_project_message - user = User.current - message = params[:new_form][:project_message] - feedback = Project.add_new_jour(user, message, params[:id]) - if(feedback.errors.empty?) - redirect_to project_feedback_url(params[:id]), notice: l(:label_feedback_success) - else - flash[:error] = feedback.errors.full_messages[0] - redirect_to project_feedback_url(params[:id]) - end - - end - - # add by nwb - def leave_course_message - user = User.current - message = params[:new_form][:course_message] - feedback = Course.add_new_jour(user, message, params[:id]) - if(feedback.errors.empty?) - redirect_to course_feedback_url(params[:id]), notice: l(:label_feedback_success) - else - flash[:error] = feedback.errors.full_messages[0] - redirect_to course_feedback_url(params[:id]) - end - - end - - def add_brief_introdution - user = User.current - message = params[:new_form][:user_introduction] - UserExtensions.introduction(user, message) - redirect_to user_url(user.id) - end - - private - - def find_user - if params[:user_id] - @user = User.find(params[:user_id]) - end - rescue - render_404 - end - - def obj_distinguish_url_origin - #modify by nwb - #添加对课程留言的支持 - referer = request.headers["Referer"] - obj_id = referer.match(%r(/([0-9]{1,})(/|\?|$)))[1] - if referer.match(/project/) - obj = Project.find_by_id(obj_id) - elsif referer.match(/course/) - obj = Course.find_by_id(obj_id) - elsif referer.match(/user/) - obj = User.find_by_id(obj_id) - elsif ( referer.match(/bids/) || referer.match(/calls/) ) - obj = Bid.find_by_id(obj_id) - elsif ( referer.match(/contests/) || referer.match(/contests/) ) #new added - obj = Contest.find_by_id(obj_id) - elsif ( referer.match(/softapplications/) || referer.match(/softapplications/) ) #new added - obj = Softapplication.find_by_id(obj_id) - elsif ( referer.match(/homework_attach/) || referer.match(/homework_attach/) ) #new added - obj = HomeworkAttach.find_by_id(obj_id) - else - raise "create reply obj unknow type.#{referer}" - end - obj - end - - def add_reply_adapter options - #modify by nwb - #添加对课程留言的支持 - obj = obj_distinguish_url_origin - if obj.kind_of? User - obj.add_jour(nil, nil, nil, options) - elsif obj.kind_of? Project - Project.add_new_jour(nil, nil, obj.id, options) - elsif obj.kind_of? Course - Course.add_new_jour(nil, nil, obj.id, options) - elsif obj.kind_of? Bid - obj.add_jour(nil, nil, nil, options) - elsif obj.kind_of? Contest - obj.add_jour(nil, nil, obj.id, options) #new added - elsif obj.kind_of? Softapplication - obj.add_jour(nil, nil, obj.id, options) #new added - elsif obj.kind_of? HomeworkAttach - obj.add_jour(nil, nil, obj.id, options) #new added - else - raise "create reply obj unknow type.#{obj.class}" - end - end - #######end of message -end +# encoding: utf-8 +#####leave message fq +class WordsController < ApplicationController + + before_filter :find_user, :only => [:new, :create, :destroy, :more, :back] + def create + if params[:new_form][:user_message].size>0 + unless params[:user_id].nil? + if params[:reference_content] + message = params[:new_form][:user_message] + "\n" + params[:reference_content] + else + message = params[:new_form][:user_message] + end + refer_user_id = params[:new_form][:reference_user_id].to_i + + @user.add_jour(User.current, message, refer_user_id) + unless refer_user_id == 0 || refer_user_id == User.current.id + User.find(refer_user_id).add_jour(User.current, message, refer_user_id) + end + @user.count_new_jour + # if a_message.size > 5 + # @message = a_message[-5, 5] + # else + # @message = a_message + # end + # @message_count = a_message.count + end + end + @jours = @user.journals_for_messages.where('m_parent_id IS NULL').reverse + @limit = 10 + @feedback_count = @jours.count + @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] + @offset ||= @feedback_pages.offset + @jour = @jours[@offset, @limit] + + respond_to do |format| + # format.html { redirect_to_referer_or {render :text => 'Watcher added.', :layout => true}} + format.js + #format.api { render_api_ok } + end + end + + + def create_reply + # 这里是创建回复所使用的方法,此方法只针对回复,每一个新的留言并不在此方法管理范围内。 + # 由于多个地方用到了留言,而之前的表设计也有jour_type/jour_id这类信息 + # 所以在方法 add_reply_adapter 中判断所有调用此方法的来源页面, + # 为了保证兼容以往所有的代码,保证以往的方法可以调用,在返回页面中都做了各式各样的判断。 + # 页面保证 render new_respond/journal_reply + # 修改 add_reply_adapter 中可以确保留言创建成功 + # 删除留言功能要调用destroy,也记得在destroy.js中修改 + + # deny api. api useless + parent_id = params[:reference_id] + author_id = User.current.id + reply_user_id = params[:reference_user_id] + reply_id = params[:reference_message_id] # 暂时不实现 + content = params[:user_notes] + options = {:user_id => author_id, + :status => true, + :m_parent_id => parent_id, + :m_reply_id => reply_id, + :reply_id => reply_user_id, + :notes => content, + :is_readed => false} + @jfm = add_reply_adapter options + + respond_to do |format| + # format.html { + # if @jfm.errors.empty? + # flash.now.notice = l(:label_feedback_success) + # else + # flash.now.errors = l(:label_feedback_fail) + # end + # render 'test/index' + # } + format.js{ + @save_succ = true if @jfm.errors.empty? + } + end + end + + def destroy + @journal_destroyed = JournalsForMessage.delete_message(params[:object_id]) + + respond_to do |format| + format.js + #format.api { render_api_ok } + end + end + + def destroyJournal + @journalP=JournalsForMessage.find(params[:object_id]) + @journalP.destroy + + @page = params[:page] + @page = @page.to_i + @project = Project.find params[:project_id] + # Find the page of the requested reply + @jours = @project.journals_for_messages.where('m_parent_id IS NULL').order('created_on DESC') + @limit = 10 + + offset = @jours.count(:conditions => ["#{JournalsForMessage.table_name}.id > ?", params[:r].to_i]) + page = 1 + offset / @limit + if params[:r] && @page.nil? + @page = page + end + + if @page < 0 + @page = 1 + end + if @page > page + @page = page + end + + @feedback_count = @jours.count + @feedback_pages = Paginator.new @feedback_count, @limit, @page + @offset ||= @feedback_pages.offset + @jour = @jours[@offset, @limit] + @state = false + @base_courses_tag = @project.project_type + + respond_to do |format| + format.js + end + end + + def new + @jour = JournalsForMessage.find(params[:journal_id]) if params[:journal_id] + if @jour + user = @jour.user + text = @jour.notes + else + user = @user + text = [] + end + # Replaces pre blocks with [...] + text = text.to_s.strip.gsub(%r{((.|\s)*?)}m, '[...]') + @content = "> #{ll(User.current.language, :text_user_wrote, user)}\n> " + @content << text.gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n" + + # @content << text.gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n" + # @content = "> #{ll(Setting.default_language, :text_user_wrote, user)}\n> " + + @id = user.id + rescue ActiveRecord::RecordNotFound + render_404 + end + + def more + @jours = @user.journals_for_messages.reverse + @limit = 10 + @feedback_count = @jours.count + @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] + @offset ||= @feedback_pages.offset + @jour = @jours[@offset, @limit] + @state = true + + respond_to do |format| + format.html { redirect_to :back } + format.js + #format.api { render_api_ok } + end + end + + def back + @jours = @user.journals_for_messages.reverse + @limit = 10 + @feedback_count = @jours.count + @feedback_pages = Paginator.new @feedback_count, @limit, params['page'] + @offset ||= @feedback_pages.offset + @jour = @jours[@offset, @limit] + @state = false + + respond_to do |format| + format.html { redirect_to :back } + format.js + #format.api { render_api_ok } + end + end + + def add_project_respond + user = User.current + message = params[:new_form][:project_message] + Project.add_jour(user, message) + + redirect_to project_feedback_url('trustie') + # redirect_to signin_path + end + + def leave_project_message + user = User.current + message = params[:new_form][:project_message] + feedback = Project.add_new_jour(user, message, params[:id]) + if(feedback.errors.empty?) + redirect_to project_feedback_url(params[:id]), notice: l(:label_feedback_success) + else + flash[:error] = feedback.errors.full_messages[0] + redirect_to project_feedback_url(params[:id]) + end + + end + + # add by nwb + def leave_course_message + user = User.current + message = params[:new_form][:course_message] + feedback = Course.add_new_jour(user, message, params[:id]) + if(feedback.errors.empty?) + redirect_to course_feedback_url(params[:id]), notice: l(:label_feedback_success) + else + flash[:error] = feedback.errors.full_messages[0] + redirect_to course_feedback_url(params[:id]) + end + + end + + def add_brief_introdution + user = User.current + message = params[:new_form][:user_introduction] + UserExtensions.introduction(user, message) + redirect_to user_url(user.id) + end + + private + + def find_user + if params[:user_id] + @user = User.find(params[:user_id]) + end + rescue + render_404 + end + + def obj_distinguish_url_origin + #modify by nwb + #添加对课程留言的支持 + referer = request.headers["Referer"] + obj_id = referer.match(%r(/([0-9]{1,})(/|\?|$)))[1] + if referer.match(/project/) + obj = Project.find_by_id(obj_id) + elsif referer.match(/course/) + obj = Course.find_by_id(obj_id) + elsif referer.match(/user/) + obj = User.find_by_id(obj_id) + elsif ( referer.match(/bids/) || referer.match(/calls/) ) + obj = Bid.find_by_id(obj_id) + elsif ( referer.match(/contests/) || referer.match(/contests/) ) #new added + obj = Contest.find_by_id(obj_id) + elsif ( referer.match(/softapplications/) || referer.match(/softapplications/) ) #new added + obj = Softapplication.find_by_id(obj_id) + elsif ( referer.match(/homework_attach/) || referer.match(/homework_attach/) ) #new added + obj = HomeworkAttach.find_by_id(obj_id) + else + raise "create reply obj unknow type.#{referer}" + end + obj + end + + def add_reply_adapter options + #modify by nwb + #添加对课程留言的支持 + obj = obj_distinguish_url_origin + if obj.kind_of? User + obj.add_jour(nil, nil, nil, options) + elsif obj.kind_of? Project + Project.add_new_jour(nil, nil, obj.id, options) + elsif obj.kind_of? Course + Course.add_new_jour(nil, nil, obj.id, options) + elsif obj.kind_of? Bid + obj.add_jour(nil, nil, nil, options) + elsif obj.kind_of? Contest + obj.add_jour(nil, nil, obj.id, options) #new added + elsif obj.kind_of? Softapplication + obj.add_jour(nil, nil, obj.id, options) #new added + elsif obj.kind_of? HomeworkAttach + obj.add_jour(nil, nil, obj.id, options) #new added + else + raise "create reply obj unknow type.#{obj.class}" + end + end + #######end of message +end diff --git a/app/controllers/workflows_controller.rb b/app/controllers/workflows_controller.rb index 44b76cb87..b7ee0c963 100644 --- a/app/controllers/workflows_controller.rb +++ b/app/controllers/workflows_controller.rb @@ -1,128 +1,128 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class WorkflowsController < ApplicationController - layout 'admin' - - before_filter :require_admin, :find_roles, :find_trackers - - def index - @workflow_counts = WorkflowTransition.count_by_tracker_and_role - end - - def edit - @role = Role.find_by_id(params[:role_id]) if params[:role_id] - @tracker = Tracker.find_by_id(params[:tracker_id]) if params[:tracker_id] - - if request.post? - WorkflowTransition.destroy_all( ["role_id=? and tracker_id=?", @role.id, @tracker.id]) - (params[:issue_status] || []).each { |status_id, transitions| - transitions.each { |new_status_id, options| - author = options.is_a?(Array) && options.include?('author') && !options.include?('always') - assignee = options.is_a?(Array) && options.include?('assignee') && !options.include?('always') - WorkflowTransition.create(:role_id => @role.id, :tracker_id => @tracker.id, :old_status_id => status_id, :new_status_id => new_status_id, :author => author, :assignee => assignee) - } - } - if @role.save - redirect_to workflows_edit_url(:role_id => @role, :tracker_id => @tracker, :used_statuses_only => params[:used_statuses_only]) - return - end - end - - @used_statuses_only = (params[:used_statuses_only] == '0' ? false : true) - if @tracker && @used_statuses_only && @tracker.issue_statuses.any? - @statuses = @tracker.issue_statuses - end - @statuses ||= IssueStatus.sorted.all - - if @tracker && @role && @statuses.any? - workflows = WorkflowTransition.where(:role_id => @role.id, :tracker_id => @tracker.id).all - @workflows = {} - @workflows['always'] = workflows.select {|w| !w.author && !w.assignee} - @workflows['author'] = workflows.select {|w| w.author} - @workflows['assignee'] = workflows.select {|w| w.assignee} - end - end - - def permissions - @role = Role.find_by_id(params[:role_id]) if params[:role_id] - @tracker = Tracker.find_by_id(params[:tracker_id]) if params[:tracker_id] - - if request.post? && @role && @tracker - WorkflowPermission.replace_permissions(@tracker, @role, params[:permissions] || {}) - redirect_to workflows_permissions_url(:role_id => @role, :tracker_id => @tracker, :used_statuses_only => params[:used_statuses_only]) - return - end - - @used_statuses_only = (params[:used_statuses_only] == '0' ? false : true) - if @tracker && @used_statuses_only && @tracker.issue_statuses.any? - @statuses = @tracker.issue_statuses - end - @statuses ||= IssueStatus.sorted.all - - if @role && @tracker - @fields = (Tracker::CORE_FIELDS_ALL - @tracker.disabled_core_fields).map {|field| [field, l("field_"+field.sub(/_id$/, ''))]} - @custom_fields = @tracker.custom_fields - - @permissions = WorkflowPermission.where(:tracker_id => @tracker.id, :role_id => @role.id).all.inject({}) do |h, w| - h[w.old_status_id] ||= {} - h[w.old_status_id][w.field_name] = w.rule - h - end - @statuses.each {|status| @permissions[status.id] ||= {}} - end - end - - def copy - - if params[:source_tracker_id].blank? || params[:source_tracker_id] == 'any' - @source_tracker = nil - else - @source_tracker = Tracker.find_by_id(params[:source_tracker_id].to_i) - end - if params[:source_role_id].blank? || params[:source_role_id] == 'any' - @source_role = nil - else - @source_role = Role.find_by_id(params[:source_role_id].to_i) - end - - @target_trackers = params[:target_tracker_ids].blank? ? nil : Tracker.find_all_by_id(params[:target_tracker_ids]) - @target_roles = params[:target_role_ids].blank? ? nil : Role.find_all_by_id(params[:target_role_ids]) - - if request.post? - if params[:source_tracker_id].blank? || params[:source_role_id].blank? || (@source_tracker.nil? && @source_role.nil?) - flash.now[:error] = l(:error_workflow_copy_source) - elsif @target_trackers.blank? || @target_roles.blank? - flash.now[:error] = l(:error_workflow_copy_target) - else - WorkflowRule.copy(@source_tracker, @source_role, @target_trackers, @target_roles) - flash[:notice] = l(:notice_successful_update) - redirect_to workflows_copy_url(:source_tracker_id => @source_tracker, :source_role_id => @source_role) - end - end - end - - private - - def find_roles - @roles = Role.sorted.all - end - - def find_trackers - @trackers = Tracker.sorted.all - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class WorkflowsController < ApplicationController + layout 'admin' + + before_filter :require_admin, :find_roles, :find_trackers + + def index + @workflow_counts = WorkflowTransition.count_by_tracker_and_role + end + + def edit + @role = Role.find_by_id(params[:role_id]) if params[:role_id] + @tracker = Tracker.find_by_id(params[:tracker_id]) if params[:tracker_id] + + if request.post? + WorkflowTransition.destroy_all( ["role_id=? and tracker_id=?", @role.id, @tracker.id]) + (params[:issue_status] || []).each { |status_id, transitions| + transitions.each { |new_status_id, options| + author = options.is_a?(Array) && options.include?('author') && !options.include?('always') + assignee = options.is_a?(Array) && options.include?('assignee') && !options.include?('always') + WorkflowTransition.create(:role_id => @role.id, :tracker_id => @tracker.id, :old_status_id => status_id, :new_status_id => new_status_id, :author => author, :assignee => assignee) + } + } + if @role.save + redirect_to workflows_edit_url(:role_id => @role, :tracker_id => @tracker, :used_statuses_only => params[:used_statuses_only]) + return + end + end + + @used_statuses_only = (params[:used_statuses_only] == '0' ? false : true) + if @tracker && @used_statuses_only && @tracker.issue_statuses.any? + @statuses = @tracker.issue_statuses + end + @statuses ||= IssueStatus.sorted.all + + if @tracker && @role && @statuses.any? + workflows = WorkflowTransition.where(:role_id => @role.id, :tracker_id => @tracker.id).all + @workflows = {} + @workflows['always'] = workflows.select {|w| !w.author && !w.assignee} + @workflows['author'] = workflows.select {|w| w.author} + @workflows['assignee'] = workflows.select {|w| w.assignee} + end + end + + def permissions + @role = Role.find_by_id(params[:role_id]) if params[:role_id] + @tracker = Tracker.find_by_id(params[:tracker_id]) if params[:tracker_id] + + if request.post? && @role && @tracker + WorkflowPermission.replace_permissions(@tracker, @role, params[:permissions] || {}) + redirect_to workflows_permissions_url(:role_id => @role, :tracker_id => @tracker, :used_statuses_only => params[:used_statuses_only]) + return + end + + @used_statuses_only = (params[:used_statuses_only] == '0' ? false : true) + if @tracker && @used_statuses_only && @tracker.issue_statuses.any? + @statuses = @tracker.issue_statuses + end + @statuses ||= IssueStatus.sorted.all + + if @role && @tracker + @fields = (Tracker::CORE_FIELDS_ALL - @tracker.disabled_core_fields).map {|field| [field, l("field_"+field.sub(/_id$/, ''))]} + @custom_fields = @tracker.custom_fields + + @permissions = WorkflowPermission.where(:tracker_id => @tracker.id, :role_id => @role.id).all.inject({}) do |h, w| + h[w.old_status_id] ||= {} + h[w.old_status_id][w.field_name] = w.rule + h + end + @statuses.each {|status| @permissions[status.id] ||= {}} + end + end + + def copy + + if params[:source_tracker_id].blank? || params[:source_tracker_id] == 'any' + @source_tracker = nil + else + @source_tracker = Tracker.find_by_id(params[:source_tracker_id].to_i) + end + if params[:source_role_id].blank? || params[:source_role_id] == 'any' + @source_role = nil + else + @source_role = Role.find_by_id(params[:source_role_id].to_i) + end + + @target_trackers = params[:target_tracker_ids].blank? ? nil : Tracker.find_all_by_id(params[:target_tracker_ids]) + @target_roles = params[:target_role_ids].blank? ? nil : Role.find_all_by_id(params[:target_role_ids]) + + if request.post? + if params[:source_tracker_id].blank? || params[:source_role_id].blank? || (@source_tracker.nil? && @source_role.nil?) + flash.now[:error] = l(:error_workflow_copy_source) + elsif @target_trackers.blank? || @target_roles.blank? + flash.now[:error] = l(:error_workflow_copy_target) + else + WorkflowRule.copy(@source_tracker, @source_role, @target_trackers, @target_roles) + flash[:notice] = l(:notice_successful_update) + redirect_to workflows_copy_url(:source_tracker_id => @source_tracker, :source_role_id => @source_role) + end + end + end + + private + + def find_roles + @roles = Role.sorted.all + end + + def find_trackers + @trackers = Tracker.sorted.all + end +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index bcba064ec..2ba16c742 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,1898 +1,1898 @@ -# encoding: utf-8 -# -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -require 'forwardable' -require 'cgi' - -module ApplicationHelper - include Redmine::WikiFormatting::Macros::Definitions - include Redmine::I18n - include GravatarHelper::PublicMethods - include Redmine::Pagination::Helper - include AvatarHelper - ## added by william - include PraiseTreadHelper - include CoursesHelper - - extend Forwardable - def_delegators :wiki_helper, :wikitoolbar_for, :heads_for_wiki_formatter - - # Added by young - # Define the course menu's link class - # 不是数组的转化成数组,然后判断当前menu_item是否在给定的列表 - # REVIEW: 目测menu的机制,貌似不是很需要转换,再说 - def link_class(label) - labels = label.is_a?(Array) ? label : ([] << label) - #a = current_menu_item - labels.include?(current_menu_item) ? 'selected' : '' - - end - #Ended by young - # Return true if user is authorized for controller/action, otherwise false - def authorize_for(controller, action) - User.current.allowed_to?({:controller => controller, :action => action}, @project) - end - - # add by nwb - def authorize_for_course(controller, action) - User.current.allowed_to?({:controller => controller, :action => action}, @course) - end - - def authorize_for_contest(controller, action) - User.current.allowed_to?({:controller => controller, :action => action}, @contest) - end - - # Display a link if user is authorized - # - # @param [String] name Anchor text (passed to link_to) - # @param [Hash] options Hash params. This will checked by authorize_for to see if the user is authorized - # @param [optional, Hash] html_options Options passed to link_to - # @param [optional, Hash] parameters_for_method_reference Extra parameters for link_to - def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference) - link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller] || params[:controller], options[:action]) - end - - def link_to_if_authorized_course(name, options = {}, html_options = nil, *parameters_for_method_reference) - link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for_course(options[:controller] || params[:controller], options[:action]) - end - - def link_to_if_authorized_contest(name, options = {}, html_options = nil, *parameters_for_method_reference) - link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for_contest(options[:controller] || params[:controller], options[:action]) - end - # Displays a link to user's account page if active - def link_to_user(user, canShowRealName = false, options={}) - if user.is_a?(User) - if canShowRealName - name = h(user.realname(options[:format])) - else - name = h(user.name(options[:format])) - end - - #if user.active? || (User.current.admin? && user.logged?) - # link_to name, {:controller=> 'users', :action => 'show', id: user.id, host: Setting.user_domain}, :class => user.css_classes - #else - # name - #end - link_to name, {:controller=> 'users', :action => 'show', id: user.id, host: Setting.user_domain}, :class => user.css_classes - else - h(user.to_s) - end - end - - # Displays a link to +issue+ with its subject. - # Examples: - # - # link_to_issue(issue) # => Defect #6: This is the subject - # link_to_issue(issue, :truncate => 6) # => Defect #6: This i... - # link_to_issue(issue, :subject => false) # => Defect #6 - # link_to_issue(issue, :project => true) # => Foo - Defect #6 - # link_to_issue(issue, :subject => false, :tracker => false) # => #6 - # - def link_to_issue(issue, options={}) - title = nil - subject = nil - text = options[:tracker] == false ? "##{issue.id}" : "#{issue.tracker} ##{issue.id}" - if options[:subject] == false - title = truncate(issue.subject, :length => 60) - else - subject = issue.subject - if options[:truncate] - subject = truncate(subject, :length => options[:truncate]) - end - end - s = link_to text, issue_path(issue), :class => issue.css_classes, :title => title - s << h(": #{subject}") if subject - s = h("#{issue.project} - ") + s if options[:project] - s - end - - # Generates a link to an attachment. - # Options: - # * :text - Link text (default to attachment filename) - # * :download - Force download (default: false) - def link_to_short_attachment(attachment, options={}) - text = h(truncate(options.delete(:text) || attachment.filename, length: 23, omission: '...')) - route_method = options.delete(:download) ? :download_named_attachment_path : :named_attachment_path - html_options = options.slice!(:only_path) - url = send(route_method, attachment, attachment.filename, options) - link_to text, url, html_options - end - - # Generates a link to an attachment. - # Options: - # * :text - Link text (default to attachment filename) - # * :download - Force download (default: false) - def link_to_attachment(attachment, options={}) - text = options.delete(:text) || attachment.filename - route_method = options.delete(:download) ? :download_named_attachment_path : :named_attachment_path - html_options = options.slice!(:only_path) - url = send(route_method, attachment, attachment.filename, options) - link_to text, url, html_options - end - - def link_to_attachment_img(attachment, options={}) - text = options.delete(:text) || attachment.filename - route_method = options.delete(:download) ? :download_named_attachment_path : :named_attachment_path - html_options = options.slice!(:only_path) - url = send(route_method, attachment, attachment.filename, options) - image_tag url, html_options - end - - # Generates a link to a SCM revision - # Options: - # * :text - Link text (default to the formatted revision) - def link_to_revision(revision, repository, options={}) - if repository.is_a?(Project) - repository = repository.repository - end - text = options.delete(:text) || format_revision(revision) - rev = revision.respond_to?(:identifier) ? revision.identifier : revision - link_to( - h(text), - {:controller => 'repositories', :action => 'revision', :id => repository.project, :repository_id => repository.identifier_param, :rev => rev}, - :title => l(:label_revision_id, format_revision(revision)) - ) - end - - # Generates a link to a message - def link_to_message(message, options={}, html_options = nil) - link_to( - truncate(message.subject, :length => 60), - board_message_path(message.board_id, message.parent_id || message.id, { - :r => (message.parent_id && message.id), - :anchor => (message.parent_id ? "message-#{message.id}" : nil) - }.merge(options)), - html_options - ) - end - - # Generates a link to a project if active - # Examples: - # - # link_to_project(project) # => link to the specified project overview - # link_to_project(project, {:only_path => false}, :class => "project") # => 3rd arg adds html options - # link_to_project(project, {}, :class => "project") # => html options with default url (project overview) - # - def link_to_project(project, options={}, html_options = nil) - if project.archived? - h(project.name) - elsif options.key?(:action) - ActiveSupport::Deprecation.warn "#link_to_project with :action option is deprecated and will be removed in Redmine 3.0." - url = {:controller => 'projects', :action => 'show', :id => project}.merge(options) - link_to project.name, url, html_options - else - link_to project.name, project_path(project, options), html_options - end - end - - def link_to_course(course, options={}, html_options = nil) - if course.archived? - h(course.name) - elsif options.key?(:action) - ActiveSupport::Deprecation.warn "#link_to_course with :action option is deprecated and will be removed in Redmine 3.0." - url = {:controller => 'courses', :action => 'show', :id => project}.merge(options) - link_to course.name, url, html_options - else - link_to course.name, course_path(course, options), html_options - end - end - - # Generates a link to a project settings if active - def link_to_project_settings(project, options={}, html_options=nil) - if project.active? - link_to project.name, settings_project_path(project, options), html_options - elsif project.archived? - h(project.name) - else - link_to project.name, project_path(project, options), html_options - end - end - - def wiki_page_path(page, options={}) - url_for({:controller => 'wiki', :action => 'show', :project_id => page.project, :id => page.title}.merge(options)) - end - - def thumbnail_tag(attachment) - link_to image_tag(thumbnail_path(attachment)), - named_attachment_path(attachment, attachment.filename), - :title => attachment.filename - end - - # 图片缩略图链接 - def thumbnail_small_tag(attachment) - imagesize = attachment.thumbnail(:size => "200*200") - imagepath = named_attachment_path(attachment, attachment.filename) - if imagesize - link_to image_tag(imagesize), - imagepath, - :title => attachment.filename - else - link_to image_tag(imagepath , height: '200', width: '250'), - imagepath, - :title => attachment.filename - end - end - - def toggle_link(name, id, options={}) - onclick = "$('##{id}').toggle(); " - onclick << (options[:focus] ? "$('##{options[:focus]}').focus(); " : "this.blur(); ") - onclick << "return false;" - link_to(name, "#", :onclick => onclick) - end - - def image_to_function(name, function, html_options = {}) - html_options.symbolize_keys! - tag(:input, html_options.merge({ - :type => "image", :src => image_path(name), - :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};" - })) - end - - def format_activity_title(text) - h(truncate_single_line(text, :length => 100)) - end - - def format_activity_day(date) - date == User.current.today ? l(:label_today).titleize : format_date(date) - end - - def format_activity_description(text) - h(truncate(text.to_s, :length => 120).gsub(%r{[\r\n]*<(pre|code)>.*$}m, '...')).gsub(/[\r\n]+/, "
").html_safe - #h(truncate(text.to_s, :length => 120).gsub(/<\/?.*?>/,"")).html_safe - end - - def format_version_name(version) - if version.project == @project - h(version) - else - h("#{version.project} - #{version}") - end - end - - def due_date_distance_in_words(date) - if date - l((date < Date.today ? :label_roadmap_overdue : :label_roadmap_due_in), distance_of_date_in_words(Date.today, date)) - end - end - - # Renders a tree of projects as a nested set of unordered lists - # The given collection may be a subset of the whole project tree - # (eg. some intermediate nodes are private and can not be seen) - #Modified by nie. - def render_project_nested_lists(projects) - s = '' - if projects.any? - ancestors = [] - original_project = @project - #modified by nie - projects.each do |project| - # set the project environment to please macros. - @project = project - if (ancestors.empty? || project.is_descendant_of?(ancestors.last)) -# s << "\n" - s << "
\n" * ancestors.size) - @project = original_project - end - s.html_safe - end - - def render_course_nested_lists(courses) - s = '' - if courses.any? - ancestors = [] - original_course = @course - #modified by nie - courses.each do |course| - # set the project environment to please macros. - @course = course - if (ancestors.empty? )#|| course.is_descendant_of?(ancestors.last)) - s << "\n" - else - ancestors.pop - s << "" - while (ancestors.any? && !project.is_descendant_of?(ancestors.last)) - ancestors.pop - s << "
\n" - end - end - classes = (ancestors.empty? ? 'root' : 'child') - s << " " - if project.try(:project_type) == Project::ProjectType_project - s << h(block_given? ? yield(project) : project.name) - else - end - - if project.try(:project_type) == Project::ProjectType_project - unless User.current.member_of?(@project) - s << "" - s << watcher_link(@project, User.current)#, ['whiteButton']) - s << "" - end - s << (render :partial => 'projects/project', :locals => {:project => project}).to_s - else - s << (render :partial => 'projects/course', :locals => {:project => project}).to_s - end - s << "\n" - ancestors << project - end - s << ("\n" - else - ancestors.pop - s << "" - while (ancestors.any? )#&& !course.is_descendant_of?(ancestors.last)) - ancestors.pop - s << "
\n" - end - end - classes = (ancestors.empty? ? 'root' : 'child') - s << "\n" * ancestors.size) - @course = original_course - end - s.html_safe - end - - - #added by young - def render_project_nested_lists_new(projects) - s = '' - if projects.any? - ancestors = [] - original_project = @project - projects.sort_by(&:lft).each do |project| - # set the project environment to please macros. - @project = project - if (ancestors.empty? || project.is_descendant_of?(ancestors.last)) -# s << " " - - s << (render :partial => 'courses/course', :locals => {:course => course}).to_s - s << "\n" - ancestors << course - end - s << ("\n" - s << "
\n" * ancestors.size) - @project = original_project - end - s.html_safe - end - #end - def render_page_hierarchy(pages, node=nil, options={}) - content = '' - if pages[node] - content << "\n" - else - ancestors.pop - s << "" - while (ancestors.any? && !project.is_descendant_of?(ancestors.last)) - ancestors.pop - s << "
\n" - end - end - classes = (ancestors.empty? ? 'root' : 'child') - s << h(block_given? ? yield(project) : project.name) - ancestors << project - end - s << ("\n" - pages[node].each do |page| - content << "
\n" - end - content.html_safe - end - - # Renders flash messages - def render_flash_messages - s = '' - flash.each do |k,v| - s << content_tag('div', v.html_safe, :class => "flash #{k}", :id => "flash_#{k}") - end - s.html_safe - end - - # Renders tabs and their content - def render_tabs(tabs) - if tabs.any? - render :partial => 'common/tabs', :locals => {:tabs => tabs} - else - content_tag 'p', l(:label_no_data), :class => "nodata" - end - end - - # Renders the project quick-jump box - def render_project_jump_box - return unless User.current.logged? - projects = User.current.memberships.collect(&:project).compact.select(&:active?).uniq - if projects.any? - options = - ("" + - '').html_safe - - options << project_tree_options_for_select(projects, :selected => @project) do |p| - { :value => project_path(:id => p, :jump => current_menu_item) } - end - - select_tag('project_quick_jump_box', options, :onchange => 'if (this.value != \'\') { window.location = this.value; }') - end - end - - def project_tree_options_for_select(projects, options = {}) - s = '' - project_tree(projects) do |project, level| - name_prefix = (level > 0 ? ' ' * 2 * level + '» ' : '').html_safe - tag_options = {:value => project.id} - if project == options[:selected] || (options[:selected].respond_to?(:include?) && options[:selected].include?(project)) - tag_options[:selected] = 'selected' - else - tag_options[:selected] = nil - end - tag_options.merge!(yield(project)) if block_given? - s << content_tag('option', name_prefix + h(project), tag_options) - end - s.html_safe - end - - # Yields the given block for each project with its level in the tree - # - # Wrapper for Project#project_tree - def project_tree(projects, &block) - Project.project_tree(projects, &block) - end - - def principals_check_box_tags(name, principals) - s = '' - principals.each do |principal| - s << "\n" - end - s.html_safe - end - - #扩展的checkbox生成 - def principals_check_box_tags_ex(name, principals) - s = '' - principals.each do |principal| - s << "\n" - end - s.html_safe - end - - #扩展的checkbox生成 - def principals_radio_box_tags_ex(name, principals) - s = '' - principals.each do |principal| - s << "\n" - end - s.html_safe - end - - - # Returns a string for users/groups option tags - def principals_options_for_select(collection, selected=nil) - s = '' - if collection.include?(User.current) - s << content_tag('option', "<< #{l(:label_me)} >>", :value => User.current.id) - end - groups = '' - collection.sort.each do |element| - selected_attribute = ' selected="selected"' if option_value_selected?(element, selected) - (element.is_a?(Group) ? groups : s) << %() - end - unless groups.empty? - s << %() - end - s.html_safe - end - - # Options for the new membership projects combo-box - def options_for_membership_project_select(principal, projects) - options = content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---") - options << project_tree_options_for_select(projects) do |p| - {:disabled => principal.projects.to_a.include?(p)} - end - options - end - - # Truncates and returns the string as a single line - def truncate_single_line(string, *args) - truncate(string.to_s, *args).gsub(%r{[\r\n]+}m, ' ') - end - - # Truncates at line break after 250 characters or options[:length] - def truncate_lines(string, options={}) - length = options[:length] || 250 - if string.to_s =~ /\A(.{#{length}}.*?)$/m - "#{$1}..." - else - string - end - end - - def anchor(text) - text.to_s.gsub(' ', '_') - end - - def html_hours(text) - text.gsub(%r{(\d+)\.(\d+)}, '\1.\2').html_safe - end - - def authoring(created, author, options={}) - l(options[:label] || :label_added_time_by, :author => link_to_user(author), :age => time_tag(created)).html_safe - end - - def added_time(created) - l(:label_added_time, :age => time_tag(created)).html_safe - end - - def user_url_and_time(user_name, user_url, created) - unless user_name.nil? || user_name == '' - l(:label_added_time_by, :author => link_to(user_name, user_url), :age => time_tag(created)).html_safe - else - l(:label_added_time, :age => time_tag(created)).html_safe - end - end - - #huang - def betweentime(enddate) - ss=(DateTime.parse("#{enddate.to_date}")-DateTime.parse("#{DateTime.now.to_date}")).to_i - return ss - end - - def time_tag(time) - text = distance_of_time_in_words(Time.now, time) - if @project - link_to(text, {:controller => 'activities', :action => 'index', :id => @project, :from => User.current.time_to_date(time)}, :title => format_time(time)) - else - content_tag('acronym', text, :title => format_time(time)) - end - end - - def syntax_highlight_lines(name, content) - lines = [] - syntax_highlight(name, content).each_line { |line| lines << line } - lines - end - - def syntax_highlight(name, content) - Redmine::SyntaxHighlighting.highlight_by_filename(content, name) - end - - def to_path_param(path) - str = path.to_s.split(%r{[/\\]}).select{|p| !p.blank?}.join("/") - str.blank? ? nil : str - end - - def reorder_links(name, url, method = :post) - link_to(image_tag('2uparrow.png', :alt => l(:label_sort_highest)), - url.merge({"#{name}[move_to]" => 'highest'}), - :method => method, :title => l(:label_sort_highest)) + - link_to(image_tag('1uparrow.png', :alt => l(:label_sort_higher)), - url.merge({"#{name}[move_to]" => 'higher'}), - :method => method, :title => l(:label_sort_higher)) + - link_to(image_tag('1downarrow.png', :alt => l(:label_sort_lower)), - url.merge({"#{name}[move_to]" => 'lower'}), - :method => method, :title => l(:label_sort_lower)) + - link_to(image_tag('2downarrow.png', :alt => l(:label_sort_lowest)), - url.merge({"#{name}[move_to]" => 'lowest'}), - :method => method, :title => l(:label_sort_lowest)) - end - - def breadcrumb(*args) - elements = args.flatten - elements.any? ? content_tag('p', (args.join(" \xc2\xbb ") + " \xc2\xbb ").html_safe, :class => 'breadcrumb') : nil - end - - def other_formats_links(&block) - concat('- " - content << link_to(h(page.pretty_title), {:controller => 'wiki', :action => 'show', :project_id => page.project, :id => page.title, :version => nil}, - :title => (options[:timestamp] && page.updated_on ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil)) - content << "\n" + render_page_hierarchy(pages, page.id, options) if pages[page.id] - content << "
\n" - end - content << "'.html_safe + l(:label_export_to)) - yield Redmine::Views::OtherFormatsBuilder.new(self) - concat('
'.html_safe) - end - - def page_header_title - if @project.nil? || @project.new_record? - h(Setting.app_title) - else - b = [] - ancestors = (@project.root? ? [] : @project.ancestors.visible.all) - if ancestors.any? - root = ancestors.shift - b << link_to_project(root, {:jump => current_menu_item}, :class => 'root') - if ancestors.size > 2 - b << "\xe2\x80\xa6" - ancestors = ancestors[-2, 2] - end - b += ancestors.collect {|p| link_to_project(p, {:jump => current_menu_item}, :class => 'ancestor') } - end - b << h(@project) - b.join(" \xc2\xbb ").html_safe - end - end - - def html_title(*args) - #點擊項目版本庫 多觸發一次 字符串為"/" - #暫時解決方法 直接判斷 - if(args == ["/"]) - args = [] - end - first_page = FirstPage.find_by_page_type('project') - if args.empty? - title = @html_title || [] - title << @project.name if @project - if first_page.nil? || first_page.web_title.nil? - title << Setting.app_title unless Setting.app_title == title.last - else - title << first_page.web_title unless first_page.web_title == title.last - end - title.select {|t| !t.blank? }.join(' - ') - else - @html_title ||= [] - @html_title += args - end - end - - # Returns the theme, controller name, and action as css classes for the - # HTML body. - def body_css_classes - css = [] - if theme = Redmine::Themes.theme(Setting.ui_theme) - css << 'theme-' + theme.name - end - - css << 'controller-' + controller_name - css << 'action-' + action_name - css.join(' ') - end - - def accesskey(s) - @used_accesskeys ||= [] - key = Redmine::AccessKeys.key_for(s) - return nil if @used_accesskeys.include?(key) - @used_accesskeys << key - key - end - - # Formats text according to system settings. - # 2 ways to call this method: - # * with a String: textilizable(text, options) - # * with an object and one of its attribute: textilizable(issue, :description, options) - def textilizable(*args) - options = args.last.is_a?(Hash) ? args.pop : {} - case args.size - when 1 - obj = options[:object] - text = args.shift - when 2 - obj = args.shift - attr = args.shift - text = obj.send(attr).to_s - else - raise ArgumentError, 'invalid arguments to textilizable' - end - return '' if text.blank? - project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil) - only_path = options.delete(:only_path) == false ? false : true - - text = text.dup - macros = catch_macros(text) - text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr) - - @parsed_headings = [] - @heading_anchors = {} - @current_section = 0 if options[:edit_section_links] - - parse_sections(text, project, obj, attr, only_path, options) - text = parse_non_pre_blocks(text, obj, macros) do |text| - [:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links].each do |method_name| - send method_name, text, project, obj, attr, only_path, options - end - end - parse_headings(text, project, obj, attr, only_path, options) - - if @parsed_headings.any? - replace_toc(text, @parsed_headings) - end - - text.html_safe - end - - # - #格式化字符串,不转义html代码 - def textAreailizable(*args) - options = args.last.is_a?(Hash) ? args.pop : {} - case args.size - when 1 - obj = options[:object] - text = args.shift - when 2 - obj = args.shift - attr = args.shift - text = obj.send(attr).to_s - else - raise ArgumentError, 'invalid arguments to textilizable' - end - return '' if text.blank? - project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil) - only_path = options.delete(:only_path) == false ? false : true - - text = text.dup - macros = catch_macros(text) - #text = Redmine::WikiFormatting.to_html("CKEditor", text, :object => obj, :attribute => attr) - - @parsed_headings = [] - @heading_anchors = {} - @current_section = 0 if options[:edit_section_links] - - parse_sections(text, project, obj, attr, only_path, options) - text = parse_non_pre_blocks(text, obj, macros) do |text| - [:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links].each do |method_name| - send method_name, text, project, obj, attr, only_path, options - end - end - parse_headings(text, project, obj, attr, only_path, options) - - if @parsed_headings.any? - replace_toc(text, @parsed_headings) - end - - text.html_safe - end - - def parse_non_pre_blocks(text, obj, macros) - s = StringScanner.new(text) - tags = [] - parsed = '' - while !s.eos? - s.scan(/(.*?)(<(\/)?(pre|code)(.*?)>|\z)/im) - text, full_tag, closing, tag = s[1], s[2], s[3], s[4] - if tags.empty? - yield text - inject_macros(text, obj, macros) if macros.any? - else - inject_macros(text, obj, macros, false) if macros.any? - end - parsed << text - if tag - if closing - if tags.last == tag.downcase - tags.pop - end - else - tags << tag.downcase - end - parsed << full_tag - end - end - # Close any non closing tags - while tag = tags.pop - parsed << "#{tag}>" - end - parsed - end - - def parse_inline_attachments(text, project, obj, attr, only_path, options) - # when using an image link, try to use an attachment, if possible - attachments = options[:attachments] || [] - attachments += obj.attachments if obj.respond_to?(:attachments) - if attachments.present? - text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpe|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m| - filename, ext, alt, alttext = $1.downcase, $2, $3, $4 - # search for the picture in attachments - if found = Attachment.latest_attach(attachments, filename) - image_url = download_named_attachment_path(found, found.filename, :only_path => only_path) - desc = found.description.to_s.gsub('"', '') - if !desc.blank? && alttext.blank? - alt = " title=\"#{desc}\" alt=\"#{desc}\"" - end - "src=\"#{image_url}\"#{alt}" - else - m - end - end - end - end - - # Wiki links - # - # Examples: - # [[mypage]] - # [[mypage|mytext]] - # wiki links can refer other project wikis, using project name or identifier: - # [[project:]] -> wiki starting page - # [[project:|mytext]] - # [[project:mypage]] - # [[project:mypage|mytext]] - def parse_wiki_links(text, project, obj, attr, only_path, options) - text.gsub!(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |m| - link_project = project - esc, all, page, title = $1, $2, $3, $5 - if esc.nil? - if page =~ /^([^\:]+)\:(.*)$/ - identifier, page = $1, $2 - link_project = Project.find_by_identifier(identifier) || Project.find_by_name(identifier) - title ||= identifier if page.blank? - end - - if link_project && link_project.wiki - # extract anchor - anchor = nil - if page =~ /^(.+?)\#(.+)$/ - page, anchor = $1, $2 - end - anchor = sanitize_anchor_name(anchor) if anchor.present? - # check if page exists - wiki_page = link_project.wiki.find_page(page) - url = if anchor.present? && wiki_page.present? && (obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version)) && obj.page == wiki_page - "##{anchor}" - else - case options[:wiki_links] - when :local; "#{page.present? ? Wiki.titleize(page) : ''}.html" + (anchor.present? ? "##{anchor}" : '') - when :anchor; "##{page.present? ? Wiki.titleize(page) : title}" + (anchor.present? ? "_#{anchor}" : '') # used for single-file wiki export - else - wiki_page_id = page.present? ? Wiki.titleize(page) : nil - parent = wiki_page.nil? && obj.is_a?(WikiContent) && obj.page && project == link_project ? obj.page.title : nil - url_for(:only_path => only_path, :controller => 'wiki', :action => 'show', :project_id => link_project, - :id => wiki_page_id, :version => nil, :anchor => anchor, :parent => parent) - end - end - link_to(title.present? ? title.html_safe : h(page), url, :class => ('wiki-page' + (wiki_page ? '' : ' new'))) - else - # project or wiki doesn't exist - all - end - else - all - end - end - end - - def select_option_helper option - tmp = Hash.new - tmp={"" => ""} - if option.nil? - else - option.each do |project| - tmp[project.name] = project.id - end - end - tmp - end - # Redmine links - # - # Examples: - # Issues: - # #52 -> Link to issue #52 - # Changesets: - # r52 -> Link to revision 52 - # commit:a85130f -> Link to scmid starting with a85130f - # Documents: - # document#17 -> Link to document with id 17 - # document:Greetings -> Link to the document with title "Greetings" - # document:"Some document" -> Link to the document with title "Some document" - # Versions: - # version#3 -> Link to version with id 3 - # version:1.0.0 -> Link to version named "1.0.0" - # version:"1.0 beta 2" -> Link to version named "1.0 beta 2" - # Attachments: - # attachment:file.zip -> Link to the attachment of the current object named file.zip - # Source files: - # source:some/file -> Link to the file located at /some/file in the project's repository - # source:some/file@52 -> Link to the file's revision 52 - # source:some/file#L120 -> Link to line 120 of the file - # source:some/file@52#L120 -> Link to line 120 of the file's revision 52 - # export:some/file -> Force the download of the file - # Forum messages: - # message#1218 -> Link to message with id 1218 - # - # Links can refer other objects from other projects, using project identifier: - # identifier:r52 - # identifier:document:"Some document" - # identifier:version:1.0.0 - # identifier:source:some/file - def parse_redmine_links(text, default_project, obj, attr, only_path, options) - text.gsub!(%r{([\s\(,\-\[\>]|^)(!)?(([a-z0-9\-_]+):)?(attachment|document|version|forum|news|message|project|commit|source|export)?(((#)|((([a-z0-9\-_]+)\|)?(r)))((\d+)((#note)?-(\d+))?)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]][^A-Za-z0-9_/])|,|\s|\]|<|$)}) do |m| - leading, esc, project_prefix, project_identifier, prefix, repo_prefix, repo_identifier, sep, identifier, comment_suffix, comment_id = $1, $2, $3, $4, $5, $10, $11, $8 || $12 || $18, $14 || $19, $15, $17 - link = nil - project = default_project - if project_identifier - project = Project.visible.find_by_identifier(project_identifier) - end - if esc.nil? - if prefix.nil? && sep == 'r' - if project - repository = nil - if repo_identifier - repository = project.repositories.detect {|repo| repo.identifier == repo_identifier} - else - repository = project.repository - end - # project.changesets.visible raises an SQL error because of a double join on repositories - if repository && (changeset = Changeset.visible.find_by_repository_id_and_revision(repository.id, identifier)) - link = link_to(h("#{project_prefix}#{repo_prefix}r#{identifier}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :repository_id => repository.identifier_param, :rev => changeset.revision}, - :class => 'changeset', - :title => truncate_single_line(changeset.comments, :length => 100)) - end - end - elsif sep == '#' - oid = identifier.to_i - case prefix - when nil - if oid.to_s == identifier && issue = Issue.visible.find_by_id(oid, :include => :status) - anchor = comment_id ? "note-#{comment_id}" : nil - link = link_to("##{oid}", {:only_path => only_path, :controller => 'issues', :action => 'show', :id => oid, :anchor => anchor}, - :class => issue.css_classes, - :title => "#{truncate(issue.subject, :length => 100)} (#{issue.status.name})") - end - when 'document' - if document = Document.visible.find_by_id(oid) - link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document}, - :class => 'document' - end - when 'version' - if version = Version.visible.find_by_id(oid) - link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version}, - :class => 'version' - end - when 'message' - if message = Message.visible.find_by_id(oid, :include => :parent) - link = link_to_message(message, {:only_path => only_path}, :class => 'message') - end - when 'forum' - if board = Board.visible.find_by_id(oid) - link = link_to h(board.name), {:only_path => only_path, :controller => 'boards', :action => 'show', :id => board, :project_id => board.project}, - :class => 'board' - end - when 'news' - if news = News.visible.find_by_id(oid) - link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news}, - :class => 'news' - end - when 'project' - if p = Project.visible.find_by_id(oid) - link = link_to_project(p, {:only_path => only_path}, :class => 'project') - end - end - elsif sep == ':' - # removes the double quotes if any - name = identifier.gsub(%r{^"(.*)"$}, "\\1") - case prefix - when 'document' - if project && document = project.documents.visible.find_by_title(name) - link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document}, - :class => 'document' - end - when 'version' - if project && version = project.versions.visible.find_by_name(name) - link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version}, - :class => 'version' - end - when 'forum' - if project && board = project.boards.visible.find_by_name(name) - link = link_to h(board.name), {:only_path => only_path, :controller => 'boards', :action => 'show', :id => board, :project_id => board.project}, - :class => 'board' - end - when 'news' - if project && news = project.news.visible.find_by_title(name) - link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news}, - :class => 'news' - end - when 'commit', 'source', 'export' - if project - repository = nil - if name =~ %r{^(([a-z0-9\-_]+)\|)(.+)$} - repo_prefix, repo_identifier, name = $1, $2, $3 - repository = project.repositories.detect {|repo| repo.identifier == repo_identifier} - else - repository = project.repository - end - if prefix == 'commit' - if repository && (changeset = Changeset.visible.where("repository_id = ? AND scmid LIKE ?", repository.id, "#{name}%").first) - link = link_to h("#{project_prefix}#{repo_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :repository_id => repository.identifier_param, :rev => changeset.identifier}, - :class => 'changeset', - :title => truncate_single_line(changeset.comments, :length => 100) - end - else - if repository && User.current.allowed_to?(:browse_repository, project) - name =~ %r{^[/\\]*(.*?)(@([^/\\@]+?))?(#(L\d+))?$} - path, rev, anchor = $1, $3, $5 - link = link_to h("#{project_prefix}#{prefix}:#{repo_prefix}#{name}"), {:controller => 'repositories', :action => (prefix == 'export' ? 'raw' : 'entry'), :id => project, :repository_id => repository.identifier_param, - :path => to_path_param(path), - :rev => rev, - :anchor => anchor}, - :class => (prefix == 'export' ? 'source download' : 'source') - end - end - repo_prefix = nil - end - when 'attachment' - attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil) - if attachments && attachment = Attachment.latest_attach(attachments, name) - link = link_to_attachment(attachment, :only_path => only_path, :download => true, :class => 'attachment') - end - when 'project' - if p = Project.visible.where("identifier = :s OR LOWER(name) = :s", :s => name.downcase).first - link = link_to_project(p, {:only_path => only_path}, :class => 'project') - end - end - end - end - (leading + (link || "#{project_prefix}#{prefix}#{repo_prefix}#{sep}#{identifier}#{comment_suffix}")) - end - end - - HEADING_RE = /(]+)?>(.+?)<\/h(\d)>)/i unless const_defined?(:HEADING_RE) - - def parse_sections(text, project, obj, attr, only_path, options) - return unless options[:edit_section_links] - text.gsub!(HEADING_RE) do - heading = $1 - @current_section += 1 - if @current_section > 1 - content_tag('div', - link_to(image_tag('edit.png'), options[:edit_section_links].merge(:section => @current_section)), - :class => 'contextual', - :title => l(:button_edit_section)) + heading.html_safe - else - heading - end - end - end - - # Headings and TOC - # Adds ids and links to headings unless options[:headings] is set to false - def parse_headings(text, project, obj, attr, only_path, options) - return if options[:headings] == false - - text.gsub!(HEADING_RE) do - level, attrs, content = $2.to_i, $3, $4 - item = strip_tags(content).strip - anchor = sanitize_anchor_name(item) - # used for single-file wiki export - anchor = "#{obj.page.title}_#{anchor}" if options[:wiki_links] == :anchor && (obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version)) - @heading_anchors[anchor] ||= 0 - idx = (@heading_anchors[anchor] += 1) - if idx > 1 - anchor = "#{anchor}-#{idx}" - end - @parsed_headings << [level, anchor, item] - "\n #{content}¶ " - end - end - - MACROS_RE = /( - (!)? # escaping - ( - \{\{ # opening tag - ([\w]+) # macro name - (\(([^\n\r]*?)\))? # optional arguments - ([\n\r].*?[\n\r])? # optional block of text - \}\} # closing tag - ) - )/mx unless const_defined?(:MACROS_RE) - - MACRO_SUB_RE = /( - \{\{ - macro\((\d+)\) - \}\} - )/x unless const_defined?(:MACRO_SUB_RE) - - # Extracts macros from text - def catch_macros(text) - macros = {} - text.gsub!(MACROS_RE) do - all, macro = $1, $4.downcase - if macro_exists?(macro) || all =~ MACRO_SUB_RE - index = macros.size - macros[index] = all - "{{macro(#{index})}}" - else - all - end - end - macros - end - - # Executes and replaces macros in text - def inject_macros(text, obj, macros, execute=true) - text.gsub!(MACRO_SUB_RE) do - all, index = $1, $2.to_i - orig = macros.delete(index) - if execute && orig && orig =~ MACROS_RE - esc, all, macro, args, block = $2, $3, $4.downcase, $6.to_s, $7.try(:strip) - if esc.nil? - h(exec_macro(macro, obj, args, block) || all) - else - h(all) - end - elsif orig - h(orig) - else - h(all) - end - end - end - - TOC_RE = /\{\{([<>]?)toc\}\}<\/p>/i unless const_defined?(:TOC_RE) - - # Renders the TOC with given headings - def replace_toc(text, headings) - text.gsub!(TOC_RE) do - # Keep only the 4 first levels - headings = headings.select{|level, anchor, item| level <= 4} - if headings.empty? - '' - else - div_class = 'toc' - div_class << ' right' if $1 == '>' - div_class << ' left' if $1 == '<' - out = "
' * (current - root) - out << '' - end - end - end - - # Same as Rails' simple_format helper without using paragraphs - def simple_format_without_paragraph(text) - text.to_s. - gsub(/\r\n?/, "\n"). # \r\n and \r -> \n - gsub(/\n\n+/, "
- " - root = headings.map(&:first).min - current = root - started = false - headings.each do |level, anchor, item| - if level > current - out << '
\n" * (current - level) + "
- ' * (level - current) - elsif level < current - out << "
- " - elsif started - out << '
- ' - end - out << "#{item}" - current = level - started = true - end - out << '
"). # 2+ newline -> 2 br - gsub(/([^\n]\n)(?=[^\n])/, '\1
'). # 1 newline -> br - html_safe - end - - def lang_options_for_select(blank=true) - { 'Chinese简体中文 '=> 'zh', :English => :en} - end - - def label_tag_for(name, option_tags = nil, options = {}) - label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "") - content_tag("label", label_text) - end - - def labelled_form_for(*args, &proc) - args << {} unless args.last.is_a?(Hash) - options = args.last - if args.first.is_a?(Symbol) - options.merge!(:as => args.shift) - end - options.merge!({:builder => Redmine::Views::LabelledFormBuilder}) - form_for(*args, &proc) - end - - def labelled_fields_for(*args, &proc) - args << {} unless args.last.is_a?(Hash) - options = args.last - options.merge!({:builder => Redmine::Views::LabelledFormBuilder}) - fields_for(*args, &proc) - end - - def labelled_remote_form_for(*args, &proc) - ActiveSupport::Deprecation.warn "ApplicationHelper#labelled_remote_form_for is deprecated and will be removed in Redmine 2.2." - args << {} unless args.last.is_a?(Hash) - options = args.last - options.merge!({:builder => Redmine::Views::LabelledFormBuilder, :remote => true}) - form_for(*args, &proc) - end - - def error_messages_for(*objects) - html = "" - # modified by fq - if objects.first.is_a?(Array) - objects = objects.first - end - # end - if objects != nil - objects = objects.map {|o| o.is_a?(String) ? instance_variable_get("@#{o}") : o}.compact - errors = objects.map {|o| o.errors.full_messages}.flatten - if errors.any? - html << "\n" - end - end - html.html_safe - end - - def delete_link(url, options={}) - options = { - :method => :delete, - :data => {:confirm => l(:text_are_you_sure)}, - :class => 'icon icon-del' - }.merge(options) - - link_to l(:button_delete), url, options - end - - def preview_link(url, form, target='preview', options={}) - content_tag 'a', l(:label_preview), { - :href => "#", - :onclick => %|submitPreview("#{escape_javascript url_for(url)}", "#{escape_javascript form}", "#{escape_javascript target}"); return false;|, - :accesskey => accesskey(:preview) - }.merge(options) - end - - def link_to_function(name, function, html_options={}) - content_tag(:a, name, {:href => '#', :onclick => "#{function}; return false;"}.merge(html_options)) - end - - # Helper to render JSON in views - def raw_json(arg) - arg.to_json.to_s.gsub('/', '\/').html_safe - end - - def back_url - url = params[:back_url] - if url.nil? && referer = request.env['HTTP_REFERER'] - url = CGI.unescape(referer.to_s) - end - url - end - - def back_url_hidden_field_tag - url = back_url - hidden_field_tag('back_url', url, :id => nil) unless url.blank? - end - - def check_all_links(form_name) - link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") + - " | ".html_safe + - link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)") - end - - def progress_bar(pcts, options={}) - pcts = [pcts, pcts] unless pcts.is_a?(Array) - pcts = pcts.collect(&:round) - pcts[1] = pcts[1] - pcts[0] - pcts << (100 - pcts[1] - pcts[0]) - width = options[:width] || '100px;' - legend = options[:legend] || '' - content_tag('table', - content_tag('tr', - (pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0]}%;", :class => 'closed') : ''.html_safe) + - (pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1]}%;", :class => 'done') : ''.html_safe) + - (pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2]}%;", :class => 'todo') : ''.html_safe) - ), :class => 'progress', :style => "width: #{width};").html_safe + - content_tag('p', legend, :class => 'percent').html_safe - end - - def checked_image(checked=true) - if checked - image_tag 'toggle_check.png' - end - end - - def context_menu(url) - unless @context_menu_included - content_for :header_tags do - javascript_include_tag('context_menu') + - stylesheet_link_tag('context_menu') - end - if l(:direction) == 'rtl' - content_for :header_tags do - stylesheet_link_tag('context_menu_rtl') - end - end - @context_menu_included = true - end - javascript_tag "contextMenuInit('#{ url_for(url) }')" - end - - def calendar_for(field_id,start_day=nil) - include_calendar_headers_tags(start_day) - javascript_tag("$(function() { $('##{field_id}').datepicker(datepickerOptions); });") - end - - def include_calendar_headers_tags(start_day=nil) - if start_day.nil? - unless @calendar_headers_tags_included - @calendar_headers_tags_included = true - content_for :header_tags do - start_of_week = Setting.start_of_week - start_of_week = l(:general_first_day_of_week, :default => '1') if start_of_week.blank? - # Redmine uses 1..7 (monday..sunday) in settings and locales - # JQuery uses 0..6 (sunday..saturday), 7 needs to be changed to 0 - start_of_week = start_of_week.to_i % 7 - - tags = javascript_tag( - "var datepickerOptions={dateFormat: 'yy-mm-dd', firstDay: #{start_of_week}, " + - "showOn: 'button', buttonImageOnly: true, buttonImage: '" + - path_to_image('/images/calendar.png') + - "', showButtonPanel: true, showWeek: true, showOtherMonths: true, selectOtherMonths: true};") - jquery_locale = l('jquery.locale', :default => current_language.to_s) - unless jquery_locale == 'en' - tags << javascript_include_tag("i18n/jquery.ui.datepicker-#{jquery_locale}.js") - end - tags - end - end - else - unless @calendar_headers_tags_included - @calendar_headers_tags_included = true - content_for :header_tags do - start_of_week = Setting.start_of_week - start_of_week = l(:general_first_day_of_week, :default => '1') if start_of_week.blank? - # Redmine uses 1..7 (monday..sunday) in settings and locales - # JQuery uses 0..6 (sunday..saturday), 7 needs to be changed to 0 - start_of_week = start_of_week.to_i % 7 - - tags = javascript_tag( - "var datepickerOptions={dateFormat: 'yy-mm-dd',minDate: new Date(), firstDay: #{start_of_week}, " + - "showOn: 'button', buttonImageOnly: true, buttonImage: '" + - path_to_image('/images/calendar.png') + - "', showButtonPanel: true, showWeek: true, showOtherMonths: true, selectOtherMonths: true, onClose: function(dateText, inst) {TimeClose(dateText,inst);}, beforeShow : function(input){TimeBeforeShow(input);} };") - jquery_locale = l('jquery.locale', :default => current_language.to_s) - unless jquery_locale == 'en' - tags << javascript_include_tag("i18n/jquery.ui.datepicker-#{jquery_locale}.js") - end - tags - end - end - end - - end - - # Overrides Rails' stylesheet_link_tag with themes and plugins support. - # Examples: - # stylesheet_link_tag('styles') # => picks styles.css from the current theme or defaults - # stylesheet_link_tag('styles', :plugin => 'foo) # => picks styles.css from plugin's assets - # - def stylesheet_link_tag(*sources) - options = sources.last.is_a?(Hash) ? sources.pop : {} - plugin = options.delete(:plugin) - sources = sources.map do |source| - if plugin - "/plugin_assets/#{plugin}/stylesheets/#{source}" - elsif current_theme && current_theme.stylesheets.include?(source) - current_theme.stylesheet_path(source) - else - source - end - end - super sources, options - end - - # Overrides Rails' image_tag with themes and plugins support. - # Examples: - # image_tag('image.png') # => picks image.png from the current theme or defaults - # image_tag('image.png', :plugin => 'foo) # => picks image.png from plugin's assets - # - def image_tag(source, options={}) - if plugin = options.delete(:plugin) - source = "/plugin_assets/#{plugin}/images/#{source}" - elsif current_theme && current_theme.images.include?(source) - source = current_theme.image_path(source) - end - super source, options - end - - # Overrides Rails' javascript_include_tag with plugins support - # Examples: - # javascript_include_tag('scripts') # => picks scripts.js from defaults - # javascript_include_tag('scripts', :plugin => 'foo) # => picks scripts.js from plugin's assets - # - def javascript_include_tag(*sources) - options = sources.last.is_a?(Hash) ? sources.pop : {} - if plugin = options.delete(:plugin) - sources = sources.map do |source| - if plugin - "/plugin_assets/#{plugin}/javascripts/#{source}" - else - source - end - end - end - super sources, options - end - - def content_for(name, content = nil, &block) - @has_content ||= {} - @has_content[name] = true - super(name, content, &block) - end - - def has_content?(name) - (@has_content && @has_content[name]) || false - end - - def sidebar_content? - has_content?(:sidebar) || view_layouts_base_sidebar_hook_response.present? - end - - def view_layouts_base_sidebar_hook_response - @view_layouts_base_sidebar_hook_response ||= call_hook(:view_layouts_base_sidebar) - end - - def email_delivery_enabled? - !!ActionMailer::Base.perform_deliveries - end - - # Returns the avatar image tag for the given +user+ if avatars are enabled - # +user+ can be a User or a string that will be scanned for an email address (eg. 'joe\n" - errors.each do |error| - ###by xianbo - if(error!=l(:label_repository_path_not_null)) - html << "
- #{h error}
\n" - end - ###xianbo - end - ###by xianbo - unless params[:repository].nil? - if params[:repository][:upassword]=="" - html << "- "+ l(:label_password_not_null) +"
\n" - end - end - ###xianbo - html << "') - def avatar(user, options = { }) - if Setting.gravatar_enabled? - options.merge!({:ssl => (request && request.ssl?), :default => Setting.gravatar_default}) - email = nil - if user.respond_to?(:mail) - email = user.mail - elsif user.to_s =~ %r{<(.+?)>} - email = $1 - end - return gravatar(email.to_s.downcase, options) unless email.blank? rescue nil - #options ={"class" => ["avatar2"],"width" =>["80px"],"height" =>["80px"]} - #return image_tag url_to_avatar(user), options - else - '' - end - end - - def sanitize_anchor_name(anchor) - if ''.respond_to?(:encoding) || RUBY_PLATFORM == 'java' - anchor.gsub(%r{[^\s\-\p{Word}]}, '').gsub(%r{\s+(\-+\s*)?}, '-') - else - # TODO: remove when ruby1.8 is no longer supported - anchor.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-') - end - end - - # Returns the javascript tags that are included in the html layout head - def javascript_heads - tags = javascript_include_tag('jquery-1.8.3-ui-1.9.2-ujs-2.0.3', 'application', 'jquery.colorbox-min') - unless User.current.pref.warn_on_leaving_unsaved == '0' - tags << "\n".html_safe + javascript_tag("$(window).load(function(){ warnLeavingUnsaved('#{escape_javascript l(:text_warn_on_leaving_unsaved)}'); });") - end - tags - end - - def hubspot_head - tags = javascript_include_tag('hubspot/messenger.min', 'hubspot/messenger-theme-future') - tags << stylesheet_link_tag('hubspot/messenger', 'hubspot/messenger-theme-future', 'hubspot/messenger-theme-flat') - end - - def bootstrap_head - tags = stylesheet_link_tag('bootstrap/bootstrap.min', 'bootstrap/bootstrap-theme.min') - tags << javascript_include_tag('bootstrap/affix') - tags << javascript_include_tag('bootstrap/alert') - tags << javascript_include_tag('bootstrap/button') - tags << javascript_include_tag('bootstrap/carousel') - tags << javascript_include_tag('bootstrap/collapse') - tags << javascript_include_tag('bootstrap/dropdown') - tags << javascript_include_tag('bootstrap/modal') - tags << javascript_include_tag('bootstrap/popover') - tags << javascript_include_tag('bootstrap/scrollspy') - tags << javascript_include_tag('bootstrap/tab') - tags << javascript_include_tag('bootstrap/tooltip') - tags << javascript_include_tag('bootstrap/transition') - tags - end - - def favicon - "".html_safe - end - - def robot_exclusion_tag - ''.html_safe - end - - # Returns true if arg is expected in the API response - def include_in_api_response?(arg) - unless @included_in_api_response - param = params[:include] - @included_in_api_response = param.is_a?(Array) ? param.collect(&:to_s) : param.to_s.split(',') - @included_in_api_response.collect!(&:strip) - end - @included_in_api_response.include?(arg.to_s) - end - - # Returns options or nil if nometa param or X-Redmine-Nometa header - # was set in the request - def api_meta(options) - if params[:nometa].present? || request.headers['X-Redmine-Nometa'] - # compatibility mode for activeresource clients that raise - # an error when unserializing an array with attributes - nil - else - options - end - end - - # Add by Tao - def url_to_avatar(source) - source = nil if source.kind_of?(String) - get_avatar(source) - end - # Endof Tao's code - - def date_format_local(time) - date = time.strftime("%Y年%m月%d日") - end - - #当TAG数量过多时,更多链接 - #1代表是user类型 2代表是project类型 3代表是issue类型 4代表需求 9代表课程 - def more_tags id,object_flag - a= 1 - case object_flag - when "1" - s = link_to l(:label_more_tags),:controller => "users", :action => "show", :id => id - when "2" - s = link_to l(:label_more_tags),:controller => "projects", :action => "show", :id => id - when "3" - s = link_to l(:label_more_tags),:controller => "issues", :action => "show", :id => id - when "4" - s = link_to l(:label_more_tags),:controller => "bids", :action => "show", :id => id - when "9" - s = link_to l(:label_more_tags),:controller => "courses", :action => "show", :id => id - end - s - end - - private - - def wiki_helper - helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting) - extend helper - return self - end - - def link_to_content_update(text, url_params = {}, html_options = {}) - link_to(text, url_params, html_options) - end - -#added by nie -# Display watcher picture - def show_more_watchers?(obj) - if User.watched_by(obj.id).count > 6 - return true - else - return false - end - end - - def show_watcher_profile(obj) - count = 0 - html = '' - if User.watched_by(obj.id).count == 0 - html << (content_tag "span", l(:label_no_current_watchers)) - end - for user in User.watched_by(obj.id) - html << (link_to image_tag(url_to_avatar(user), :class => "avatar"), user_path(user), :class => "avatar", :title => "#{user.name}") - count = count + 1 - if count >= 12 - break - end - end - html.html_safe - end - -#display bid project - def show_more_bid_project?(bid) - if bid.projects.where('is_public = 1').count > 12 - return true - else - return false - end - end - - def show_bid_project(bid) - html = '' - if bid.projects.where('is_public = 1').count == 0 - html << (content_tag "p", l(:label_no_bid_project), :class => "font_lighter") - else - bid.projects.where('is_public = 1').take(12).each do |project| - html << (link_to image_tag(url_to_avatar(project), :class => "avatar", :title => project.name), project_path(project), :class => "avatar") - end - end - html.html_safe - end - - def show_bid_fans_picture(obj) - html = '' - if obj.watcher_users.count == 0 - html << (content_tag "span", l(:label_project_no_follow)) - else - obj.watcher_users.take(12).each do |user| - html << (link_to image_tag(url_to_avatar(user), :class => "avatar"), user_path(user), :class => "avatar", :title => user.name) - end - end - html.html_safe - end - -#display contest project - def show_more_contest_project?(contest) - if contest.projects.where('is_public = 1').count > 12 - return true - else - return false - end - end - - def show_more_contest_softapplication?(contest) - if contest.softapplications.where('is_public = 1').count > 12 - return true - else - return false - end - end - - def show_contest_project(bid) - html = '' - if contest.projects.where('is_public = 1').count == 0 - html << (content_tag "p", l(:label_no_bid_project), :class => "font_lighter") - else - contest.projects.where('is_public = 1').take(12).each do |project| - html << (link_to image_tag(url_to_avatar(project), :class => "avatar", :title => project.name), project_path(project), :class => "avatar") - end - end - html.html_safe - end - - def show_contest_project(contest) - html = '' - if contest.projects.where('is_public = 1').count == 0 - html << (content_tag "p", l(:label_no_bid_project), :class => "font_lighter") - else - contest.projects.where('is_public = 1').take(12).each do |project| - html << (link_to image_tag(url_to_avatar(project), :class => "avatar", :title => project.name), project_path(project), :class => "avatar") - end - end - html.html_safe - end - - def show_contest_softapplication(contest) - html = '' - if contest.softapplications.where('is_public = 1').count == 0 - html << (content_tag "p", l(:label_no_contest_softapplication), :class => "font_lighter") - else - contest.softapplications.where('is_public = 1').take(12).each do |softapplication| - html << (link_to image_tag(url_to_avatar(project), :class => "avatar", :title => project.name), project_path(project), :class => "avatar") - end - end - html.html_safe - end - - def show_contest_fans_picture(obj) - html = '' - if obj.watcher_users.count == 0 - html << (content_tag "span", l(:label_project_no_follow)) - else - obj.watcher_users.take(12).each do |user| - html << (link_to image_tag(url_to_avatar(user), :class => "avatar"), user_path(user), :class => "avatar", :title => user.name) - end - end - html.html_safe - end - -#display fans picture - def show_more_fans?(obj) - if obj.watcher_users.count > 12 - return true - else - return false - end - end - - def show_fans_picture(obj) - html = '' - if obj.watcher_users.count == 0 - html << (content_tag "span", l(:label_no_current_fans)) - else - obj.watcher_users.take(12).each do |user| - html << (link_to image_tag(url_to_avatar(user), :class => "avatar"), user_path(user), :class => "avatar", :title => user.name) - end - end - html.html_safe - end - - # added by bai - def show_more_participate?(obj) - if obj.join_in_contests.count > 12 - return true - else - return false - end - end - - def show_participate_picture(obj) - html = '' - count = 0 - if obj.join_in_contests.count == 0 - html << (content_tag "span", l(:label_no_current_participate)) - end - for temp in obj.join_in_contests - html << (link_to image_tag(url_to_avatar(temp.user), :class => "avatar"), user_path(temp.user), :class => "avatar", :title => "#{temp.user.name}") - count = count + 1 - if count >= 12 - break - end - end - html.html_safe - end - -#end - -# add by huang - def show_watcher_list(user) - html = '' - count = 0 - for user in User.watched_by(user.id) - html << (link_to image_tag(url_to_avatar(user), :class => "avatar"), user_path(user), :class => "avatar", :title => "#{user.name}") - count = count + 1 - if count >= 12 - break - end - end - html.html_safe - end -# end - -#added by william - def get_fans_num(user) - user.watcher_users.count - end -#end - - - def hadcommittedhomework(cur,curb) - bid = Bid.find_by_id(curb) - return true if bid.nil? - - case bid.homework_type - when Bid::HomeworkFile - attaches = HomeworkAttach.where(bid_id: curb) - attaches.map(&:user_id).include? cur - when Bid::HomeworkProject - attaches = BidingProject.where(user_id: User.current, bid_id: bid) - attaches.count > 0 # > 0 则有提交记录 - else - true - end - - end - - def render_dynamic_nav - home_link = link_to l(:field_homepage), {:controller => 'welcome', :action => 'index'} - home_link = " " << home_link << " " - # bootstrap_render_dynamic_nav - content_tag :ul, (home_link.html_safe+bootstrap_render_dynamic_nav) - end - - def bootstrap_render_dynamic_nav - - main_course_link = link_to l(:label_course_practice), {:controller => 'welcome', :action => 'index', :host => Setting.course_domain} - main_project_link = link_to l(:label_project_deposit), {:controller => 'welcome', :action => 'index', :host => Setting.project_domain} - main_contest_link = link_to l(:label_contest_innovate), {:controller => 'welcome', :action => 'index', :host => Setting.contest_domain} - - course_all_course_link = link_to l(:label_course_all), {:controller => 'courses', :action => 'index'} - course_teacher_all_link = link_to l(:label_teacher_all), {:controller => 'users', :action => 'index', :role => 'teacher', :host => Setting.course_domain} - courses_link = link_to l(:label_course_practice), {:controller => 'courses', :action => 'index'} - projects_link = link_to l(:label_project_deposit), {:controller => 'projects', :action => 'index', :project_type => 0, :host => Setting.project_domain} - users_link = link_to l(:label_software_user), {:controller => 'users', :action => 'index', :host => Setting.user_domain} - contest_link = link_to l(:label_contest_innovate), {:controller => 'contests', :action => 'index'} - bids_link = link_to l(:label_requirement_enterprise), {:controller => 'bids', :action => 'index'} - forum_link = link_to l(:label_project_module_forums), {:controller => "forums", :action => "index"} - stores_link = link_to l(:label_stores_index), {:controller => 'stores', :action=> 'index'} - - - school_all_school_link = link_to l(:label_school_all), {:controller => 'school', :action => 'index'} - - - #@nav_dispaly_project_label - nav_list = Array.new - nav_list.push(school_all_school_link) if @nav_dispaly_course_all_label && @show_course == 1 - nav_list.push(course_all_course_link) if @nav_dispaly_course_all_label && @show_course == 1 - nav_list.push(course_teacher_all_link) if @nav_dispaly_teacher_all_label && @show_course == 1 - - nav_list.push(main_project_link) if @nav_dispaly_main_project_label - nav_list.push(main_course_link) if @nav_dispaly_main_course_label && @show_course == 1 - nav_list.push(main_contest_link) if @nav_dispaly_main_contest_label && @show_contest == 1 - - nav_list.push(courses_link) if @nav_dispaly_course_label && @show_course == 1 - nav_list.push(projects_link) if @nav_dispaly_project_label - nav_list.push(users_link) if @nav_dispaly_user_label - nav_list.push(contest_link) if @nav_dispaly_contest_label && @show_contest == 1 - nav_list.push(bids_link) if @nav_dispaly_bid_label - nav_list.push(forum_link) if @nav_dispaly_forum_label - nav_list.push(stores_link) if @nav_dispaly_store_all_label - - content_li = '' - nav_list.collect do |nav_item| - content_li << content_tag(:li, nav_item) - end - content_li.html_safe - end - - def current_user - User.current - end - - # def hadcommittedforcontest(curu) - # message = JournalsForMessage.find_by_sql("select * from journals_for_messages where jour_type = 'Softapplication' ") - # message.each do |createmessage| - # if createmessage.user_id == curu - # return true - # end - # end - # end - - def footer_logo(ul_class=nil, li_class=nil) - logos = [] - logos.push(link_to image_tag('/images/footer_logo/nudt.png',:alt=>"nudt"),"http://www.nudt.edu.cn/special.asp?classid=12" ) - logos.push(link_to image_tag('/images/footer_logo/peking_eecs.png', :alt=>"peking_eecs"), "http://eecs.pku.edu.cn" ) - logos.push(link_to image_tag('/images/footer_logo/buaa_scse.png', :alt=>"buaa_scse"), "http://scse.buaa.edu.cn/" ) - logos.push(link_to image_tag('/images/footer_logo/iscas.png', :alt=>"iscas"), "http://www.iscas.ac.cn" ) - logos.push(link_to image_tag('/images/footer_logo/inforbus.png', :alt=>"inforbus"), "http://www.inforbus.com" ) - - logos.collect! { |logo| - content_tag(:li, logo.html_safe, :class => li_class.to_s) - } - - content_tag(:ul, logos.join("").html_safe, :class => ul_class.to_s).html_safe - end - - -end +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'forwardable' +require 'cgi' + +module ApplicationHelper + include Redmine::WikiFormatting::Macros::Definitions + include Redmine::I18n + include GravatarHelper::PublicMethods + include Redmine::Pagination::Helper + include AvatarHelper + ## added by william + include PraiseTreadHelper + include CoursesHelper + + extend Forwardable + def_delegators :wiki_helper, :wikitoolbar_for, :heads_for_wiki_formatter + + # Added by young + # Define the course menu's link class + # 不是数组的转化成数组,然后判断当前menu_item是否在给定的列表 + # REVIEW: 目测menu的机制,貌似不是很需要转换,再说 + def link_class(label) + labels = label.is_a?(Array) ? label : ([] << label) + #a = current_menu_item + labels.include?(current_menu_item) ? 'selected' : '' + + end + #Ended by young + # Return true if user is authorized for controller/action, otherwise false + def authorize_for(controller, action) + User.current.allowed_to?({:controller => controller, :action => action}, @project) + end + + # add by nwb + def authorize_for_course(controller, action) + User.current.allowed_to?({:controller => controller, :action => action}, @course) + end + + def authorize_for_contest(controller, action) + User.current.allowed_to?({:controller => controller, :action => action}, @contest) + end + + # Display a link if user is authorized + # + # @param [String] name Anchor text (passed to link_to) + # @param [Hash] options Hash params. This will checked by authorize_for to see if the user is authorized + # @param [optional, Hash] html_options Options passed to link_to + # @param [optional, Hash] parameters_for_method_reference Extra parameters for link_to + def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference) + link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller] || params[:controller], options[:action]) + end + + def link_to_if_authorized_course(name, options = {}, html_options = nil, *parameters_for_method_reference) + link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for_course(options[:controller] || params[:controller], options[:action]) + end + + def link_to_if_authorized_contest(name, options = {}, html_options = nil, *parameters_for_method_reference) + link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for_contest(options[:controller] || params[:controller], options[:action]) + end + # Displays a link to user's account page if active + def link_to_user(user, canShowRealName = false, options={}) + if user.is_a?(User) + if canShowRealName + name = h(user.realname(options[:format])) + else + name = h(user.name(options[:format])) + end + + #if user.active? || (User.current.admin? && user.logged?) + # link_to name, {:controller=> 'users', :action => 'show', id: user.id, host: Setting.user_domain}, :class => user.css_classes + #else + # name + #end + link_to name, {:controller=> 'users', :action => 'show', id: user.id, host: Setting.user_domain}, :class => user.css_classes + else + h(user.to_s) + end + end + + # Displays a link to +issue+ with its subject. + # Examples: + # + # link_to_issue(issue) # => Defect #6: This is the subject + # link_to_issue(issue, :truncate => 6) # => Defect #6: This i... + # link_to_issue(issue, :subject => false) # => Defect #6 + # link_to_issue(issue, :project => true) # => Foo - Defect #6 + # link_to_issue(issue, :subject => false, :tracker => false) # => #6 + # + def link_to_issue(issue, options={}) + title = nil + subject = nil + text = options[:tracker] == false ? "##{issue.id}" : "#{issue.tracker} ##{issue.id}" + if options[:subject] == false + title = truncate(issue.subject, :length => 60) + else + subject = issue.subject + if options[:truncate] + subject = truncate(subject, :length => options[:truncate]) + end + end + s = link_to text, issue_path(issue), :class => issue.css_classes, :title => title + s << h(": #{subject}") if subject + s = h("#{issue.project} - ") + s if options[:project] + s + end + + # Generates a link to an attachment. + # Options: + # * :text - Link text (default to attachment filename) + # * :download - Force download (default: false) + def link_to_short_attachment(attachment, options={}) + text = h(truncate(options.delete(:text) || attachment.filename, length: 23, omission: '...')) + route_method = options.delete(:download) ? :download_named_attachment_path : :named_attachment_path + html_options = options.slice!(:only_path) + url = send(route_method, attachment, attachment.filename, options) + link_to text, url, html_options + end + + # Generates a link to an attachment. + # Options: + # * :text - Link text (default to attachment filename) + # * :download - Force download (default: false) + def link_to_attachment(attachment, options={}) + text = options.delete(:text) || attachment.filename + route_method = options.delete(:download) ? :download_named_attachment_path : :named_attachment_path + html_options = options.slice!(:only_path) + url = send(route_method, attachment, attachment.filename, options) + link_to text, url, html_options + end + + def link_to_attachment_img(attachment, options={}) + text = options.delete(:text) || attachment.filename + route_method = options.delete(:download) ? :download_named_attachment_path : :named_attachment_path + html_options = options.slice!(:only_path) + url = send(route_method, attachment, attachment.filename, options) + image_tag url, html_options + end + + # Generates a link to a SCM revision + # Options: + # * :text - Link text (default to the formatted revision) + def link_to_revision(revision, repository, options={}) + if repository.is_a?(Project) + repository = repository.repository + end + text = options.delete(:text) || format_revision(revision) + rev = revision.respond_to?(:identifier) ? revision.identifier : revision + link_to( + h(text), + {:controller => 'repositories', :action => 'revision', :id => repository.project, :repository_id => repository.identifier_param, :rev => rev}, + :title => l(:label_revision_id, format_revision(revision)) + ) + end + + # Generates a link to a message + def link_to_message(message, options={}, html_options = nil) + link_to( + truncate(message.subject, :length => 60), + board_message_path(message.board_id, message.parent_id || message.id, { + :r => (message.parent_id && message.id), + :anchor => (message.parent_id ? "message-#{message.id}" : nil) + }.merge(options)), + html_options + ) + end + + # Generates a link to a project if active + # Examples: + # + # link_to_project(project) # => link to the specified project overview + # link_to_project(project, {:only_path => false}, :class => "project") # => 3rd arg adds html options + # link_to_project(project, {}, :class => "project") # => html options with default url (project overview) + # + def link_to_project(project, options={}, html_options = nil) + if project.archived? + h(project.name) + elsif options.key?(:action) + ActiveSupport::Deprecation.warn "#link_to_project with :action option is deprecated and will be removed in Redmine 3.0." + url = {:controller => 'projects', :action => 'show', :id => project}.merge(options) + link_to project.name, url, html_options + else + link_to project.name, project_path(project, options), html_options + end + end + + def link_to_course(course, options={}, html_options = nil) + if course.archived? + h(course.name) + elsif options.key?(:action) + ActiveSupport::Deprecation.warn "#link_to_course with :action option is deprecated and will be removed in Redmine 3.0." + url = {:controller => 'courses', :action => 'show', :id => project}.merge(options) + link_to course.name, url, html_options + else + link_to course.name, course_path(course, options), html_options + end + end + + # Generates a link to a project settings if active + def link_to_project_settings(project, options={}, html_options=nil) + if project.active? + link_to project.name, settings_project_path(project, options), html_options + elsif project.archived? + h(project.name) + else + link_to project.name, project_path(project, options), html_options + end + end + + def wiki_page_path(page, options={}) + url_for({:controller => 'wiki', :action => 'show', :project_id => page.project, :id => page.title}.merge(options)) + end + + def thumbnail_tag(attachment) + link_to image_tag(thumbnail_path(attachment)), + named_attachment_path(attachment, attachment.filename), + :title => attachment.filename + end + + # 图片缩略图链接 + def thumbnail_small_tag(attachment) + imagesize = attachment.thumbnail(:size => "200*200") + imagepath = named_attachment_path(attachment, attachment.filename) + if imagesize + link_to image_tag(imagesize), + imagepath, + :title => attachment.filename + else + link_to image_tag(imagepath , height: '200', width: '250'), + imagepath, + :title => attachment.filename + end + end + + def toggle_link(name, id, options={}) + onclick = "$('##{id}').toggle(); " + onclick << (options[:focus] ? "$('##{options[:focus]}').focus(); " : "this.blur(); ") + onclick << "return false;" + link_to(name, "#", :onclick => onclick) + end + + def image_to_function(name, function, html_options = {}) + html_options.symbolize_keys! + tag(:input, html_options.merge({ + :type => "image", :src => image_path(name), + :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};" + })) + end + + def format_activity_title(text) + h(truncate_single_line(text, :length => 100)) + end + + def format_activity_day(date) + date == User.current.today ? l(:label_today).titleize : format_date(date) + end + + def format_activity_description(text) + h(truncate(text.to_s, :length => 120).gsub(%r{[\r\n]*<(pre|code)>.*$}m, '...')).gsub(/[\r\n]+/, "
").html_safe + #h(truncate(text.to_s, :length => 120).gsub(/<\/?.*?>/,"")).html_safe + end + + def format_version_name(version) + if version.project == @project + h(version) + else + h("#{version.project} - #{version}") + end + end + + def due_date_distance_in_words(date) + if date + l((date < Date.today ? :label_roadmap_overdue : :label_roadmap_due_in), distance_of_date_in_words(Date.today, date)) + end + end + + # Renders a tree of projects as a nested set of unordered lists + # The given collection may be a subset of the whole project tree + # (eg. some intermediate nodes are private and can not be seen) + #Modified by nie. + def render_project_nested_lists(projects) + s = '' + if projects.any? + ancestors = [] + original_project = @project + #modified by nie + projects.each do |project| + # set the project environment to please macros. + @project = project + if (ancestors.empty? || project.is_descendant_of?(ancestors.last)) +# s << "\n" + s << "
\n" * ancestors.size) + @project = original_project + end + s.html_safe + end + + def render_course_nested_lists(courses) + s = '' + if courses.any? + ancestors = [] + original_course = @course + #modified by nie + courses.each do |course| + # set the project environment to please macros. + @course = course + if (ancestors.empty? )#|| course.is_descendant_of?(ancestors.last)) + s << "\n" + else + ancestors.pop + s << "" + while (ancestors.any? && !project.is_descendant_of?(ancestors.last)) + ancestors.pop + s << "
\n" + end + end + classes = (ancestors.empty? ? 'root' : 'child') + s << " " + if project.try(:project_type) == Project::ProjectType_project + s << h(block_given? ? yield(project) : project.name) + else + end + + if project.try(:project_type) == Project::ProjectType_project + unless User.current.member_of?(@project) + s << "" + s << watcher_link(@project, User.current)#, ['whiteButton']) + s << "" + end + s << (render :partial => 'projects/project', :locals => {:project => project}).to_s + else + s << (render :partial => 'projects/course', :locals => {:project => project}).to_s + end + s << "\n" + ancestors << project + end + s << ("\n" + else + ancestors.pop + s << "" + while (ancestors.any? )#&& !course.is_descendant_of?(ancestors.last)) + ancestors.pop + s << "
\n" + end + end + classes = (ancestors.empty? ? 'root' : 'child') + s << "\n" * ancestors.size) + @course = original_course + end + s.html_safe + end + + + #added by young + def render_project_nested_lists_new(projects) + s = '' + if projects.any? + ancestors = [] + original_project = @project + projects.sort_by(&:lft).each do |project| + # set the project environment to please macros. + @project = project + if (ancestors.empty? || project.is_descendant_of?(ancestors.last)) +# s << " " + + s << (render :partial => 'courses/course', :locals => {:course => course}).to_s + s << "\n" + ancestors << course + end + s << ("\n" + s << "
\n" * ancestors.size) + @project = original_project + end + s.html_safe + end + #end + def render_page_hierarchy(pages, node=nil, options={}) + content = '' + if pages[node] + content << "\n" + else + ancestors.pop + s << "" + while (ancestors.any? && !project.is_descendant_of?(ancestors.last)) + ancestors.pop + s << "
\n" + end + end + classes = (ancestors.empty? ? 'root' : 'child') + s << h(block_given? ? yield(project) : project.name) + ancestors << project + end + s << ("\n" + pages[node].each do |page| + content << "
\n" + end + content.html_safe + end + + # Renders flash messages + def render_flash_messages + s = '' + flash.each do |k,v| + s << content_tag('div', v.html_safe, :class => "flash #{k}", :id => "flash_#{k}") + end + s.html_safe + end + + # Renders tabs and their content + def render_tabs(tabs) + if tabs.any? + render :partial => 'common/tabs', :locals => {:tabs => tabs} + else + content_tag 'p', l(:label_no_data), :class => "nodata" + end + end + + # Renders the project quick-jump box + def render_project_jump_box + return unless User.current.logged? + projects = User.current.memberships.collect(&:project).compact.select(&:active?).uniq + if projects.any? + options = + ("" + + '').html_safe + + options << project_tree_options_for_select(projects, :selected => @project) do |p| + { :value => project_path(:id => p, :jump => current_menu_item) } + end + + select_tag('project_quick_jump_box', options, :onchange => 'if (this.value != \'\') { window.location = this.value; }') + end + end + + def project_tree_options_for_select(projects, options = {}) + s = '' + project_tree(projects) do |project, level| + name_prefix = (level > 0 ? ' ' * 2 * level + '» ' : '').html_safe + tag_options = {:value => project.id} + if project == options[:selected] || (options[:selected].respond_to?(:include?) && options[:selected].include?(project)) + tag_options[:selected] = 'selected' + else + tag_options[:selected] = nil + end + tag_options.merge!(yield(project)) if block_given? + s << content_tag('option', name_prefix + h(project), tag_options) + end + s.html_safe + end + + # Yields the given block for each project with its level in the tree + # + # Wrapper for Project#project_tree + def project_tree(projects, &block) + Project.project_tree(projects, &block) + end + + def principals_check_box_tags(name, principals) + s = '' + principals.each do |principal| + s << "\n" + end + s.html_safe + end + + #扩展的checkbox生成 + def principals_check_box_tags_ex(name, principals) + s = '' + principals.each do |principal| + s << "\n" + end + s.html_safe + end + + #扩展的checkbox生成 + def principals_radio_box_tags_ex(name, principals) + s = '' + principals.each do |principal| + s << "\n" + end + s.html_safe + end + + + # Returns a string for users/groups option tags + def principals_options_for_select(collection, selected=nil) + s = '' + if collection.include?(User.current) + s << content_tag('option', "<< #{l(:label_me)} >>", :value => User.current.id) + end + groups = '' + collection.sort.each do |element| + selected_attribute = ' selected="selected"' if option_value_selected?(element, selected) + (element.is_a?(Group) ? groups : s) << %() + end + unless groups.empty? + s << %() + end + s.html_safe + end + + # Options for the new membership projects combo-box + def options_for_membership_project_select(principal, projects) + options = content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---") + options << project_tree_options_for_select(projects) do |p| + {:disabled => principal.projects.to_a.include?(p)} + end + options + end + + # Truncates and returns the string as a single line + def truncate_single_line(string, *args) + truncate(string.to_s, *args).gsub(%r{[\r\n]+}m, ' ') + end + + # Truncates at line break after 250 characters or options[:length] + def truncate_lines(string, options={}) + length = options[:length] || 250 + if string.to_s =~ /\A(.{#{length}}.*?)$/m + "#{$1}..." + else + string + end + end + + def anchor(text) + text.to_s.gsub(' ', '_') + end + + def html_hours(text) + text.gsub(%r{(\d+)\.(\d+)}, '\1.\2').html_safe + end + + def authoring(created, author, options={}) + l(options[:label] || :label_added_time_by, :author => link_to_user(author), :age => time_tag(created)).html_safe + end + + def added_time(created) + l(:label_added_time, :age => time_tag(created)).html_safe + end + + def user_url_and_time(user_name, user_url, created) + unless user_name.nil? || user_name == '' + l(:label_added_time_by, :author => link_to(user_name, user_url), :age => time_tag(created)).html_safe + else + l(:label_added_time, :age => time_tag(created)).html_safe + end + end + + #huang + def betweentime(enddate) + ss=(DateTime.parse("#{enddate.to_date}")-DateTime.parse("#{DateTime.now.to_date}")).to_i + return ss + end + + def time_tag(time) + text = distance_of_time_in_words(Time.now, time) + if @project + link_to(text, {:controller => 'activities', :action => 'index', :id => @project, :from => User.current.time_to_date(time)}, :title => format_time(time)) + else + content_tag('acronym', text, :title => format_time(time)) + end + end + + def syntax_highlight_lines(name, content) + lines = [] + syntax_highlight(name, content).each_line { |line| lines << line } + lines + end + + def syntax_highlight(name, content) + Redmine::SyntaxHighlighting.highlight_by_filename(content, name) + end + + def to_path_param(path) + str = path.to_s.split(%r{[/\\]}).select{|p| !p.blank?}.join("/") + str.blank? ? nil : str + end + + def reorder_links(name, url, method = :post) + link_to(image_tag('2uparrow.png', :alt => l(:label_sort_highest)), + url.merge({"#{name}[move_to]" => 'highest'}), + :method => method, :title => l(:label_sort_highest)) + + link_to(image_tag('1uparrow.png', :alt => l(:label_sort_higher)), + url.merge({"#{name}[move_to]" => 'higher'}), + :method => method, :title => l(:label_sort_higher)) + + link_to(image_tag('1downarrow.png', :alt => l(:label_sort_lower)), + url.merge({"#{name}[move_to]" => 'lower'}), + :method => method, :title => l(:label_sort_lower)) + + link_to(image_tag('2downarrow.png', :alt => l(:label_sort_lowest)), + url.merge({"#{name}[move_to]" => 'lowest'}), + :method => method, :title => l(:label_sort_lowest)) + end + + def breadcrumb(*args) + elements = args.flatten + elements.any? ? content_tag('p', (args.join(" \xc2\xbb ") + " \xc2\xbb ").html_safe, :class => 'breadcrumb') : nil + end + + def other_formats_links(&block) + concat('- " + content << link_to(h(page.pretty_title), {:controller => 'wiki', :action => 'show', :project_id => page.project, :id => page.title, :version => nil}, + :title => (options[:timestamp] && page.updated_on ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil)) + content << "\n" + render_page_hierarchy(pages, page.id, options) if pages[page.id] + content << "
\n" + end + content << "'.html_safe + l(:label_export_to)) + yield Redmine::Views::OtherFormatsBuilder.new(self) + concat('
'.html_safe) + end + + def page_header_title + if @project.nil? || @project.new_record? + h(Setting.app_title) + else + b = [] + ancestors = (@project.root? ? [] : @project.ancestors.visible.all) + if ancestors.any? + root = ancestors.shift + b << link_to_project(root, {:jump => current_menu_item}, :class => 'root') + if ancestors.size > 2 + b << "\xe2\x80\xa6" + ancestors = ancestors[-2, 2] + end + b += ancestors.collect {|p| link_to_project(p, {:jump => current_menu_item}, :class => 'ancestor') } + end + b << h(@project) + b.join(" \xc2\xbb ").html_safe + end + end + + def html_title(*args) + #點擊項目版本庫 多觸發一次 字符串為"/" + #暫時解決方法 直接判斷 + if(args == ["/"]) + args = [] + end + first_page = FirstPage.find_by_page_type('project') + if args.empty? + title = @html_title || [] + title << @project.name if @project + if first_page.nil? || first_page.web_title.nil? + title << Setting.app_title unless Setting.app_title == title.last + else + title << first_page.web_title unless first_page.web_title == title.last + end + title.select {|t| !t.blank? }.join(' - ') + else + @html_title ||= [] + @html_title += args + end + end + + # Returns the theme, controller name, and action as css classes for the + # HTML body. + def body_css_classes + css = [] + if theme = Redmine::Themes.theme(Setting.ui_theme) + css << 'theme-' + theme.name + end + + css << 'controller-' + controller_name + css << 'action-' + action_name + css.join(' ') + end + + def accesskey(s) + @used_accesskeys ||= [] + key = Redmine::AccessKeys.key_for(s) + return nil if @used_accesskeys.include?(key) + @used_accesskeys << key + key + end + + # Formats text according to system settings. + # 2 ways to call this method: + # * with a String: textilizable(text, options) + # * with an object and one of its attribute: textilizable(issue, :description, options) + def textilizable(*args) + options = args.last.is_a?(Hash) ? args.pop : {} + case args.size + when 1 + obj = options[:object] + text = args.shift + when 2 + obj = args.shift + attr = args.shift + text = obj.send(attr).to_s + else + raise ArgumentError, 'invalid arguments to textilizable' + end + return '' if text.blank? + project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil) + only_path = options.delete(:only_path) == false ? false : true + + text = text.dup + macros = catch_macros(text) + text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr) + + @parsed_headings = [] + @heading_anchors = {} + @current_section = 0 if options[:edit_section_links] + + parse_sections(text, project, obj, attr, only_path, options) + text = parse_non_pre_blocks(text, obj, macros) do |text| + [:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links].each do |method_name| + send method_name, text, project, obj, attr, only_path, options + end + end + parse_headings(text, project, obj, attr, only_path, options) + + if @parsed_headings.any? + replace_toc(text, @parsed_headings) + end + + text.html_safe + end + + # + #格式化字符串,不转义html代码 + def textAreailizable(*args) + options = args.last.is_a?(Hash) ? args.pop : {} + case args.size + when 1 + obj = options[:object] + text = args.shift + when 2 + obj = args.shift + attr = args.shift + text = obj.send(attr).to_s + else + raise ArgumentError, 'invalid arguments to textilizable' + end + return '' if text.blank? + project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil) + only_path = options.delete(:only_path) == false ? false : true + + text = text.dup + macros = catch_macros(text) + #text = Redmine::WikiFormatting.to_html("CKEditor", text, :object => obj, :attribute => attr) + + @parsed_headings = [] + @heading_anchors = {} + @current_section = 0 if options[:edit_section_links] + + parse_sections(text, project, obj, attr, only_path, options) + text = parse_non_pre_blocks(text, obj, macros) do |text| + [:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links].each do |method_name| + send method_name, text, project, obj, attr, only_path, options + end + end + parse_headings(text, project, obj, attr, only_path, options) + + if @parsed_headings.any? + replace_toc(text, @parsed_headings) + end + + text.html_safe + end + + def parse_non_pre_blocks(text, obj, macros) + s = StringScanner.new(text) + tags = [] + parsed = '' + while !s.eos? + s.scan(/(.*?)(<(\/)?(pre|code)(.*?)>|\z)/im) + text, full_tag, closing, tag = s[1], s[2], s[3], s[4] + if tags.empty? + yield text + inject_macros(text, obj, macros) if macros.any? + else + inject_macros(text, obj, macros, false) if macros.any? + end + parsed << text + if tag + if closing + if tags.last == tag.downcase + tags.pop + end + else + tags << tag.downcase + end + parsed << full_tag + end + end + # Close any non closing tags + while tag = tags.pop + parsed << "#{tag}>" + end + parsed + end + + def parse_inline_attachments(text, project, obj, attr, only_path, options) + # when using an image link, try to use an attachment, if possible + attachments = options[:attachments] || [] + attachments += obj.attachments if obj.respond_to?(:attachments) + if attachments.present? + text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpe|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m| + filename, ext, alt, alttext = $1.downcase, $2, $3, $4 + # search for the picture in attachments + if found = Attachment.latest_attach(attachments, filename) + image_url = download_named_attachment_path(found, found.filename, :only_path => only_path) + desc = found.description.to_s.gsub('"', '') + if !desc.blank? && alttext.blank? + alt = " title=\"#{desc}\" alt=\"#{desc}\"" + end + "src=\"#{image_url}\"#{alt}" + else + m + end + end + end + end + + # Wiki links + # + # Examples: + # [[mypage]] + # [[mypage|mytext]] + # wiki links can refer other project wikis, using project name or identifier: + # [[project:]] -> wiki starting page + # [[project:|mytext]] + # [[project:mypage]] + # [[project:mypage|mytext]] + def parse_wiki_links(text, project, obj, attr, only_path, options) + text.gsub!(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |m| + link_project = project + esc, all, page, title = $1, $2, $3, $5 + if esc.nil? + if page =~ /^([^\:]+)\:(.*)$/ + identifier, page = $1, $2 + link_project = Project.find_by_identifier(identifier) || Project.find_by_name(identifier) + title ||= identifier if page.blank? + end + + if link_project && link_project.wiki + # extract anchor + anchor = nil + if page =~ /^(.+?)\#(.+)$/ + page, anchor = $1, $2 + end + anchor = sanitize_anchor_name(anchor) if anchor.present? + # check if page exists + wiki_page = link_project.wiki.find_page(page) + url = if anchor.present? && wiki_page.present? && (obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version)) && obj.page == wiki_page + "##{anchor}" + else + case options[:wiki_links] + when :local; "#{page.present? ? Wiki.titleize(page) : ''}.html" + (anchor.present? ? "##{anchor}" : '') + when :anchor; "##{page.present? ? Wiki.titleize(page) : title}" + (anchor.present? ? "_#{anchor}" : '') # used for single-file wiki export + else + wiki_page_id = page.present? ? Wiki.titleize(page) : nil + parent = wiki_page.nil? && obj.is_a?(WikiContent) && obj.page && project == link_project ? obj.page.title : nil + url_for(:only_path => only_path, :controller => 'wiki', :action => 'show', :project_id => link_project, + :id => wiki_page_id, :version => nil, :anchor => anchor, :parent => parent) + end + end + link_to(title.present? ? title.html_safe : h(page), url, :class => ('wiki-page' + (wiki_page ? '' : ' new'))) + else + # project or wiki doesn't exist + all + end + else + all + end + end + end + + def select_option_helper option + tmp = Hash.new + tmp={"" => ""} + if option.nil? + else + option.each do |project| + tmp[project.name] = project.id + end + end + tmp + end + # Redmine links + # + # Examples: + # Issues: + # #52 -> Link to issue #52 + # Changesets: + # r52 -> Link to revision 52 + # commit:a85130f -> Link to scmid starting with a85130f + # Documents: + # document#17 -> Link to document with id 17 + # document:Greetings -> Link to the document with title "Greetings" + # document:"Some document" -> Link to the document with title "Some document" + # Versions: + # version#3 -> Link to version with id 3 + # version:1.0.0 -> Link to version named "1.0.0" + # version:"1.0 beta 2" -> Link to version named "1.0 beta 2" + # Attachments: + # attachment:file.zip -> Link to the attachment of the current object named file.zip + # Source files: + # source:some/file -> Link to the file located at /some/file in the project's repository + # source:some/file@52 -> Link to the file's revision 52 + # source:some/file#L120 -> Link to line 120 of the file + # source:some/file@52#L120 -> Link to line 120 of the file's revision 52 + # export:some/file -> Force the download of the file + # Forum messages: + # message#1218 -> Link to message with id 1218 + # + # Links can refer other objects from other projects, using project identifier: + # identifier:r52 + # identifier:document:"Some document" + # identifier:version:1.0.0 + # identifier:source:some/file + def parse_redmine_links(text, default_project, obj, attr, only_path, options) + text.gsub!(%r{([\s\(,\-\[\>]|^)(!)?(([a-z0-9\-_]+):)?(attachment|document|version|forum|news|message|project|commit|source|export)?(((#)|((([a-z0-9\-_]+)\|)?(r)))((\d+)((#note)?-(\d+))?)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]][^A-Za-z0-9_/])|,|\s|\]|<|$)}) do |m| + leading, esc, project_prefix, project_identifier, prefix, repo_prefix, repo_identifier, sep, identifier, comment_suffix, comment_id = $1, $2, $3, $4, $5, $10, $11, $8 || $12 || $18, $14 || $19, $15, $17 + link = nil + project = default_project + if project_identifier + project = Project.visible.find_by_identifier(project_identifier) + end + if esc.nil? + if prefix.nil? && sep == 'r' + if project + repository = nil + if repo_identifier + repository = project.repositories.detect {|repo| repo.identifier == repo_identifier} + else + repository = project.repository + end + # project.changesets.visible raises an SQL error because of a double join on repositories + if repository && (changeset = Changeset.visible.find_by_repository_id_and_revision(repository.id, identifier)) + link = link_to(h("#{project_prefix}#{repo_prefix}r#{identifier}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :repository_id => repository.identifier_param, :rev => changeset.revision}, + :class => 'changeset', + :title => truncate_single_line(changeset.comments, :length => 100)) + end + end + elsif sep == '#' + oid = identifier.to_i + case prefix + when nil + if oid.to_s == identifier && issue = Issue.visible.find_by_id(oid, :include => :status) + anchor = comment_id ? "note-#{comment_id}" : nil + link = link_to("##{oid}", {:only_path => only_path, :controller => 'issues', :action => 'show', :id => oid, :anchor => anchor}, + :class => issue.css_classes, + :title => "#{truncate(issue.subject, :length => 100)} (#{issue.status.name})") + end + when 'document' + if document = Document.visible.find_by_id(oid) + link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document}, + :class => 'document' + end + when 'version' + if version = Version.visible.find_by_id(oid) + link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version}, + :class => 'version' + end + when 'message' + if message = Message.visible.find_by_id(oid, :include => :parent) + link = link_to_message(message, {:only_path => only_path}, :class => 'message') + end + when 'forum' + if board = Board.visible.find_by_id(oid) + link = link_to h(board.name), {:only_path => only_path, :controller => 'boards', :action => 'show', :id => board, :project_id => board.project}, + :class => 'board' + end + when 'news' + if news = News.visible.find_by_id(oid) + link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news}, + :class => 'news' + end + when 'project' + if p = Project.visible.find_by_id(oid) + link = link_to_project(p, {:only_path => only_path}, :class => 'project') + end + end + elsif sep == ':' + # removes the double quotes if any + name = identifier.gsub(%r{^"(.*)"$}, "\\1") + case prefix + when 'document' + if project && document = project.documents.visible.find_by_title(name) + link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document}, + :class => 'document' + end + when 'version' + if project && version = project.versions.visible.find_by_name(name) + link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version}, + :class => 'version' + end + when 'forum' + if project && board = project.boards.visible.find_by_name(name) + link = link_to h(board.name), {:only_path => only_path, :controller => 'boards', :action => 'show', :id => board, :project_id => board.project}, + :class => 'board' + end + when 'news' + if project && news = project.news.visible.find_by_title(name) + link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news}, + :class => 'news' + end + when 'commit', 'source', 'export' + if project + repository = nil + if name =~ %r{^(([a-z0-9\-_]+)\|)(.+)$} + repo_prefix, repo_identifier, name = $1, $2, $3 + repository = project.repositories.detect {|repo| repo.identifier == repo_identifier} + else + repository = project.repository + end + if prefix == 'commit' + if repository && (changeset = Changeset.visible.where("repository_id = ? AND scmid LIKE ?", repository.id, "#{name}%").first) + link = link_to h("#{project_prefix}#{repo_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :repository_id => repository.identifier_param, :rev => changeset.identifier}, + :class => 'changeset', + :title => truncate_single_line(changeset.comments, :length => 100) + end + else + if repository && User.current.allowed_to?(:browse_repository, project) + name =~ %r{^[/\\]*(.*?)(@([^/\\@]+?))?(#(L\d+))?$} + path, rev, anchor = $1, $3, $5 + link = link_to h("#{project_prefix}#{prefix}:#{repo_prefix}#{name}"), {:controller => 'repositories', :action => (prefix == 'export' ? 'raw' : 'entry'), :id => project, :repository_id => repository.identifier_param, + :path => to_path_param(path), + :rev => rev, + :anchor => anchor}, + :class => (prefix == 'export' ? 'source download' : 'source') + end + end + repo_prefix = nil + end + when 'attachment' + attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil) + if attachments && attachment = Attachment.latest_attach(attachments, name) + link = link_to_attachment(attachment, :only_path => only_path, :download => true, :class => 'attachment') + end + when 'project' + if p = Project.visible.where("identifier = :s OR LOWER(name) = :s", :s => name.downcase).first + link = link_to_project(p, {:only_path => only_path}, :class => 'project') + end + end + end + end + (leading + (link || "#{project_prefix}#{prefix}#{repo_prefix}#{sep}#{identifier}#{comment_suffix}")) + end + end + + HEADING_RE = /(]+)?>(.+?)<\/h(\d)>)/i unless const_defined?(:HEADING_RE) + + def parse_sections(text, project, obj, attr, only_path, options) + return unless options[:edit_section_links] + text.gsub!(HEADING_RE) do + heading = $1 + @current_section += 1 + if @current_section > 1 + content_tag('div', + link_to(image_tag('edit.png'), options[:edit_section_links].merge(:section => @current_section)), + :class => 'contextual', + :title => l(:button_edit_section)) + heading.html_safe + else + heading + end + end + end + + # Headings and TOC + # Adds ids and links to headings unless options[:headings] is set to false + def parse_headings(text, project, obj, attr, only_path, options) + return if options[:headings] == false + + text.gsub!(HEADING_RE) do + level, attrs, content = $2.to_i, $3, $4 + item = strip_tags(content).strip + anchor = sanitize_anchor_name(item) + # used for single-file wiki export + anchor = "#{obj.page.title}_#{anchor}" if options[:wiki_links] == :anchor && (obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version)) + @heading_anchors[anchor] ||= 0 + idx = (@heading_anchors[anchor] += 1) + if idx > 1 + anchor = "#{anchor}-#{idx}" + end + @parsed_headings << [level, anchor, item] + "\n #{content}¶ " + end + end + + MACROS_RE = /( + (!)? # escaping + ( + \{\{ # opening tag + ([\w]+) # macro name + (\(([^\n\r]*?)\))? # optional arguments + ([\n\r].*?[\n\r])? # optional block of text + \}\} # closing tag + ) + )/mx unless const_defined?(:MACROS_RE) + + MACRO_SUB_RE = /( + \{\{ + macro\((\d+)\) + \}\} + )/x unless const_defined?(:MACRO_SUB_RE) + + # Extracts macros from text + def catch_macros(text) + macros = {} + text.gsub!(MACROS_RE) do + all, macro = $1, $4.downcase + if macro_exists?(macro) || all =~ MACRO_SUB_RE + index = macros.size + macros[index] = all + "{{macro(#{index})}}" + else + all + end + end + macros + end + + # Executes and replaces macros in text + def inject_macros(text, obj, macros, execute=true) + text.gsub!(MACRO_SUB_RE) do + all, index = $1, $2.to_i + orig = macros.delete(index) + if execute && orig && orig =~ MACROS_RE + esc, all, macro, args, block = $2, $3, $4.downcase, $6.to_s, $7.try(:strip) + if esc.nil? + h(exec_macro(macro, obj, args, block) || all) + else + h(all) + end + elsif orig + h(orig) + else + h(all) + end + end + end + + TOC_RE = /\{\{([<>]?)toc\}\}<\/p>/i unless const_defined?(:TOC_RE) + + # Renders the TOC with given headings + def replace_toc(text, headings) + text.gsub!(TOC_RE) do + # Keep only the 4 first levels + headings = headings.select{|level, anchor, item| level <= 4} + if headings.empty? + '' + else + div_class = 'toc' + div_class << ' right' if $1 == '>' + div_class << ' left' if $1 == '<' + out = "
' * (current - root) + out << '' + end + end + end + + # Same as Rails' simple_format helper without using paragraphs + def simple_format_without_paragraph(text) + text.to_s. + gsub(/\r\n?/, "\n"). # \r\n and \r -> \n + gsub(/\n\n+/, "
- " + root = headings.map(&:first).min + current = root + started = false + headings.each do |level, anchor, item| + if level > current + out << '
\n" * (current - level) + "
- ' * (level - current) + elsif level < current + out << "
- " + elsif started + out << '
- ' + end + out << "#{item}" + current = level + started = true + end + out << '
"). # 2+ newline -> 2 br + gsub(/([^\n]\n)(?=[^\n])/, '\1
'). # 1 newline -> br + html_safe + end + + def lang_options_for_select(blank=true) + { 'Chinese简体中文 '=> 'zh', :English => :en} + end + + def label_tag_for(name, option_tags = nil, options = {}) + label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "") + content_tag("label", label_text) + end + + def labelled_form_for(*args, &proc) + args << {} unless args.last.is_a?(Hash) + options = args.last + if args.first.is_a?(Symbol) + options.merge!(:as => args.shift) + end + options.merge!({:builder => Redmine::Views::LabelledFormBuilder}) + form_for(*args, &proc) + end + + def labelled_fields_for(*args, &proc) + args << {} unless args.last.is_a?(Hash) + options = args.last + options.merge!({:builder => Redmine::Views::LabelledFormBuilder}) + fields_for(*args, &proc) + end + + def labelled_remote_form_for(*args, &proc) + ActiveSupport::Deprecation.warn "ApplicationHelper#labelled_remote_form_for is deprecated and will be removed in Redmine 2.2." + args << {} unless args.last.is_a?(Hash) + options = args.last + options.merge!({:builder => Redmine::Views::LabelledFormBuilder, :remote => true}) + form_for(*args, &proc) + end + + def error_messages_for(*objects) + html = "" + # modified by fq + if objects.first.is_a?(Array) + objects = objects.first + end + # end + if objects != nil + objects = objects.map {|o| o.is_a?(String) ? instance_variable_get("@#{o}") : o}.compact + errors = objects.map {|o| o.errors.full_messages}.flatten + if errors.any? + html << "\n" + end + end + html.html_safe + end + + def delete_link(url, options={}) + options = { + :method => :delete, + :data => {:confirm => l(:text_are_you_sure)}, + :class => 'icon icon-del' + }.merge(options) + + link_to l(:button_delete), url, options + end + + def preview_link(url, form, target='preview', options={}) + content_tag 'a', l(:label_preview), { + :href => "#", + :onclick => %|submitPreview("#{escape_javascript url_for(url)}", "#{escape_javascript form}", "#{escape_javascript target}"); return false;|, + :accesskey => accesskey(:preview) + }.merge(options) + end + + def link_to_function(name, function, html_options={}) + content_tag(:a, name, {:href => '#', :onclick => "#{function}; return false;"}.merge(html_options)) + end + + # Helper to render JSON in views + def raw_json(arg) + arg.to_json.to_s.gsub('/', '\/').html_safe + end + + def back_url + url = params[:back_url] + if url.nil? && referer = request.env['HTTP_REFERER'] + url = CGI.unescape(referer.to_s) + end + url + end + + def back_url_hidden_field_tag + url = back_url + hidden_field_tag('back_url', url, :id => nil) unless url.blank? + end + + def check_all_links(form_name) + link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") + + " | ".html_safe + + link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)") + end + + def progress_bar(pcts, options={}) + pcts = [pcts, pcts] unless pcts.is_a?(Array) + pcts = pcts.collect(&:round) + pcts[1] = pcts[1] - pcts[0] + pcts << (100 - pcts[1] - pcts[0]) + width = options[:width] || '100px;' + legend = options[:legend] || '' + content_tag('table', + content_tag('tr', + (pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0]}%;", :class => 'closed') : ''.html_safe) + + (pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1]}%;", :class => 'done') : ''.html_safe) + + (pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2]}%;", :class => 'todo') : ''.html_safe) + ), :class => 'progress', :style => "width: #{width};").html_safe + + content_tag('p', legend, :class => 'percent').html_safe + end + + def checked_image(checked=true) + if checked + image_tag 'toggle_check.png' + end + end + + def context_menu(url) + unless @context_menu_included + content_for :header_tags do + javascript_include_tag('context_menu') + + stylesheet_link_tag('context_menu') + end + if l(:direction) == 'rtl' + content_for :header_tags do + stylesheet_link_tag('context_menu_rtl') + end + end + @context_menu_included = true + end + javascript_tag "contextMenuInit('#{ url_for(url) }')" + end + + def calendar_for(field_id,start_day=nil) + include_calendar_headers_tags(start_day) + javascript_tag("$(function() { $('##{field_id}').datepicker(datepickerOptions); });") + end + + def include_calendar_headers_tags(start_day=nil) + if start_day.nil? + unless @calendar_headers_tags_included + @calendar_headers_tags_included = true + content_for :header_tags do + start_of_week = Setting.start_of_week + start_of_week = l(:general_first_day_of_week, :default => '1') if start_of_week.blank? + # Redmine uses 1..7 (monday..sunday) in settings and locales + # JQuery uses 0..6 (sunday..saturday), 7 needs to be changed to 0 + start_of_week = start_of_week.to_i % 7 + + tags = javascript_tag( + "var datepickerOptions={dateFormat: 'yy-mm-dd', firstDay: #{start_of_week}, " + + "showOn: 'button', buttonImageOnly: true, buttonImage: '" + + path_to_image('/images/calendar.png') + + "', showButtonPanel: true, showWeek: true, showOtherMonths: true, selectOtherMonths: true};") + jquery_locale = l('jquery.locale', :default => current_language.to_s) + unless jquery_locale == 'en' + tags << javascript_include_tag("i18n/jquery.ui.datepicker-#{jquery_locale}.js") + end + tags + end + end + else + unless @calendar_headers_tags_included + @calendar_headers_tags_included = true + content_for :header_tags do + start_of_week = Setting.start_of_week + start_of_week = l(:general_first_day_of_week, :default => '1') if start_of_week.blank? + # Redmine uses 1..7 (monday..sunday) in settings and locales + # JQuery uses 0..6 (sunday..saturday), 7 needs to be changed to 0 + start_of_week = start_of_week.to_i % 7 + + tags = javascript_tag( + "var datepickerOptions={dateFormat: 'yy-mm-dd',minDate: new Date(), firstDay: #{start_of_week}, " + + "showOn: 'button', buttonImageOnly: true, buttonImage: '" + + path_to_image('/images/calendar.png') + + "', showButtonPanel: true, showWeek: true, showOtherMonths: true, selectOtherMonths: true, onClose: function(dateText, inst) {TimeClose(dateText,inst);}, beforeShow : function(input){TimeBeforeShow(input);} };") + jquery_locale = l('jquery.locale', :default => current_language.to_s) + unless jquery_locale == 'en' + tags << javascript_include_tag("i18n/jquery.ui.datepicker-#{jquery_locale}.js") + end + tags + end + end + end + + end + + # Overrides Rails' stylesheet_link_tag with themes and plugins support. + # Examples: + # stylesheet_link_tag('styles') # => picks styles.css from the current theme or defaults + # stylesheet_link_tag('styles', :plugin => 'foo) # => picks styles.css from plugin's assets + # + def stylesheet_link_tag(*sources) + options = sources.last.is_a?(Hash) ? sources.pop : {} + plugin = options.delete(:plugin) + sources = sources.map do |source| + if plugin + "/plugin_assets/#{plugin}/stylesheets/#{source}" + elsif current_theme && current_theme.stylesheets.include?(source) + current_theme.stylesheet_path(source) + else + source + end + end + super sources, options + end + + # Overrides Rails' image_tag with themes and plugins support. + # Examples: + # image_tag('image.png') # => picks image.png from the current theme or defaults + # image_tag('image.png', :plugin => 'foo) # => picks image.png from plugin's assets + # + def image_tag(source, options={}) + if plugin = options.delete(:plugin) + source = "/plugin_assets/#{plugin}/images/#{source}" + elsif current_theme && current_theme.images.include?(source) + source = current_theme.image_path(source) + end + super source, options + end + + # Overrides Rails' javascript_include_tag with plugins support + # Examples: + # javascript_include_tag('scripts') # => picks scripts.js from defaults + # javascript_include_tag('scripts', :plugin => 'foo) # => picks scripts.js from plugin's assets + # + def javascript_include_tag(*sources) + options = sources.last.is_a?(Hash) ? sources.pop : {} + if plugin = options.delete(:plugin) + sources = sources.map do |source| + if plugin + "/plugin_assets/#{plugin}/javascripts/#{source}" + else + source + end + end + end + super sources, options + end + + def content_for(name, content = nil, &block) + @has_content ||= {} + @has_content[name] = true + super(name, content, &block) + end + + def has_content?(name) + (@has_content && @has_content[name]) || false + end + + def sidebar_content? + has_content?(:sidebar) || view_layouts_base_sidebar_hook_response.present? + end + + def view_layouts_base_sidebar_hook_response + @view_layouts_base_sidebar_hook_response ||= call_hook(:view_layouts_base_sidebar) + end + + def email_delivery_enabled? + !!ActionMailer::Base.perform_deliveries + end + + # Returns the avatar image tag for the given +user+ if avatars are enabled + # +user+ can be a User or a string that will be scanned for an email address (eg. 'joe\n" + errors.each do |error| + ###by xianbo + if(error!=l(:label_repository_path_not_null)) + html << "
- #{h error}
\n" + end + ###xianbo + end + ###by xianbo + unless params[:repository].nil? + if params[:repository][:upassword]=="" + html << "- "+ l(:label_password_not_null) +"
\n" + end + end + ###xianbo + html << "') + def avatar(user, options = { }) + if Setting.gravatar_enabled? + options.merge!({:ssl => (request && request.ssl?), :default => Setting.gravatar_default}) + email = nil + if user.respond_to?(:mail) + email = user.mail + elsif user.to_s =~ %r{<(.+?)>} + email = $1 + end + return gravatar(email.to_s.downcase, options) unless email.blank? rescue nil + #options ={"class" => ["avatar2"],"width" =>["80px"],"height" =>["80px"]} + #return image_tag url_to_avatar(user), options + else + '' + end + end + + def sanitize_anchor_name(anchor) + if ''.respond_to?(:encoding) || RUBY_PLATFORM == 'java' + anchor.gsub(%r{[^\s\-\p{Word}]}, '').gsub(%r{\s+(\-+\s*)?}, '-') + else + # TODO: remove when ruby1.8 is no longer supported + anchor.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-') + end + end + + # Returns the javascript tags that are included in the html layout head + def javascript_heads + tags = javascript_include_tag('jquery-1.8.3-ui-1.9.2-ujs-2.0.3', 'application', 'jquery.colorbox-min') + unless User.current.pref.warn_on_leaving_unsaved == '0' + tags << "\n".html_safe + javascript_tag("$(window).load(function(){ warnLeavingUnsaved('#{escape_javascript l(:text_warn_on_leaving_unsaved)}'); });") + end + tags + end + + def hubspot_head + tags = javascript_include_tag('hubspot/messenger.min', 'hubspot/messenger-theme-future') + tags << stylesheet_link_tag('hubspot/messenger', 'hubspot/messenger-theme-future', 'hubspot/messenger-theme-flat') + end + + def bootstrap_head + tags = stylesheet_link_tag('bootstrap/bootstrap.min', 'bootstrap/bootstrap-theme.min') + tags << javascript_include_tag('bootstrap/affix') + tags << javascript_include_tag('bootstrap/alert') + tags << javascript_include_tag('bootstrap/button') + tags << javascript_include_tag('bootstrap/carousel') + tags << javascript_include_tag('bootstrap/collapse') + tags << javascript_include_tag('bootstrap/dropdown') + tags << javascript_include_tag('bootstrap/modal') + tags << javascript_include_tag('bootstrap/popover') + tags << javascript_include_tag('bootstrap/scrollspy') + tags << javascript_include_tag('bootstrap/tab') + tags << javascript_include_tag('bootstrap/tooltip') + tags << javascript_include_tag('bootstrap/transition') + tags + end + + def favicon + "".html_safe + end + + def robot_exclusion_tag + ''.html_safe + end + + # Returns true if arg is expected in the API response + def include_in_api_response?(arg) + unless @included_in_api_response + param = params[:include] + @included_in_api_response = param.is_a?(Array) ? param.collect(&:to_s) : param.to_s.split(',') + @included_in_api_response.collect!(&:strip) + end + @included_in_api_response.include?(arg.to_s) + end + + # Returns options or nil if nometa param or X-Redmine-Nometa header + # was set in the request + def api_meta(options) + if params[:nometa].present? || request.headers['X-Redmine-Nometa'] + # compatibility mode for activeresource clients that raise + # an error when unserializing an array with attributes + nil + else + options + end + end + + # Add by Tao + def url_to_avatar(source) + source = nil if source.kind_of?(String) + get_avatar(source) + end + # Endof Tao's code + + def date_format_local(time) + date = time.strftime("%Y年%m月%d日") + end + + #当TAG数量过多时,更多链接 + #1代表是user类型 2代表是project类型 3代表是issue类型 4代表需求 9代表课程 + def more_tags id,object_flag + a= 1 + case object_flag + when "1" + s = link_to l(:label_more_tags),:controller => "users", :action => "show", :id => id + when "2" + s = link_to l(:label_more_tags),:controller => "projects", :action => "show", :id => id + when "3" + s = link_to l(:label_more_tags),:controller => "issues", :action => "show", :id => id + when "4" + s = link_to l(:label_more_tags),:controller => "bids", :action => "show", :id => id + when "9" + s = link_to l(:label_more_tags),:controller => "courses", :action => "show", :id => id + end + s + end + + private + + def wiki_helper + helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting) + extend helper + return self + end + + def link_to_content_update(text, url_params = {}, html_options = {}) + link_to(text, url_params, html_options) + end + +#added by nie +# Display watcher picture + def show_more_watchers?(obj) + if User.watched_by(obj.id).count > 6 + return true + else + return false + end + end + + def show_watcher_profile(obj) + count = 0 + html = '' + if User.watched_by(obj.id).count == 0 + html << (content_tag "span", l(:label_no_current_watchers)) + end + for user in User.watched_by(obj.id) + html << (link_to image_tag(url_to_avatar(user), :class => "avatar"), user_path(user), :class => "avatar", :title => "#{user.name}") + count = count + 1 + if count >= 12 + break + end + end + html.html_safe + end + +#display bid project + def show_more_bid_project?(bid) + if bid.projects.where('is_public = 1').count > 12 + return true + else + return false + end + end + + def show_bid_project(bid) + html = '' + if bid.projects.where('is_public = 1').count == 0 + html << (content_tag "p", l(:label_no_bid_project), :class => "font_lighter") + else + bid.projects.where('is_public = 1').take(12).each do |project| + html << (link_to image_tag(url_to_avatar(project), :class => "avatar", :title => project.name), project_path(project), :class => "avatar") + end + end + html.html_safe + end + + def show_bid_fans_picture(obj) + html = '' + if obj.watcher_users.count == 0 + html << (content_tag "span", l(:label_project_no_follow)) + else + obj.watcher_users.take(12).each do |user| + html << (link_to image_tag(url_to_avatar(user), :class => "avatar"), user_path(user), :class => "avatar", :title => user.name) + end + end + html.html_safe + end + +#display contest project + def show_more_contest_project?(contest) + if contest.projects.where('is_public = 1').count > 12 + return true + else + return false + end + end + + def show_more_contest_softapplication?(contest) + if contest.softapplications.where('is_public = 1').count > 12 + return true + else + return false + end + end + + def show_contest_project(bid) + html = '' + if contest.projects.where('is_public = 1').count == 0 + html << (content_tag "p", l(:label_no_bid_project), :class => "font_lighter") + else + contest.projects.where('is_public = 1').take(12).each do |project| + html << (link_to image_tag(url_to_avatar(project), :class => "avatar", :title => project.name), project_path(project), :class => "avatar") + end + end + html.html_safe + end + + def show_contest_project(contest) + html = '' + if contest.projects.where('is_public = 1').count == 0 + html << (content_tag "p", l(:label_no_bid_project), :class => "font_lighter") + else + contest.projects.where('is_public = 1').take(12).each do |project| + html << (link_to image_tag(url_to_avatar(project), :class => "avatar", :title => project.name), project_path(project), :class => "avatar") + end + end + html.html_safe + end + + def show_contest_softapplication(contest) + html = '' + if contest.softapplications.where('is_public = 1').count == 0 + html << (content_tag "p", l(:label_no_contest_softapplication), :class => "font_lighter") + else + contest.softapplications.where('is_public = 1').take(12).each do |softapplication| + html << (link_to image_tag(url_to_avatar(project), :class => "avatar", :title => project.name), project_path(project), :class => "avatar") + end + end + html.html_safe + end + + def show_contest_fans_picture(obj) + html = '' + if obj.watcher_users.count == 0 + html << (content_tag "span", l(:label_project_no_follow)) + else + obj.watcher_users.take(12).each do |user| + html << (link_to image_tag(url_to_avatar(user), :class => "avatar"), user_path(user), :class => "avatar", :title => user.name) + end + end + html.html_safe + end + +#display fans picture + def show_more_fans?(obj) + if obj.watcher_users.count > 12 + return true + else + return false + end + end + + def show_fans_picture(obj) + html = '' + if obj.watcher_users.count == 0 + html << (content_tag "span", l(:label_no_current_fans)) + else + obj.watcher_users.take(12).each do |user| + html << (link_to image_tag(url_to_avatar(user), :class => "avatar"), user_path(user), :class => "avatar", :title => user.name) + end + end + html.html_safe + end + + # added by bai + def show_more_participate?(obj) + if obj.join_in_contests.count > 12 + return true + else + return false + end + end + + def show_participate_picture(obj) + html = '' + count = 0 + if obj.join_in_contests.count == 0 + html << (content_tag "span", l(:label_no_current_participate)) + end + for temp in obj.join_in_contests + html << (link_to image_tag(url_to_avatar(temp.user), :class => "avatar"), user_path(temp.user), :class => "avatar", :title => "#{temp.user.name}") + count = count + 1 + if count >= 12 + break + end + end + html.html_safe + end + +#end + +# add by huang + def show_watcher_list(user) + html = '' + count = 0 + for user in User.watched_by(user.id) + html << (link_to image_tag(url_to_avatar(user), :class => "avatar"), user_path(user), :class => "avatar", :title => "#{user.name}") + count = count + 1 + if count >= 12 + break + end + end + html.html_safe + end +# end + +#added by william + def get_fans_num(user) + user.watcher_users.count + end +#end + + + def hadcommittedhomework(cur,curb) + bid = Bid.find_by_id(curb) + return true if bid.nil? + + case bid.homework_type + when Bid::HomeworkFile + attaches = HomeworkAttach.where(bid_id: curb) + attaches.map(&:user_id).include? cur + when Bid::HomeworkProject + attaches = BidingProject.where(user_id: User.current, bid_id: bid) + attaches.count > 0 # > 0 则有提交记录 + else + true + end + + end + + def render_dynamic_nav + home_link = link_to l(:field_homepage), {:controller => 'welcome', :action => 'index'} + home_link = " " << home_link << " " + # bootstrap_render_dynamic_nav + content_tag :ul, (home_link.html_safe+bootstrap_render_dynamic_nav) + end + + def bootstrap_render_dynamic_nav + + main_course_link = link_to l(:label_course_practice), {:controller => 'welcome', :action => 'index', :host => Setting.course_domain} + main_project_link = link_to l(:label_project_deposit), {:controller => 'welcome', :action => 'index', :host => Setting.project_domain} + main_contest_link = link_to l(:label_contest_innovate), {:controller => 'welcome', :action => 'index', :host => Setting.contest_domain} + + course_all_course_link = link_to l(:label_course_all), {:controller => 'courses', :action => 'index'} + course_teacher_all_link = link_to l(:label_teacher_all), {:controller => 'users', :action => 'index', :role => 'teacher', :host => Setting.course_domain} + courses_link = link_to l(:label_course_practice), {:controller => 'courses', :action => 'index'} + projects_link = link_to l(:label_project_deposit), {:controller => 'projects', :action => 'index', :project_type => 0, :host => Setting.project_domain} + users_link = link_to l(:label_software_user), {:controller => 'users', :action => 'index', :host => Setting.user_domain} + contest_link = link_to l(:label_contest_innovate), {:controller => 'contests', :action => 'index'} + bids_link = link_to l(:label_requirement_enterprise), {:controller => 'bids', :action => 'index'} + forum_link = link_to l(:label_project_module_forums), {:controller => "forums", :action => "index"} + stores_link = link_to l(:label_stores_index), {:controller => 'stores', :action=> 'index'} + + + school_all_school_link = link_to l(:label_school_all), {:controller => 'school', :action => 'index'} + + + #@nav_dispaly_project_label + nav_list = Array.new + nav_list.push(school_all_school_link) if @nav_dispaly_course_all_label && @show_course == 1 + nav_list.push(course_all_course_link) if @nav_dispaly_course_all_label && @show_course == 1 + nav_list.push(course_teacher_all_link) if @nav_dispaly_teacher_all_label && @show_course == 1 + + nav_list.push(main_project_link) if @nav_dispaly_main_project_label + nav_list.push(main_course_link) if @nav_dispaly_main_course_label && @show_course == 1 + nav_list.push(main_contest_link) if @nav_dispaly_main_contest_label && @show_contest == 1 + + nav_list.push(courses_link) if @nav_dispaly_course_label && @show_course == 1 + nav_list.push(projects_link) if @nav_dispaly_project_label + nav_list.push(users_link) if @nav_dispaly_user_label + nav_list.push(contest_link) if @nav_dispaly_contest_label && @show_contest == 1 + nav_list.push(bids_link) if @nav_dispaly_bid_label + nav_list.push(forum_link) if @nav_dispaly_forum_label + nav_list.push(stores_link) if @nav_dispaly_store_all_label + + content_li = '' + nav_list.collect do |nav_item| + content_li << content_tag(:li, nav_item) + end + content_li.html_safe + end + + def current_user + User.current + end + + # def hadcommittedforcontest(curu) + # message = JournalsForMessage.find_by_sql("select * from journals_for_messages where jour_type = 'Softapplication' ") + # message.each do |createmessage| + # if createmessage.user_id == curu + # return true + # end + # end + # end + + def footer_logo(ul_class=nil, li_class=nil) + logos = [] + logos.push(link_to image_tag('/images/footer_logo/nudt.png',:alt=>"nudt"),"http://www.nudt.edu.cn/special.asp?classid=12" ) + logos.push(link_to image_tag('/images/footer_logo/peking_eecs.png', :alt=>"peking_eecs"), "http://eecs.pku.edu.cn" ) + logos.push(link_to image_tag('/images/footer_logo/buaa_scse.png', :alt=>"buaa_scse"), "http://scse.buaa.edu.cn/" ) + logos.push(link_to image_tag('/images/footer_logo/iscas.png', :alt=>"iscas"), "http://www.iscas.ac.cn" ) + logos.push(link_to image_tag('/images/footer_logo/inforbus.png', :alt=>"inforbus"), "http://www.inforbus.com" ) + + logos.collect! { |logo| + content_tag(:li, logo.html_safe, :class => li_class.to_s) + } + + content_tag(:ul, logos.join("").html_safe, :class => ul_class.to_s).html_safe + end + + +end diff --git a/app/helpers/attachments_helper.rb b/app/helpers/attachments_helper.rb index 060ced940..7ea49dad2 100644 --- a/app/helpers/attachments_helper.rb +++ b/app/helpers/attachments_helper.rb @@ -1,219 +1,219 @@ -# encoding: utf-8 -# -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -module AttachmentsHelper - # Displays view/delete links to the attachments of the given object - # Options: - # :author -- author names are not displayed if set to false - # :thumbails -- display thumbnails if enabled in settings - - include Redmine::Pagination - - def link_to_attachments(container, options = {}) - options.assert_valid_keys(:author, :thumbnails) - - if container.attachments.any? - options = {:deletable => container.attachments_deletable?, :author => true}.merge(options) - render :partial => 'attachments/links', - :locals => {:attachments => container.attachments, :options => options, :thumbnails => (options[:thumbnails] && Setting.thumbnails_enabled?)} - end - end - - def attach_delete(project) - if User.current.logged? && (User.current.admin? || (!Member.where('user_id = ? and project_id = ?', User.current.id, project.bid.courses.first.id).first.nil? && (Member.where('user_id = ? and project_id = ?', User.current.id, project.bid.courses.first.id).first.roles&Role.where('id = ? or id = ?', 3, 7)).size >0) || project.user_id == User.current.id) - true - else - false - end - - end - - def render_api_attachment(attachment, api) - api.attachment do - api.id attachment.id - api.filename attachment.filename - api.filesize attachment.filesize - api.content_type attachment.content_type - api.description attachment.description - api.content_url url_for(:controller => 'attachments', :action => 'download', :id => attachment, :filename => attachment.filename, :only_path => false) - api.author(:id => attachment.author.id, :name => attachment.author.name) if attachment.author - api.created_on attachment.created_on - end - end - - def link_to_memo_attachments(container, options = {}) - options.assert_valid_keys(:author, :thumbnails) - - if container.attachments.any? - options = {:deletable => deletable?(container), :author => true}.merge(options) - render :partial => 'attachments/links', - :locals => {:attachments => container.attachments, :options => options, :thumbnails => (options[:thumbnails] && Setting.thumbnails_enabled?)} - end - end - - private - - def deletable? container, user=User.current - User.current.logged? && (container.author == user || user.admin?) - end - - # this method is used to get all projects that tagged one tag - # added by william - def get_attachments_by_tag(tag_name) - Attachment.tagged_with(tag_name).order('created_on desc') - end - - # this method is used to get all attachments that from one project and tagged one tag - # added by Long Jun - def get_attachments_by_project_tag(tag_name, obj) - @project_id =nil - if obj.container_type == 'Version' - @project_id = Version.find(obj.container_id).project_id - - elsif obj.container_type == 'Project' - @project_id = obj.container_id - - end - attachments = Attachment.tagged_with(tag_name).order('created_on desc').where("(container_id = :project_id and container_type = 'Project') or - (container_id in (select id from versions where project_id =:project_id) and container_type = 'Version')", {:project_id => @project_id}) - return attachments - end - - - def render_attachments_for_new_project(project, limit=nil) - # 查询条件 - params[:q] ||= "" - filename_condition = params[:q].strip - - attachAll = Attachment.scoped - # 当前项目所有资源 - # attachments = Attachment.find_all_by_container_type_and_container_id(project.class, project.id) - # attachments = Attachment.where("container_type = '#{project.class}' and container_id = #{project.id}") - - # 除去当前项目的所有资源 - nobelong_attach = Attachment.where("!(container_type = '#{project.class}' and container_id = #{project.id})") unless project.blank? - - # 搜索域确定 - domain = project.nil? ? attachAll : nobelong_attach - - # 搜索到的资源 - searched_attach = domain.where("is_public=1 and filename LIKE :like ", like:"%#{filename_condition}%").limit(limit).order('created_on desc') - #searched_attach = private_filter searched_attach - searched_attach = paginateHelper(searched_attach, 10) - - s = content_tag('div', attachments_check_box_tags('attachment[attach][]', searched_attach), :id => 'attachments') - links = pagination_links_full(@obj_pages, @obj_count, :per_page_links => false) {|text, parameters, options| - link_to text, attachments_autocomplete_path( parameters.merge(:project_id=>project.id,:q => params[:q], :format => 'js')), :remote => true } - - return s + content_tag('div', content_tag('ul', links), :class => 'pagination') - - # ================================================================================================ - - # attach_count = searched_attach.count - # attach_pages = Redmine::Pagination::Paginator.new attach_count, 10, params['page'] #by young - # attachs = searched_attach.offset(attach_pages.offset).limit(attach_pages.per_page).all - - # s = content_tag('div', attachments_check_box_tags('attachment[attach][]', attachs), :id => 'attachments') - # links = pagination_links_full(attach_pages, attach_count, :per_page_links => false) {|text, parameters, options| - # link_to text, attachments_autocomplete_path( parameters.merge(:q => params[:q], :format => 'js')), :remote => true } - - # return s + content_tag('div', content_tag('ul', links), :class => 'pagination') - # return searched_attach.to_json - end - - # add by nwb - def render_attachments_for_new_course(course, limit=nil) - # 查询条件 - params[:q] ||= "" - filename_condition = params[:q].strip - - #attachAll = Attachment.where("author_id = #{User.current.id}") - # - ## 除去当前课程的所有资源 - #nobelong_attach = - - # 搜索域确定 - course.nil? ? - domain=Attachment.where("author_id = #{User.current.id}") - : - domain=Attachment.where("author_id = #{User.current.id} and container_type = 'Course' and container_id <> #{course.id}") unless course.blank? - - # 搜索到的资源 - searched_attach = domain.where("filename LIKE :like ", like:"%#{filename_condition}%").limit(limit).order('created_on desc') - #searched_attach = private_filter searched_attach - searched_attach = paginateHelper(searched_attach, 10) - - #testattach = Attachment.public_attachments - - s = content_tag('div', attachments_check_box_tags('attachment[attach][]', searched_attach), :id => 'attachments') - links = pagination_links_full(@obj_pages, @obj_count, :per_page_links => false) {|text, parameters, options| - link_to text, attachments_autocomplete_path( parameters.merge(:course_id=>course.id,:q => params[:q], :format => 'js')), :remote => true } - - return s + content_tag('div', content_tag('ul', links), :class => 'pagination') - - end - - def attachments_check_box_tags(name, attachs) - s = '' - attachs.each do |attach| - s << "
" - end - s.html_safe - end - - # Modified by Longjun - # 有参数的方法要加() - def private_filter(resultSet) - result = resultSet.to_a.dup - - # modify by nwb - #添加对课程资源文件的判断 - resultSet.map { |res| - if(res.container.nil? || - (res.container.class.to_s=="Project" && res.container.is_public == false) || - (res.container.has_attribute?(:project) && res.container.project && res.container.project.is_public == false) || - (res.container.class.to_s=="HomeworkAttach" && res.container.bid.reward_type == 3) || - (res.container.class.to_s=="Course" && res.container.is_public == false) || - (res.container.has_attribute?(:course) && res.container.course && res.container.course.is_public == false) - ) - result.delete(res) - end - } - result - end - - # Modified by Longjun - # include 应放在class/model 的开始处 - # include Redmine::Pagination - # end - - def paginateHelper (obj, pre_size=10) - @obj_count = obj.count - @obj_pages = Paginator.new @obj_count, pre_size, params['page'] - if obj.kind_of? ActiveRecord::Base or obj.kind_of? ActiveRecord::Relation - obj.limit(@obj_pages.per_page).offset(@obj_pages.offset) - elsif obj.kind_of? Array - obj[@obj_pages.offset, @obj_pages.per_page] - else - logger.error "[ApplicationController] Error : application_controller#paginateHelper ===> unknow category: #{obj.class}" - raise RuntimeError, 'unknow type, Please input you type into this helper.' - end - end - -end +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module AttachmentsHelper + # Displays view/delete links to the attachments of the given object + # Options: + # :author -- author names are not displayed if set to false + # :thumbails -- display thumbnails if enabled in settings + + include Redmine::Pagination + + def link_to_attachments(container, options = {}) + options.assert_valid_keys(:author, :thumbnails) + + if container.attachments.any? + options = {:deletable => container.attachments_deletable?, :author => true}.merge(options) + render :partial => 'attachments/links', + :locals => {:attachments => container.attachments, :options => options, :thumbnails => (options[:thumbnails] && Setting.thumbnails_enabled?)} + end + end + + def attach_delete(project) + if User.current.logged? && (User.current.admin? || (!Member.where('user_id = ? and project_id = ?', User.current.id, project.bid.courses.first.id).first.nil? && (Member.where('user_id = ? and project_id = ?', User.current.id, project.bid.courses.first.id).first.roles&Role.where('id = ? or id = ?', 3, 7)).size >0) || project.user_id == User.current.id) + true + else + false + end + + end + + def render_api_attachment(attachment, api) + api.attachment do + api.id attachment.id + api.filename attachment.filename + api.filesize attachment.filesize + api.content_type attachment.content_type + api.description attachment.description + api.content_url url_for(:controller => 'attachments', :action => 'download', :id => attachment, :filename => attachment.filename, :only_path => false) + api.author(:id => attachment.author.id, :name => attachment.author.name) if attachment.author + api.created_on attachment.created_on + end + end + + def link_to_memo_attachments(container, options = {}) + options.assert_valid_keys(:author, :thumbnails) + + if container.attachments.any? + options = {:deletable => deletable?(container), :author => true}.merge(options) + render :partial => 'attachments/links', + :locals => {:attachments => container.attachments, :options => options, :thumbnails => (options[:thumbnails] && Setting.thumbnails_enabled?)} + end + end + + private + + def deletable? container, user=User.current + User.current.logged? && (container.author == user || user.admin?) + end + + # this method is used to get all projects that tagged one tag + # added by william + def get_attachments_by_tag(tag_name) + Attachment.tagged_with(tag_name).order('created_on desc') + end + + # this method is used to get all attachments that from one project and tagged one tag + # added by Long Jun + def get_attachments_by_project_tag(tag_name, obj) + @project_id =nil + if obj.container_type == 'Version' + @project_id = Version.find(obj.container_id).project_id + + elsif obj.container_type == 'Project' + @project_id = obj.container_id + + end + attachments = Attachment.tagged_with(tag_name).order('created_on desc').where("(container_id = :project_id and container_type = 'Project') or + (container_id in (select id from versions where project_id =:project_id) and container_type = 'Version')", {:project_id => @project_id}) + return attachments + end + + + def render_attachments_for_new_project(project, limit=nil) + # 查询条件 + params[:q] ||= "" + filename_condition = params[:q].strip + + attachAll = Attachment.scoped + # 当前项目所有资源 + # attachments = Attachment.find_all_by_container_type_and_container_id(project.class, project.id) + # attachments = Attachment.where("container_type = '#{project.class}' and container_id = #{project.id}") + + # 除去当前项目的所有资源 + nobelong_attach = Attachment.where("!(container_type = '#{project.class}' and container_id = #{project.id})") unless project.blank? + + # 搜索域确定 + domain = project.nil? ? attachAll : nobelong_attach + + # 搜索到的资源 + searched_attach = domain.where("is_public=1 and filename LIKE :like ", like:"%#{filename_condition}%").limit(limit).order('created_on desc') + #searched_attach = private_filter searched_attach + searched_attach = paginateHelper(searched_attach, 10) + + s = content_tag('div', attachments_check_box_tags('attachment[attach][]', searched_attach), :id => 'attachments') + links = pagination_links_full(@obj_pages, @obj_count, :per_page_links => false) {|text, parameters, options| + link_to text, attachments_autocomplete_path( parameters.merge(:project_id=>project.id,:q => params[:q], :format => 'js')), :remote => true } + + return s + content_tag('div', content_tag('ul', links), :class => 'pagination') + + # ================================================================================================ + + # attach_count = searched_attach.count + # attach_pages = Redmine::Pagination::Paginator.new attach_count, 10, params['page'] #by young + # attachs = searched_attach.offset(attach_pages.offset).limit(attach_pages.per_page).all + + # s = content_tag('div', attachments_check_box_tags('attachment[attach][]', attachs), :id => 'attachments') + # links = pagination_links_full(attach_pages, attach_count, :per_page_links => false) {|text, parameters, options| + # link_to text, attachments_autocomplete_path( parameters.merge(:q => params[:q], :format => 'js')), :remote => true } + + # return s + content_tag('div', content_tag('ul', links), :class => 'pagination') + # return searched_attach.to_json + end + + # add by nwb + def render_attachments_for_new_course(course, limit=nil) + # 查询条件 + params[:q] ||= "" + filename_condition = params[:q].strip + + #attachAll = Attachment.where("author_id = #{User.current.id}") + # + ## 除去当前课程的所有资源 + #nobelong_attach = + + # 搜索域确定 + course.nil? ? + domain=Attachment.where("author_id = #{User.current.id}") + : + domain=Attachment.where("author_id = #{User.current.id} and container_type = 'Course' and container_id <> #{course.id}") unless course.blank? + + # 搜索到的资源 + searched_attach = domain.where("filename LIKE :like ", like:"%#{filename_condition}%").limit(limit).order('created_on desc') + #searched_attach = private_filter searched_attach + searched_attach = paginateHelper(searched_attach, 10) + + #testattach = Attachment.public_attachments + + s = content_tag('div', attachments_check_box_tags('attachment[attach][]', searched_attach), :id => 'attachments') + links = pagination_links_full(@obj_pages, @obj_count, :per_page_links => false) {|text, parameters, options| + link_to text, attachments_autocomplete_path( parameters.merge(:course_id=>course.id,:q => params[:q], :format => 'js')), :remote => true } + + return s + content_tag('div', content_tag('ul', links), :class => 'pagination') + + end + + def attachments_check_box_tags(name, attachs) + s = '' + attachs.each do |attach| + s << "
" + end + s.html_safe + end + + # Modified by Longjun + # 有参数的方法要加() + def private_filter(resultSet) + result = resultSet.to_a.dup + + # modify by nwb + #添加对课程资源文件的判断 + resultSet.map { |res| + if(res.container.nil? || + (res.container.class.to_s=="Project" && res.container.is_public == false) || + (res.container.has_attribute?(:project) && res.container.project && res.container.project.is_public == false) || + (res.container.class.to_s=="HomeworkAttach" && res.container.bid.reward_type == 3) || + (res.container.class.to_s=="Course" && res.container.is_public == false) || + (res.container.has_attribute?(:course) && res.container.course && res.container.course.is_public == false) + ) + result.delete(res) + end + } + result + end + + # Modified by Longjun + # include 应放在class/model 的开始处 + # include Redmine::Pagination + # end + + def paginateHelper (obj, pre_size=10) + @obj_count = obj.count + @obj_pages = Paginator.new @obj_count, pre_size, params['page'] + if obj.kind_of? ActiveRecord::Base or obj.kind_of? ActiveRecord::Relation + obj.limit(@obj_pages.per_page).offset(@obj_pages.offset) + elsif obj.kind_of? Array + obj[@obj_pages.offset, @obj_pages.per_page] + else + logger.error "[ApplicationController] Error : application_controller#paginateHelper ===> unknow category: #{obj.class}" + raise RuntimeError, 'unknow type, Please input you type into this helper.' + end + end + +end diff --git a/app/helpers/logger_helper.rb b/app/helpers/logger_helper.rb index af04e38d3..3a7953c02 100644 --- a/app/helpers/logger_helper.rb +++ b/app/helpers/logger_helper.rb @@ -1,27 +1,27 @@ -module LoggerHelper - - #输出日志 - def OutLogger - #日志输出级别 - #Rails.logger.level = Logger::INFO - - if(!File.exist?("database")) - Dir.mkdir("database") - end - if(!File.exist?("database/get")) - Dir.mkdir("database/get") - end - if(!File.exist?("database/sql")) - Dir.mkdir("database/sql") - end - if(!File.exist?("database/controller")) - Dir.mkdir("database/controller") - end - - Rails.logger = Logger.new("database/get/#{Date.today.to_s}.log", "daily") - ActiveRecord::Base.logger = Logger.new("database/sql/#{Date.today.to_s}.log", "daily") - ActionController::Base.logger = Logger.new("database/controller/#{Date.today.to_s}.log", "daily") - end - -end - +module LoggerHelper + + #输出日志 + def OutLogger + #日志输出级别 + #Rails.logger.level = Logger::INFO + + if(!File.exist?("database")) + Dir.mkdir("database") + end + if(!File.exist?("database/get")) + Dir.mkdir("database/get") + end + if(!File.exist?("database/sql")) + Dir.mkdir("database/sql") + end + if(!File.exist?("database/controller")) + Dir.mkdir("database/controller") + end + + Rails.logger = Logger.new("database/get/#{Date.today.to_s}.log", "daily") + ActiveRecord::Base.logger = Logger.new("database/sql/#{Date.today.to_s}.log", "daily") + ActionController::Base.logger = Logger.new("database/controller/#{Date.today.to_s}.log", "daily") + end + +end + diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index a19819a02..5df3644ad 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -1,378 +1,378 @@ -# encoding: utf-8 -# -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -include AvatarHelper -module ProjectsHelper - def link_to_version(version, options = {}) - return '' unless version && version.is_a?(Version) - link_to_if version.visible?, format_version_name(version), { :controller => 'versions', :action => 'show', :id => version }, options - end - - def project_settings_tabs - tabs = [{:name => 'info', :action => :edit_project, :partial => 'projects/edit', :label => :label_information_plural}, - {:name => 'modules', :action => :select_project_modules, :partial => 'projects/settings/modules', :label => :label_module_plural}, - {:name => 'members', :action => :manage_members, :partial => 'projects/settings/members', :label => :label_member_plural}, - {:name => 'versions', :action => :manage_versions, :partial => 'projects/settings/versions', :label => :label_version_plural}, - {:name => 'categories', :action => :manage_categories, :partial => 'projects/settings/issue_categories', :label => :label_issue_category_plural}, - # {:name => 'wiki', :action => :manage_wiki, :partial => 'projects/settings/wiki', :label => :label_wiki}, - {:name => 'repositories', :action => :manage_repository, :partial => 'projects/settings/repositories', :label => :label_repository_plural}, - #{:name => 'boards', :action => :manage_boards, :partial => 'projects/settings/boards', :label => :label_board_plural}, - {:name => 'activities', :action => :manage_project_activities, :partial => 'projects/settings/activities', :label => :enumeration_activities} - ] - tabs.select {|tab| User.current.allowed_to?(tab[:action], @project)} - - end - - # added bu huang - def sort_project_enterprise(state, project_type) - content = ''.html_safe - case state - when 0 - - content << content_tag('li', link_to(l(:label_sort_by_active), projects_path(:project_sort_type => '1', :project_type => project_type))) - content << content_tag('li', link_to(l(:label_sort_by_influence), projects_path(:project_sort_type => '2', :project_type => project_type))) - content << content_tag('li', link_to(l(:label_sort_by_time), projects_path(:project_sort_type => '0', :project_type => project_type), :class=>"selected"), :class=>"selected") - when 1 - - content << content_tag('li', link_to(l(:label_sort_by_active), projects_path(:project_sort_type => '1', :project_type => project_type), :class=>"selected"), :class=>"selected") - content << content_tag('li', link_to(l(:label_sort_by_influence), projects_path(:project_sort_type => '2', :project_type => project_type))) - content << content_tag('li', link_to(l(:label_sort_by_time), projects_path(:project_sort_type => '0', :project_type => project_type))) - when 2 - content << content_tag('li', link_to(l(:label_sort_by_active), projects_path(:project_sort_type => '1', :project_type => project_type))) - content << content_tag('li', link_to(l(:label_sort_by_influence), projects_path(:project_sort_type => '2', :project_type => project_type), :class=>"selected"), :class=>"selected") - content << content_tag('li', link_to(l(:label_sort_by_time), projects_path(:project_sort_type => '0', :project_type => project_type))) - end - content = content_tag('ul', content) - content_tag('div', content, :class => "tabs_enterprise") - end - - def sort_course(state, project_type, school_id) - content = ''.html_safe - case state - when 0 - content << content_tag('li', link_to(l(:label_sort_by_time), course_path(:project_sort_type => '0', :project_type => project_type), :school_id => school_id, :class=>"selected"), :class=>"selected") - content << content_tag('li', link_to(l(:label_sort_by_active), course_path(:project_sort_type => '1', :project_type => project_type, :school_id => school_id))) - # content << content_tag('li', link_to(l(:label_sort_by_influence), course_path(:project_sort_type => '2', :project_type => project_type))) - content << content_tag('li', link_to(l(:label_sort_by_activity), course_path(:project_sort_type => '3', :project_type => project_type, :school_id => school_id))) - - when 1 - content << content_tag('li', link_to(l(:label_sort_by_time), course_path(:project_sort_type => '0', :project_type => project_type, :school_id => school_id))) - content << content_tag('li', link_to(l(:label_sort_by_active), course_path(:project_sort_type => '1', :project_type => project_type, :school_id => school_id), :class=>"selected"), :class=>"selected") - # content << content_tag('li', link_to(l(:label_sort_by_influence), course_path(:project_sort_type => '2', :project_type => project_type))) - content << content_tag('li', link_to(l(:label_sort_by_activity), course_path(:project_sort_type => '3', :project_type => project_type, :school_id => school_id))) - - when 2 - content << content_tag('li', link_to(l(:label_sort_by_time), course_path(:project_sort_type => '0', :project_type => project_type, :school_id => school_id))) - content << content_tag('li', link_to(l(:label_sort_by_active), course_path(:project_sort_type => '1', :project_type => project_type, :school_id => school_id))) - # content << content_tag('li', link_to(l(:label_sort_by_influence), course_path(:project_sort_type => '2', :project_type => project_type), :class=>"selected"), :class=>"selected") - content << content_tag('li', link_to(l(:label_sort_by_activity), course_path(:project_sort_type => '3', :project_type => project_type, :school_id => school_id))) - - #gcm - when 3 - content << content_tag('li', link_to(l(:label_sort_by_time), course_path(:project_sort_type => '0', :project_type => project_type, :school_id => school_id))) - content << content_tag('li', link_to(l(:label_sort_by_active), course_path(:project_sort_type => '1', :project_type => project_type, :school_id => school_id))) - # content << content_tag('li', link_to(l(:label_sort_by_influence), course_path(:project_sort_type => '2', :project_type => project_type))) - content << content_tag('li', link_to(l(:label_sort_by_activity), course_path(:project_sort_type => '3', :project_type => project_type, :school_id => school_id), :class=>"selected"), :class=>"selected") - end - #gcmend - - content = content_tag('ul', content) - content_tag('div', content, :class => "tabs") - end - # end - - def sort_project(state, project_type) - content = ''.html_safe - case state - when 0 - - content << content_tag('li', link_to(l(:label_sort_by_active), projects_path(:project_sort_type => '1', :project_type => project_type))) - content << content_tag('li', link_to(l(:label_sort_by_influence), projects_path(:project_sort_type => '2', :project_type => project_type))) - content << content_tag('li', link_to(l(:label_sort_by_time), projects_path(:project_sort_type => '0', :project_type => project_type), :class=>"selected"), :class=>"selected") - when 1 - - content << content_tag('li', link_to(l(:label_sort_by_active), projects_path(:project_sort_type => '1', :project_type => project_type), :class=>"selected"), :class=>"selected") - content << content_tag('li', link_to(l(:label_sort_by_influence), projects_path(:project_sort_type => '2', :project_type => project_type))) - content << content_tag('li', link_to(l(:label_sort_by_time), projects_path(:project_sort_type => '0', :project_type => project_type))) - when 2 - content << content_tag('li', link_to(l(:label_sort_by_active), projects_path(:project_sort_type => '1', :project_type => project_type))) - content << content_tag('li', link_to(l(:label_sort_by_influence), projects_path(:project_sort_type => '2', :project_type => project_type), :class=>"selected"), :class=>"selected") - content << content_tag('li', link_to(l(:label_sort_by_time), projects_path(:project_sort_type => '0', :project_type => project_type))) - end - content = content_tag('ul', content) - content_tag('div', content, :class => "tabs") - end - - # def sort_course(state, project_type) - # content = ''.html_safe - # case state - # when 0 -# - # content << content_tag('li', link_to(l(:label_sort_by_active), course_path(:project_sort_type => '1', :project_type => project_type))) - # content << content_tag('li', link_to(l(:label_sort_by_influence), course_path(:project_sort_type => '2', :project_type => project_type))) - # content << content_tag('li', link_to(l(:label_sort_by_time), course_path(:project_sort_type => '0', :project_type => project_type), :class=>"selected"), :class=>"selected") - # when 1 -# - # content << content_tag('li', link_to(l(:label_sort_by_active), course_path(:project_sort_type => '1', :project_type => project_type), :class=>"selected"), :class=>"selected") - # content << content_tag('li', link_to(l(:label_sort_by_influence), course_path(:project_sort_type => '2', :project_type => project_type))) - # content << content_tag('li', link_to(l(:label_sort_by_time), course_path(:project_sort_type => '0', :project_type => project_type))) - # when 2 - # content << content_tag('li', link_to(l(:label_sort_by_active), course_path(:project_sort_type => '1', :project_type => project_type))) - # content << content_tag('li', link_to(l(:label_sort_by_influence), course_path(:project_sort_type => '2', :project_type => project_type), :class=>"selected"), :class=>"selected") - # content << content_tag('li', link_to(l(:label_sort_by_time), course_path(:project_sort_type => '0', :project_type => project_type))) - # end - # content = content_tag('ul', content) - # content_tag('div', content, :class => "tabs") - # end - - - # Added by young - def course_settings_tabs - tabs = [{:name => 'info', :action => :edit_project, :partial => 'projects/edit', :label => :label_information_plural, :course=>'1'}, - #{:name => 'boards', :action => :manage_boards, :partial => 'projects/settings/boards', :label => :label_board_plural, :project_type => 1}, - # {:name => 'repositories', :action => :manage_repository, :partial => 'projects/settings/repositories', :label => :label_repository_plural}, - {:name => 'members', :action => :manage_members, :partial => 'projects/settings/members', :label => :label_member_plural} - ] - tabs.select {|tab| User.current.allowed_to?(tab[:action], @project)} - end - # Ended by young - - - - - def parent_project_select_tag(project) - selected = project.parent - # retrieve the requested parent project - parent_id = (params[:project] && params[:project][:parent_id]) || params[:parent_id] - if parent_id - selected = (parent_id.blank? ? nil : Project.find(parent_id)) - end - - options = '' - options << "" if project.allowed_parents.include?(nil) - options << project_tree_options_for_select(project.allowed_parents.compact, :selected => selected) - content_tag('select', options.html_safe, :name => 'project[parent_id]', :id => 'project_parent_id') - end - - # Renders the projects index - def render_project_hierarchy(projects) - render_project_nested_lists(projects) do |project| - #Modified by young - if project.try(:project_type) == Project::ProjectType_course - # modified by longjun - # never use unless and else - # unless project.is_public == 1 - if project.is_public != 1 - s = "#{l(:label_private)}".html_safe - else - s = "".html_safe - end - # end longjun - # modified by Longjun - s += link_to_project(project, {}, - :class => "#{project.css_classes} #{User.current.member_of?(project) ? 'my-project' : nil}").html_safe - # end longjun - else - # modified by longjun - # unless project.is_public - if !project.is_public - # end longjun - s = "#{l(:label_private)}".html_safe - else - s = "".html_safe - end - # modified by longjun - s += link_to_project(project, {}, - :class => "#{project.css_classes} #{User.current.member_of?(project) ? 'my-project' : nil}") - # end longjun - end - #Ended by young - if project.description.present? - #Delete by nie. - # s << content_tag('td', textilizable(project.short_description, :project => project), :class => 'wiki description') - end - s - end - end - - # Returns a set of options for a select field, grouped by project. - def version_options_for_select(versions, selected=nil) - grouped = Hash.new {|h,k| h[k] = []} - versions.each do |version| - grouped[version.project.name] << [version.name, version.id] - end - - if grouped.keys.size > 1 - grouped_options_for_select(grouped, selected && selected.id) - else - options_for_select((grouped.values.first || []), selected && selected.id) - end - end - - def format_version_sharing(sharing) - sharing = 'none' unless Version::VERSION_SHARINGS.include?(sharing) - l("label_version_sharing_#{sharing}") - end - - # this method is used to get all projects that tagged one tag - # added by william - def get_projects_by_tag(tag_name) - Project.tagged_with(tag_name).order('updated_on desc') - end - - # added by fq - def homework_type_option - type = [] - option1 = [] - option2 = [] - option1 << l(:label_task_submit_form_accessory) - option1 << 1 - option2 << l(:label_task_submit_form_project) - option2 << 2 - type << option1 - type << option2 - end - - #是否启动互评下拉框 - def is_evaluation_option - type = [] - option1 = [] - option2 = [] - option1 << l(:lable_start_mutual_evaluation) - option1 << 1 - option2 << l(:lable_close_mutual_evaluation) - option2 << 2 - type << option1 - type << option2 - end - - # 用来判断用户是否是项目的管理员 - # added by william - def is_manager?(user_id,project_id) - @result = false - @user_id = ProjectInfo.find_by_project_id(project_id) - - # modified by longjun - # if @user_id == user.id - # @result = true - # end - - @result = true if @user_id = user.id - # end longjun - return @result - end - - # 将动态中类型转换为可读的字符串 - def eventToLanguage event_type - case event_type - when "issue-note" - l :label_issue - when "issue" - l :label_issue - when "attachment" - l :label_attachment - when "news" - l :label_news - else - "" - end - end - - def eventToLanguageCourse event_type, project - case event_type - when "issue-note" - l :label_issue - when "issue" - l :label_issue - when "attachment" - l :label_attachment - when "news" - project.project_type == 1 ? (l :label_notification) : (l :label_news) - else - "" - end - end - - def rolesToLanguage rolesArray - rolesArray = ([] << rolesArray) unless rolesArray.is_a?(Array) - rolesArray.map{ |roleName| - case roleName.to_sym - when :Manager - l :default_role_manager - when :Developer - l :default_role_developer - when :Reporter - l :default_role_reporter - else - 'Unkown' - end - } - end - - def sort_project_by_hot - return sort_project_by_hot_rails - @projects_status = ProjectStatus.visible.where("project_statuses.project_type <> ? or project_statuses.project_type is null", 1) - @projects_status = @projects_status.reorder('grade').all.reverse - @projects = [] - @projects_status.each do |obj| - break if(@projects_status[10] == obj) - @projects << Project.visible.find_by_id("#{obj.project_id}")#where('id=:id', id: obj.project_id) - end - @projects - rescue NoMethodError => e - logger.error "Logger.Error [ProjectsHelper] ===> #sort_project_by_hot, NoMethodError: #{e}" - [] - end - - def sort_project_by_hot_rails - # @projects_status = ProjectStatus.visible.where("project_statuses.project_type <> ? or project_statuses.project_type is null", 1) - # @projects_status = @projects_status.reorder('grade').all.reverse - # Project.joins(@projects_status).limit(10) - limit = 10 - #Project.find_by_sql("SELECT * FROM projects RIGHT OUTER JOIN (SELECT * FROM project_statuses ORDER BY grade DESC LIMIT #{limit} ) AS t ON projects.id = t.project_id ") - Project.find_by_sql(" - SELECT p.id, p.name, p.description, p.identifier, t.project_id - FROM projects AS p RIGHT OUTER JOIN ( - SELECT project_id,grade FROM project_statuses - WHERE project_type = 0 ORDER BY grade DESC LIMIT #{limit} ) AS t ON p.id = t.project_id ") - end - - - # 判断课程是否结束,快别用,这个定日子的方法有问题 - def course_timeout? project - return true if (project.nil? && project.course_extra.nil?) - courses_year = project.course_extra.time - current_year = Time.now.year - if courses_year >= current_year - return false - elsif (courses_year < current_year) && (Time.now.month < 3) - return false - else - return true - end - end - - def find_project_repository project - unless project.repositories.nil? - project.repositories.each do |repository| - repository.fetch_changesets if Setting.autofetch_changesets? - end - end - end -end +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +include AvatarHelper +module ProjectsHelper + def link_to_version(version, options = {}) + return '' unless version && version.is_a?(Version) + link_to_if version.visible?, format_version_name(version), { :controller => 'versions', :action => 'show', :id => version }, options + end + + def project_settings_tabs + tabs = [{:name => 'info', :action => :edit_project, :partial => 'projects/edit', :label => :label_information_plural}, + {:name => 'modules', :action => :select_project_modules, :partial => 'projects/settings/modules', :label => :label_module_plural}, + {:name => 'members', :action => :manage_members, :partial => 'projects/settings/members', :label => :label_member_plural}, + {:name => 'versions', :action => :manage_versions, :partial => 'projects/settings/versions', :label => :label_version_plural}, + {:name => 'categories', :action => :manage_categories, :partial => 'projects/settings/issue_categories', :label => :label_issue_category_plural}, + # {:name => 'wiki', :action => :manage_wiki, :partial => 'projects/settings/wiki', :label => :label_wiki}, + {:name => 'repositories', :action => :manage_repository, :partial => 'projects/settings/repositories', :label => :label_repository_plural}, + #{:name => 'boards', :action => :manage_boards, :partial => 'projects/settings/boards', :label => :label_board_plural}, + {:name => 'activities', :action => :manage_project_activities, :partial => 'projects/settings/activities', :label => :enumeration_activities} + ] + tabs.select {|tab| User.current.allowed_to?(tab[:action], @project)} + + end + + # added bu huang + def sort_project_enterprise(state, project_type) + content = ''.html_safe + case state + when 0 + + content << content_tag('li', link_to(l(:label_sort_by_active), projects_path(:project_sort_type => '1', :project_type => project_type))) + content << content_tag('li', link_to(l(:label_sort_by_influence), projects_path(:project_sort_type => '2', :project_type => project_type))) + content << content_tag('li', link_to(l(:label_sort_by_time), projects_path(:project_sort_type => '0', :project_type => project_type), :class=>"selected"), :class=>"selected") + when 1 + + content << content_tag('li', link_to(l(:label_sort_by_active), projects_path(:project_sort_type => '1', :project_type => project_type), :class=>"selected"), :class=>"selected") + content << content_tag('li', link_to(l(:label_sort_by_influence), projects_path(:project_sort_type => '2', :project_type => project_type))) + content << content_tag('li', link_to(l(:label_sort_by_time), projects_path(:project_sort_type => '0', :project_type => project_type))) + when 2 + content << content_tag('li', link_to(l(:label_sort_by_active), projects_path(:project_sort_type => '1', :project_type => project_type))) + content << content_tag('li', link_to(l(:label_sort_by_influence), projects_path(:project_sort_type => '2', :project_type => project_type), :class=>"selected"), :class=>"selected") + content << content_tag('li', link_to(l(:label_sort_by_time), projects_path(:project_sort_type => '0', :project_type => project_type))) + end + content = content_tag('ul', content) + content_tag('div', content, :class => "tabs_enterprise") + end + + def sort_course(state, project_type, school_id) + content = ''.html_safe + case state + when 0 + content << content_tag('li', link_to(l(:label_sort_by_time), course_path(:project_sort_type => '0', :project_type => project_type), :school_id => school_id, :class=>"selected"), :class=>"selected") + content << content_tag('li', link_to(l(:label_sort_by_active), course_path(:project_sort_type => '1', :project_type => project_type, :school_id => school_id))) + # content << content_tag('li', link_to(l(:label_sort_by_influence), course_path(:project_sort_type => '2', :project_type => project_type))) + content << content_tag('li', link_to(l(:label_sort_by_activity), course_path(:project_sort_type => '3', :project_type => project_type, :school_id => school_id))) + + when 1 + content << content_tag('li', link_to(l(:label_sort_by_time), course_path(:project_sort_type => '0', :project_type => project_type, :school_id => school_id))) + content << content_tag('li', link_to(l(:label_sort_by_active), course_path(:project_sort_type => '1', :project_type => project_type, :school_id => school_id), :class=>"selected"), :class=>"selected") + # content << content_tag('li', link_to(l(:label_sort_by_influence), course_path(:project_sort_type => '2', :project_type => project_type))) + content << content_tag('li', link_to(l(:label_sort_by_activity), course_path(:project_sort_type => '3', :project_type => project_type, :school_id => school_id))) + + when 2 + content << content_tag('li', link_to(l(:label_sort_by_time), course_path(:project_sort_type => '0', :project_type => project_type, :school_id => school_id))) + content << content_tag('li', link_to(l(:label_sort_by_active), course_path(:project_sort_type => '1', :project_type => project_type, :school_id => school_id))) + # content << content_tag('li', link_to(l(:label_sort_by_influence), course_path(:project_sort_type => '2', :project_type => project_type), :class=>"selected"), :class=>"selected") + content << content_tag('li', link_to(l(:label_sort_by_activity), course_path(:project_sort_type => '3', :project_type => project_type, :school_id => school_id))) + + #gcm + when 3 + content << content_tag('li', link_to(l(:label_sort_by_time), course_path(:project_sort_type => '0', :project_type => project_type, :school_id => school_id))) + content << content_tag('li', link_to(l(:label_sort_by_active), course_path(:project_sort_type => '1', :project_type => project_type, :school_id => school_id))) + # content << content_tag('li', link_to(l(:label_sort_by_influence), course_path(:project_sort_type => '2', :project_type => project_type))) + content << content_tag('li', link_to(l(:label_sort_by_activity), course_path(:project_sort_type => '3', :project_type => project_type, :school_id => school_id), :class=>"selected"), :class=>"selected") + end + #gcmend + + content = content_tag('ul', content) + content_tag('div', content, :class => "tabs") + end + # end + + def sort_project(state, project_type) + content = ''.html_safe + case state + when 0 + + content << content_tag('li', link_to(l(:label_sort_by_active), projects_path(:project_sort_type => '1', :project_type => project_type))) + content << content_tag('li', link_to(l(:label_sort_by_influence), projects_path(:project_sort_type => '2', :project_type => project_type))) + content << content_tag('li', link_to(l(:label_sort_by_time), projects_path(:project_sort_type => '0', :project_type => project_type), :class=>"selected"), :class=>"selected") + when 1 + + content << content_tag('li', link_to(l(:label_sort_by_active), projects_path(:project_sort_type => '1', :project_type => project_type), :class=>"selected"), :class=>"selected") + content << content_tag('li', link_to(l(:label_sort_by_influence), projects_path(:project_sort_type => '2', :project_type => project_type))) + content << content_tag('li', link_to(l(:label_sort_by_time), projects_path(:project_sort_type => '0', :project_type => project_type))) + when 2 + content << content_tag('li', link_to(l(:label_sort_by_active), projects_path(:project_sort_type => '1', :project_type => project_type))) + content << content_tag('li', link_to(l(:label_sort_by_influence), projects_path(:project_sort_type => '2', :project_type => project_type), :class=>"selected"), :class=>"selected") + content << content_tag('li', link_to(l(:label_sort_by_time), projects_path(:project_sort_type => '0', :project_type => project_type))) + end + content = content_tag('ul', content) + content_tag('div', content, :class => "tabs") + end + + # def sort_course(state, project_type) + # content = ''.html_safe + # case state + # when 0 +# + # content << content_tag('li', link_to(l(:label_sort_by_active), course_path(:project_sort_type => '1', :project_type => project_type))) + # content << content_tag('li', link_to(l(:label_sort_by_influence), course_path(:project_sort_type => '2', :project_type => project_type))) + # content << content_tag('li', link_to(l(:label_sort_by_time), course_path(:project_sort_type => '0', :project_type => project_type), :class=>"selected"), :class=>"selected") + # when 1 +# + # content << content_tag('li', link_to(l(:label_sort_by_active), course_path(:project_sort_type => '1', :project_type => project_type), :class=>"selected"), :class=>"selected") + # content << content_tag('li', link_to(l(:label_sort_by_influence), course_path(:project_sort_type => '2', :project_type => project_type))) + # content << content_tag('li', link_to(l(:label_sort_by_time), course_path(:project_sort_type => '0', :project_type => project_type))) + # when 2 + # content << content_tag('li', link_to(l(:label_sort_by_active), course_path(:project_sort_type => '1', :project_type => project_type))) + # content << content_tag('li', link_to(l(:label_sort_by_influence), course_path(:project_sort_type => '2', :project_type => project_type), :class=>"selected"), :class=>"selected") + # content << content_tag('li', link_to(l(:label_sort_by_time), course_path(:project_sort_type => '0', :project_type => project_type))) + # end + # content = content_tag('ul', content) + # content_tag('div', content, :class => "tabs") + # end + + + # Added by young + def course_settings_tabs + tabs = [{:name => 'info', :action => :edit_project, :partial => 'projects/edit', :label => :label_information_plural, :course=>'1'}, + #{:name => 'boards', :action => :manage_boards, :partial => 'projects/settings/boards', :label => :label_board_plural, :project_type => 1}, + # {:name => 'repositories', :action => :manage_repository, :partial => 'projects/settings/repositories', :label => :label_repository_plural}, + {:name => 'members', :action => :manage_members, :partial => 'projects/settings/members', :label => :label_member_plural} + ] + tabs.select {|tab| User.current.allowed_to?(tab[:action], @project)} + end + # Ended by young + + + + + def parent_project_select_tag(project) + selected = project.parent + # retrieve the requested parent project + parent_id = (params[:project] && params[:project][:parent_id]) || params[:parent_id] + if parent_id + selected = (parent_id.blank? ? nil : Project.find(parent_id)) + end + + options = '' + options << "" if project.allowed_parents.include?(nil) + options << project_tree_options_for_select(project.allowed_parents.compact, :selected => selected) + content_tag('select', options.html_safe, :name => 'project[parent_id]', :id => 'project_parent_id') + end + + # Renders the projects index + def render_project_hierarchy(projects) + render_project_nested_lists(projects) do |project| + #Modified by young + if project.try(:project_type) == Project::ProjectType_course + # modified by longjun + # never use unless and else + # unless project.is_public == 1 + if project.is_public != 1 + s = "#{l(:label_private)}".html_safe + else + s = "".html_safe + end + # end longjun + # modified by Longjun + s += link_to_project(project, {}, + :class => "#{project.css_classes} #{User.current.member_of?(project) ? 'my-project' : nil}").html_safe + # end longjun + else + # modified by longjun + # unless project.is_public + if !project.is_public + # end longjun + s = "#{l(:label_private)}".html_safe + else + s = "".html_safe + end + # modified by longjun + s += link_to_project(project, {}, + :class => "#{project.css_classes} #{User.current.member_of?(project) ? 'my-project' : nil}") + # end longjun + end + #Ended by young + if project.description.present? + #Delete by nie. + # s << content_tag('td', textilizable(project.short_description, :project => project), :class => 'wiki description') + end + s + end + end + + # Returns a set of options for a select field, grouped by project. + def version_options_for_select(versions, selected=nil) + grouped = Hash.new {|h,k| h[k] = []} + versions.each do |version| + grouped[version.project.name] << [version.name, version.id] + end + + if grouped.keys.size > 1 + grouped_options_for_select(grouped, selected && selected.id) + else + options_for_select((grouped.values.first || []), selected && selected.id) + end + end + + def format_version_sharing(sharing) + sharing = 'none' unless Version::VERSION_SHARINGS.include?(sharing) + l("label_version_sharing_#{sharing}") + end + + # this method is used to get all projects that tagged one tag + # added by william + def get_projects_by_tag(tag_name) + Project.tagged_with(tag_name).order('updated_on desc') + end + + # added by fq + def homework_type_option + type = [] + option1 = [] + option2 = [] + option1 << l(:label_task_submit_form_accessory) + option1 << 1 + option2 << l(:label_task_submit_form_project) + option2 << 2 + type << option1 + type << option2 + end + + #是否启动互评下拉框 + def is_evaluation_option + type = [] + option1 = [] + option2 = [] + option1 << l(:lable_start_mutual_evaluation) + option1 << 1 + option2 << l(:lable_close_mutual_evaluation) + option2 << 2 + type << option1 + type << option2 + end + + # 用来判断用户是否是项目的管理员 + # added by william + def is_manager?(user_id,project_id) + @result = false + @user_id = ProjectInfo.find_by_project_id(project_id) + + # modified by longjun + # if @user_id == user.id + # @result = true + # end + + @result = true if @user_id = user.id + # end longjun + return @result + end + + # 将动态中类型转换为可读的字符串 + def eventToLanguage event_type + case event_type + when "issue-note" + l :label_issue + when "issue" + l :label_issue + when "attachment" + l :label_attachment + when "news" + l :label_news + else + "" + end + end + + def eventToLanguageCourse event_type, project + case event_type + when "issue-note" + l :label_issue + when "issue" + l :label_issue + when "attachment" + l :label_attachment + when "news" + project.project_type == 1 ? (l :label_notification) : (l :label_news) + else + "" + end + end + + def rolesToLanguage rolesArray + rolesArray = ([] << rolesArray) unless rolesArray.is_a?(Array) + rolesArray.map{ |roleName| + case roleName.to_sym + when :Manager + l :default_role_manager + when :Developer + l :default_role_developer + when :Reporter + l :default_role_reporter + else + 'Unkown' + end + } + end + + def sort_project_by_hot + return sort_project_by_hot_rails + @projects_status = ProjectStatus.visible.where("project_statuses.project_type <> ? or project_statuses.project_type is null", 1) + @projects_status = @projects_status.reorder('grade').all.reverse + @projects = [] + @projects_status.each do |obj| + break if(@projects_status[10] == obj) + @projects << Project.visible.find_by_id("#{obj.project_id}")#where('id=:id', id: obj.project_id) + end + @projects + rescue NoMethodError => e + logger.error "Logger.Error [ProjectsHelper] ===> #sort_project_by_hot, NoMethodError: #{e}" + [] + end + + def sort_project_by_hot_rails + # @projects_status = ProjectStatus.visible.where("project_statuses.project_type <> ? or project_statuses.project_type is null", 1) + # @projects_status = @projects_status.reorder('grade').all.reverse + # Project.joins(@projects_status).limit(10) + limit = 10 + #Project.find_by_sql("SELECT * FROM projects RIGHT OUTER JOIN (SELECT * FROM project_statuses ORDER BY grade DESC LIMIT #{limit} ) AS t ON projects.id = t.project_id ") + Project.find_by_sql(" + SELECT p.id, p.name, p.description, p.identifier, t.project_id + FROM projects AS p RIGHT OUTER JOIN ( + SELECT project_id,grade FROM project_statuses + WHERE project_type = 0 ORDER BY grade DESC LIMIT #{limit} ) AS t ON p.id = t.project_id ") + end + + + # 判断课程是否结束,快别用,这个定日子的方法有问题 + def course_timeout? project + return true if (project.nil? && project.course_extra.nil?) + courses_year = project.course_extra.time + current_year = Time.now.year + if courses_year >= current_year + return false + elsif (courses_year < current_year) && (Time.now.month < 3) + return false + else + return true + end + end + + def find_project_repository project + unless project.repositories.nil? + project.repositories.each do |repository| + repository.fetch_changesets if Setting.autofetch_changesets? + end + end + end +end diff --git a/app/helpers/watchers_helper.rb b/app/helpers/watchers_helper.rb index 155485b4c..166dfd0ec 100644 --- a/app/helpers/watchers_helper.rb +++ b/app/helpers/watchers_helper.rb @@ -64,8 +64,8 @@ module WatchersHelper :object_id => (objects.size == 1 ? objects.first.id : objects.map(&:id).sort) ) method = watched ? 'delete' : 'post' - - link_to text, url, :remote => true, :method => method, :class => css + + link_to text, url, :remote => true, :method => method, :class => css, :onclick => "location.reload()" end # add by nwb diff --git a/app/helpers/welcome_helper.rb b/app/helpers/welcome_helper.rb index 5ada224ae..8de7f4ec4 100644 --- a/app/helpers/welcome_helper.rb +++ b/app/helpers/welcome_helper.rb @@ -1,512 +1,512 @@ -# encoding: utf-8 -# -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -module WelcomeHelper - - include CoursesHelper - include ProjectsHelper - - def get_timestamp(obj) - if obj.respond_to? :updated_on - :updated_on - elsif obj.respond_to? :updated_at - :updated_at - elsif obj.respond_to? :created_on - :created_on - elsif obj.respond_to? :created_at - :created_at - else - Time.now.to_i.to_s.to_sym - end - end - - def cache_key_for_project(obj) - timestamp = get_timestamp(obj) - "welcome_index_project_ul_#{obj.class}_li_#{obj.id}_#{obj.__send__ timestamp}" - end - def cache_key_for_event(obj) - timestamp = get_timestamp(obj) - "welcome_index_event_ul_#{obj.class}_li_#{obj.id}_#{obj.__send__ timestamp}" - end - def cache_key_for_topic(obj) - timestamp = get_timestamp(obj) - "welcome_index_topic_ul_#{obj.class}_li_#{obj.id}_#{obj.__send__ timestamp}" - end - - def welcome_join_in_course(project, user) - if(user.logged? && - !(course_endTime_timeout? project) && - (project.course_extra.teacher.id != user.id) - ) - join_in_course(project, user) - end - end - - def get_course_avatar project - if get_avatar?(project) - url_to_avatar(project) - else - '../images/avatars/Project/course.jpg' - end - end - - def get_project_avatar project - if get_avatar?(project) - url_to_avatar(project) - else - '../images/avatars/Project/0' - end - end - # 前略·天国の首页君/Earth has been unable stop to welcomePage's. - # sum - 要搜索的项目数量 - # max_rate - 新项目所占所有项目的比重,10分制 - # - # Examples - # - # find_miracle_course(10, 7) - # # => 前7个项目为新课程,后面三个是参与人数最多的 - # - # Returns project&courses array - # 原来的取课程逻辑 - def find_miracle_course_base(sum=10, max_rate=7, school_id) - - if User.current.user_extensions.school.nil? and school_id.nil? - Project.active.visible.course_entities. - joins(:course_extra). - joins(:memberships). - group('members.project_id'). - reorder("courses.time DESC, COUNT(members.project_id) DESC").take sum -# elseif school_id.nil? - - else - if school_id.nil? - Project.active.visible.course_entities. - joins(:course_extra). - joins(:memberships). - where("#{Course.table_name}.school_id = ?", User.current.user_extensions.school.id). - group('members.project_id'). - reorder("courses.time DESC, COUNT(members.project_id) DESC").take sum - else - if school_id == "0" - Project.active.visible.course_entities. - joins(:course_extra). - joins(:memberships). - group('members.project_id'). - reorder("courses.time DESC, COUNT(members.project_id) DESC").take sum - else - Project.active.visible.course_entities. - joins(:course_extra). - joins(:memberships). - where("#{Course.table_name}.school_id = ?", school_id). - group('members.project_id'). - reorder("courses.time DESC, COUNT(members.project_id) DESC").take sum - end - end - end -# else -# Project.active.visible.course_entities. -# joins(:course_extra). -# joins(:memberships). -# where("#{Course.table_name}.school_id = ?", school_id). -# group('members.project_id'). -# reorder("courses.time DESC, COUNT(members.project_id) DESC").take sum -# end - # max = sum*(max_rate.to_f/10) - # c1 = find_new_course(sum).to_a.dup - # c2 = find_all_hot_course(sum).to_a.dup - # c2 = c2 - c1 - # (c1.take(max)+c2).take(sum) - end - - #获取课程列表 - # add by nwb - def find_miracle_course(sum=10, max_rate=7, school_id, time,term) - if User.current.user_extensions.nil? && User.current.user_extensions.school.nil? and school_id.nil? - Course.active.visible. - joins(:memberships). - where("courses.time = #{time} and courses.term = #{term}"). - group('members.course_id'). - reorder("courses.created_at DESC, COUNT(members.course_id) DESC").take sum - else - if school_id.nil? - Course.active.visible. - joins(:memberships). - where("#{Course.table_name}.school_id = ? and courses.time = ? and courses.term = ?", User.current.user_extensions.school.id, time, term). - group('members.course_id'). - reorder("COUNT(members.course_id) DESC").take sum - else - if school_id == "0" - Course.active.visible. - joins(:memberships). - where("courses.time = #{time} and courses.term = #{term}"). - group('members.course_id'). - reorder("COUNT(members.course_id) DESC").take sum - else - Course.active.visible. - joins(:memberships). - where("#{Course.table_name}.school_id = ? and courses.time = ? and courses.term = ?", school_id, time, term). - group('members.course_id'). - reorder("COUNT(members.course_id) DESC").take sum - end - end - end -# else -# Project.active.visible.course_entities. -# joins(:course_extra). -# joins(:memberships). -# where("#{Course.table_name}.school_id = ?", school_id). -# group('members.project_id'). -# reorder("courses.time DESC, COUNT(members.project_id) DESC").take sum -# end -# max = sum*(max_rate.to_f/10) -# c1 = find_new_course(sum).to_a.dup -# c2 = find_all_hot_course(sum).to_a.dup -# c2 = c2 - c1 -# (c1.take(max)+c2).take(sum) - end - - #查找所有学校按每个学校开设课程数量降序排序 - #page 分页查询开始条数的编号,从0开始 - #limit 分页查询的数量 - def find_maxmin_course_school page,limit - School.find_by_sql("SELECT *,(SELECT COUNT(*) FROM courses WHERE school_id = schools.id) AS a - FROM schools - ORDER BY a DESC LIMIT #{page},#{limit}") - #School.where(" id IN (SELECT school_id FROM courses GROUP BY school_id)").limit limit; - #School.order("#{School.course_count}").limit(limit).all - #@school = School.all.sort - #@school.each do |s| - # s.courses.count - #end - #result = [] - #@school = School.all.to_ary - #i = 1 - #for i in i < School.count - # j = i - 1 - # for j in j > 0 - # if @school[j].courses.count > - # end - #end - end - - def find_miracle_project(sum, max_rate,order) - #max = sum*(max_rate.to_f/10) - #c1 = find_new_project(sum).to_a.dup - #c2 = find_all_hot_project(sum).to_a.dup - #(c2.take(sum-max)+c1.take(max)).take(sum) - find_all_hot_project(sum,order).to_a.dup - end - - def find_new_course limit=15 - Project.visible.joins(:course_extra).where("#{Project.table_name}.project_type = ? ", 1).order("courses.time DESC, #{Project.table_name}.created_on DESC").limit(limit).all - end - - def find_new_project limit=15 - Project.visible.where("#{Project.table_name}.project_type = ? ", 0).order("#{Project.table_name}.updated_on DESC, #{Project.table_name}.created_on DESC").limit(limit).all - end - - - def find_all_hot_project limit=15,order - sort_project_by_hot limit,order - end - - def find_all_hot_course limit=15 - sort_course_by_hot limit - end - - # modif by nwb - def find_all_new_hot_course limit = 9 ,school_id = nil, year_now, course_term - #sort_project_by_hot_rails 1, 'course_ac_para DESC', limit - #time_now = Time.new.strftime("%Y") - #if school_id - #courses = Course.includes(:school, :members).visible.joins(:course_status).where("#{Course.table_name}.created_at like '%#{time_now}%' and #{Course.table_name}.school_id <> - # ?", school_id).order("course_ac_para DESC").limit(limit).all - #else - # courses = Course.includes(:school, :members).visible.joins(:course_status).where("#{Course.table_name}.created_at like '%#{time_now}%' and #{Course.table_name}.school_id is not NULL - # ").order("course_ac_para DESC").limit(limit).all - # end - school_id.nil? ? - courses = Course.includes(:school, :members).visible. - joins(:memberships). - where("courses.time = ? and courses.term = ? and courses.school_id is not NULL", year_now, course_term). - group('members.course_id'). - reorder("COUNT(members.course_id) DESC").limit(limit).all - : - courses = Course.includes(:school, :members).visible. - joins(:memberships). - where("courses.time = ? and courses.term = ? and courses.school_id <> ?",year_now, course_term, school_id). - group('members.course_id'). - reorder("COUNT(members.course_id) DESC").limit(limit).all - courses - end - - def find_all_hot_bid - sort_bid_by_hot - end - - def find_all_hot_contest limit=10 - Contest.reorder("created_on DESC").all.take limit - # mix_bid = [] - # mix_bid += Contest.reorder("created_on DESC").take(limit).to_a - # mix_bid += Bid.visible.where('reward_type = ?', 2).reorder('bids.created_on desc').take(limit).to_a - # mix_bid.sort do |older, newer| - # newer.created_on - older.created_on - # end - # mix_bid.take limit - end - - def find_all_hot_softapplication limit=10 - Softapplication.reorder("created_at DESC").all.take limit - end - - def cal_memos_count event - return nil if event.parent_id - event.replies_count - rescue NoMethodError - nil - end - - def cal_issues_count event - event.journals.count - rescue NoMethodError - nil - end - - def topic_last_time topic - return topic.event_datetime if ( !(topic.methods.to_s =~ %r[last_reply]) || topic.last_reply.nil? ) - topic.last_reply.event_datetime - end - - - def time_tag_welcome time - text = distance_of_time_in_words(Time.now, time) - content_tag('span', text, :title => format_time(time)) - end - - def show_grade project - grade = 0 - begin - #ActiveRecord::Base.connection.execute("CALL sp_project_status_cursor();")#执行存储过程速度慢 - grade = project.project_status.grade if project && project.project_status - rescue Exception => e - logger.error "Logger.Error [WelcomeHelper] ===> #{e}" - end - "项目评分:".html_safe << grade.to_s - end - - def show_user_content event - str = ' '.html_safe - case event.event_type - when 'news' - str << content_tag("span", "发表了") << - content_tag("span", find_all_event_type(event)) << - ': '.html_safe << - link_to(strip_tags(event.event_description).gsub(/ /,''), event.event_url) - when 'issue', 'message' , 'bid' , 'wiki-page' , 'document' - str << content_tag("span", "发表了") << - content_tag("span", find_all_event_type(event)) << - ': '.html_safe << - link_to(event.event_title, event.event_url) - when 'reply' ,'Reply', 'Memo' - str << content_tag("span", "发表了") << - content_tag("span", find_all_event_type(event)) << - ': '.html_safe << - link_to(strip_tags(event.event_description).gsub(/ /,''), event.event_url) - when 'attachment' - str << content_tag('span', '上传了') << - content_tag('span', find_all_event_type(event)) << - ': '.html_safe << - link_to(event.event_title, event.event_url) << - link_to((' ['.html_safe+l(:label_downloads_list).to_s << ']'), project_files_path(event.container.project), :class => "attachments_list_color") - else - str << content_tag("span", "更新了") << - content_tag("span", find_all_event_type(event)) << - ': '.html_safe << link_to(event.event_title, event.event_url) - end - str - rescue Exception => e - str << content_tag("span", '未知内容') - end - - def show_event_reply event - str = "回复(" - case event.event_type - when 'news' - str << link_to( event.comments.count, news_path(event)) << ")" - when "issue" - str << link_to(cal_issues_count(event), issue_path(event)) << ")" - when "Memo" - str << link_to(cal_memos_count(event), forum_memo_path(event.forum_id,event.id)) << ")" - else - str = "" - end - str.html_safe - end - - def find_new_forum_topics limit=7 - # Memo.where('memos.parent_id IS NULL').reorder('memos.created_at DESC').limit(limit) - # activity = Redmine::Activity::Fetcher.new(nil) - # activity.scope=['memos'] - # activity.events_welcome(nil, nil, {:limit => limit}) - - resultSet = Memo.where('memos.parent_id IS NULL').includes(:last_reply).order('COALESCE (last_replies_memos.created_at, memos.created_at) DESC').limit(limit) - # resultSet += Message.where('messages.parent_id IS NULL').includes(:last_reply).order('COALESCE (last_replies_messages.created_on, messages.created_on) DESC').limit(limit) - - # resultSet = Memo.includes(:children).where('parent_id IS NULL').order('updated_at DESC').limit(limit) - # resultSet += Message.includes(:children).where('parent_id IS NULL').order('updated_on DESC').limit(limit) - # resultSet.sort! {|x,y| y.event_datetime <=> x.event_datetime} - # resultSet = resultSet.to_a - # for i in 0..(resultSet.size-1) - # resultSet[i] = resultSet[i].children.last if resultSet[i].children.count > 0 - # end - # resultSet.take(limit) - end - - private - - def sort_project_by_hot limit=15,order - #'grade DESC' - sort_project_by_hot_rails 0,order , limit - end - - def sort_course_by_hot limit=15 - sort_project_by_hot_rails 1, 'course_ac_para DESC', limit - end - - def sort_bid_by_hot - sort_bid_by_hot_rails 1 - end - - def sort_contest_by_hot - sort_bid_by_hot_rails 2 - end -#new added by linchun - def sort_contest_by_time - sort_bid_by_time 2 - end - - #取得所有活动 - def find_all_activities limit=6 - # users = [] - # activities = Activity.find_by_sql("select distinct user_id from activities order by id DESC limit #{limit}" ) - # activities.each { |activity| - # users << activity.user_id - # } - # user_objs = User.find_by_sql("SELECT * FROM users WHERE (users.id IN #{"(" << users.join(',') << ")"} )") - activity = Redmine::Activity::Fetcher.new(nil) - has = { # TODO: 待完成 - "show_issues" => true, - "show_files" => true, - "show_documents" => true, - "show_messages" => true, - "show_news" => true, - "show_bids" => true, - "show_contest" => true - } - activity.scope_select{|t| ['changesets', 'documents', 'memos', 'messages', 'journals_for_messages', 'bids', 'news', 'contestnotification'].include?(t) ? - nil : 'You may think you know what the following code does, may be. but why don"t you close this file and go play with something else, Now?' } - activity.events_welcome(nil, nil, {:limit => limit, :types => 'welcome'}) - end - - #取得论坛数据 - def find_hot_forum_topics limit=9 - ## 以下语句会内链接自身查询出最后一条回复时间,没有回复的帖子不会显示 - # Memo.find_by_sql(" - # SELECT memos.*, reply.created_at AS last_reply_date FROM memos AS memos - # INNER JOIN memos - # AS reply ON memos.last_reply_id=reply.id - # WHERE memos.parent_id IS NULL - # ORDER BY memos.replies_count DESC, memos.created_at DESC - # LIMIT #{limit}") - - #Memo.order('replies_count DESC').where('replies_count <> 0').limit(limit) - - resultSet = Memo.order('replies_count DESC, created_at DESC').where('parent_id IS NULL').limit(limit) - resultSet += Message.order('replies_count DESC, created_on DESC').where('parent_id IS NULL').limit(limit) - resultSet.sort! {|x,y| (y.replies_count <=> x.replies_count).nonzero? || (y.event_datetime <=> x.event_datetime)} - resultSet.take(limit) - end - - def sort_project_by_hot_rails project_type=0, order_by='score DESC', limit=15 - # Project.find_by_sql(" - # SELECT p.id, p.name, p.description, p.identifier, t.project_id - # FROM projects AS p LEFT OUTER JOIN ( - # SELECT project_id,grade FROM project_statuses - # WHERE project_type = #{project_type} ORDER BY #{order_by} LIMIT #{limit} ) AS t ON p.id = t.project_id ") - Project.visible.joins(:project_status).joins("LEFT JOIN #{ProjectScore.table_name} ON #{Project.table_name}.id = #{ProjectScore.table_name}.project_id").where("#{Project.table_name}.project_type = ?", project_type).order(order_by).limit(limit).all - end - - def sort_bid_by_hot_rails reward_type, limit = 10 - Bid.visible.where('reward_type = ?', reward_type).reorder('bids.commit desc').limit(limit) - end - - def sort_bid_by_time reward_type, limit = 10 - Bid.visible.where('reward_type = ?', reward_type).reorder('bids.created_on desc').limit(limit) - end - - def find_all_event_type event - case event.event_type - when 'news' - '新闻' - when 'issue' - '缺陷' - when 'attachment' - '附件' - when 'message' - '主题' - when 'Reply','reply' - '回复' - when 'bid' - '作业' - when 'Memo' - '主题' - when 'document' - '文件' - when 'changeset' - '版本库' - when 'issue-note' - '问题说明' - else - event.event_type - end - end - - def newbie_send_path - create_new_forum_path '新手讨论' - end - def suggestion_send_path - create_new_forum_path '网站建议' - end - - private - - def create_new_forum_path name - # 没有论坛则返回'#' 不能发帖 - # 否则到指定论坛里发帖 - # 没有找到置顶论坛就跑默认第一个论坛发帖 - forum_relation = create_find_undefine_forum name - backUrl = '#' - backUrl = new_forum_memo_path(Forum.first) if Forum.count > 0 - backUrl = new_forum_memo_path(forum_relation.first) if !forum_relation.empty? - return backUrl - end - def create_find_undefine_forum name - Forum.where("name LIKE \'%#{name}%\'") - end -end +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module WelcomeHelper + + include CoursesHelper + include ProjectsHelper + + def get_timestamp(obj) + if obj.respond_to? :updated_on + :updated_on + elsif obj.respond_to? :updated_at + :updated_at + elsif obj.respond_to? :created_on + :created_on + elsif obj.respond_to? :created_at + :created_at + else + Time.now.to_i.to_s.to_sym + end + end + + def cache_key_for_project(obj) + timestamp = get_timestamp(obj) + "welcome_index_project_ul_#{obj.class}_li_#{obj.id}_#{obj.__send__ timestamp}" + end + def cache_key_for_event(obj) + timestamp = get_timestamp(obj) + "welcome_index_event_ul_#{obj.class}_li_#{obj.id}_#{obj.__send__ timestamp}" + end + def cache_key_for_topic(obj) + timestamp = get_timestamp(obj) + "welcome_index_topic_ul_#{obj.class}_li_#{obj.id}_#{obj.__send__ timestamp}" + end + + def welcome_join_in_course(project, user) + if(user.logged? && + !(course_endTime_timeout? project) && + (project.course_extra.teacher.id != user.id) + ) + join_in_course(project, user) + end + end + + def get_course_avatar project + if get_avatar?(project) + url_to_avatar(project) + else + '../images/avatars/Project/course.jpg' + end + end + + def get_project_avatar project + if get_avatar?(project) + url_to_avatar(project) + else + '../images/avatars/Project/0' + end + end + # 前略·天国の首页君/Earth has been unable stop to welcomePage's. + # sum - 要搜索的项目数量 + # max_rate - 新项目所占所有项目的比重,10分制 + # + # Examples + # + # find_miracle_course(10, 7) + # # => 前7个项目为新课程,后面三个是参与人数最多的 + # + # Returns project&courses array + # 原来的取课程逻辑 + def find_miracle_course_base(sum=10, max_rate=7, school_id) + + if User.current.user_extensions.school.nil? and school_id.nil? + Project.active.visible.course_entities. + joins(:course_extra). + joins(:memberships). + group('members.project_id'). + reorder("courses.time DESC, COUNT(members.project_id) DESC").take sum +# elseif school_id.nil? + + else + if school_id.nil? + Project.active.visible.course_entities. + joins(:course_extra). + joins(:memberships). + where("#{Course.table_name}.school_id = ?", User.current.user_extensions.school.id). + group('members.project_id'). + reorder("courses.time DESC, COUNT(members.project_id) DESC").take sum + else + if school_id == "0" + Project.active.visible.course_entities. + joins(:course_extra). + joins(:memberships). + group('members.project_id'). + reorder("courses.time DESC, COUNT(members.project_id) DESC").take sum + else + Project.active.visible.course_entities. + joins(:course_extra). + joins(:memberships). + where("#{Course.table_name}.school_id = ?", school_id). + group('members.project_id'). + reorder("courses.time DESC, COUNT(members.project_id) DESC").take sum + end + end + end +# else +# Project.active.visible.course_entities. +# joins(:course_extra). +# joins(:memberships). +# where("#{Course.table_name}.school_id = ?", school_id). +# group('members.project_id'). +# reorder("courses.time DESC, COUNT(members.project_id) DESC").take sum +# end + # max = sum*(max_rate.to_f/10) + # c1 = find_new_course(sum).to_a.dup + # c2 = find_all_hot_course(sum).to_a.dup + # c2 = c2 - c1 + # (c1.take(max)+c2).take(sum) + end + + #获取课程列表 + # add by nwb + def find_miracle_course(sum=10, max_rate=7, school_id, time,term) + if User.current.user_extensions.nil? && User.current.user_extensions.school.nil? and school_id.nil? + Course.active.visible. + joins(:memberships). + where("courses.time = #{time} and courses.term = #{term}"). + group('members.course_id'). + reorder("courses.created_at DESC, COUNT(members.course_id) DESC").take sum + else + if school_id.nil? + Course.active.visible. + joins(:memberships). + where("#{Course.table_name}.school_id = ? and courses.time = ? and courses.term = ?", User.current.user_extensions.school.id, time, term). + group('members.course_id'). + reorder("COUNT(members.course_id) DESC").take sum + else + if school_id == "0" + Course.active.visible. + joins(:memberships). + where("courses.time = #{time} and courses.term = #{term}"). + group('members.course_id'). + reorder("COUNT(members.course_id) DESC").take sum + else + Course.active.visible. + joins(:memberships). + where("#{Course.table_name}.school_id = ? and courses.time = ? and courses.term = ?", school_id, time, term). + group('members.course_id'). + reorder("COUNT(members.course_id) DESC").take sum + end + end + end +# else +# Project.active.visible.course_entities. +# joins(:course_extra). +# joins(:memberships). +# where("#{Course.table_name}.school_id = ?", school_id). +# group('members.project_id'). +# reorder("courses.time DESC, COUNT(members.project_id) DESC").take sum +# end +# max = sum*(max_rate.to_f/10) +# c1 = find_new_course(sum).to_a.dup +# c2 = find_all_hot_course(sum).to_a.dup +# c2 = c2 - c1 +# (c1.take(max)+c2).take(sum) + end + + #查找所有学校按每个学校开设课程数量降序排序 + #page 分页查询开始条数的编号,从0开始 + #limit 分页查询的数量 + def find_maxmin_course_school page,limit + School.find_by_sql("SELECT *,(SELECT COUNT(*) FROM courses WHERE school_id = schools.id) AS a + FROM schools + ORDER BY a DESC LIMIT #{page},#{limit}") + #School.where(" id IN (SELECT school_id FROM courses GROUP BY school_id)").limit limit; + #School.order("#{School.course_count}").limit(limit).all + #@school = School.all.sort + #@school.each do |s| + # s.courses.count + #end + #result = [] + #@school = School.all.to_ary + #i = 1 + #for i in i < School.count + # j = i - 1 + # for j in j > 0 + # if @school[j].courses.count > + # end + #end + end + + def find_miracle_project(sum, max_rate,order) + #max = sum*(max_rate.to_f/10) + #c1 = find_new_project(sum).to_a.dup + #c2 = find_all_hot_project(sum).to_a.dup + #(c2.take(sum-max)+c1.take(max)).take(sum) + find_all_hot_project(sum,order).to_a.dup + end + + def find_new_course limit=15 + Project.visible.joins(:course_extra).where("#{Project.table_name}.project_type = ? ", 1).order("courses.time DESC, #{Project.table_name}.created_on DESC").limit(limit).all + end + + def find_new_project limit=15 + Project.visible.where("#{Project.table_name}.project_type = ? ", 0).order("#{Project.table_name}.updated_on DESC, #{Project.table_name}.created_on DESC").limit(limit).all + end + + + def find_all_hot_project limit=15,order + sort_project_by_hot limit,order + end + + def find_all_hot_course limit=15 + sort_course_by_hot limit + end + + # modif by nwb + def find_all_new_hot_course limit = 9 ,school_id = nil, year_now, course_term + #sort_project_by_hot_rails 1, 'course_ac_para DESC', limit + #time_now = Time.new.strftime("%Y") + #if school_id + #courses = Course.includes(:school, :members).visible.joins(:course_status).where("#{Course.table_name}.created_at like '%#{time_now}%' and #{Course.table_name}.school_id <> + # ?", school_id).order("course_ac_para DESC").limit(limit).all + #else + # courses = Course.includes(:school, :members).visible.joins(:course_status).where("#{Course.table_name}.created_at like '%#{time_now}%' and #{Course.table_name}.school_id is not NULL + # ").order("course_ac_para DESC").limit(limit).all + # end + school_id.nil? ? + courses = Course.includes(:school, :members).visible. + joins(:memberships). + where("courses.time = ? and courses.term = ? and courses.school_id is not NULL", year_now, course_term). + group('members.course_id'). + reorder("COUNT(members.course_id) DESC").limit(limit).all + : + courses = Course.includes(:school, :members).visible. + joins(:memberships). + where("courses.time = ? and courses.term = ? and courses.school_id <> ?",year_now, course_term, school_id). + group('members.course_id'). + reorder("COUNT(members.course_id) DESC").limit(limit).all + courses + end + + def find_all_hot_bid + sort_bid_by_hot + end + + def find_all_hot_contest limit=10 + Contest.reorder("created_on DESC").all.take limit + # mix_bid = [] + # mix_bid += Contest.reorder("created_on DESC").take(limit).to_a + # mix_bid += Bid.visible.where('reward_type = ?', 2).reorder('bids.created_on desc').take(limit).to_a + # mix_bid.sort do |older, newer| + # newer.created_on - older.created_on + # end + # mix_bid.take limit + end + + def find_all_hot_softapplication limit=10 + Softapplication.reorder("created_at DESC").all.take limit + end + + def cal_memos_count event + return nil if event.parent_id + event.replies_count + rescue NoMethodError + nil + end + + def cal_issues_count event + event.journals.count + rescue NoMethodError + nil + end + + def topic_last_time topic + return topic.event_datetime if ( !(topic.methods.to_s =~ %r[last_reply]) || topic.last_reply.nil? ) + topic.last_reply.event_datetime + end + + + def time_tag_welcome time + text = distance_of_time_in_words(Time.now, time) + content_tag('span', text, :title => format_time(time)) + end + + def show_grade project + grade = 0 + begin + #ActiveRecord::Base.connection.execute("CALL sp_project_status_cursor();")#执行存储过程速度慢 + grade = project.project_status.grade if project && project.project_status + rescue Exception => e + logger.error "Logger.Error [WelcomeHelper] ===> #{e}" + end + "项目评分:".html_safe << grade.to_s + end + + def show_user_content event + str = ' '.html_safe + case event.event_type + when 'news' + str << content_tag("span", "发表了") << + content_tag("span", find_all_event_type(event)) << + ': '.html_safe << + link_to(strip_tags(event.event_description).gsub(/ /,''), event.event_url) + when 'issue', 'message' , 'bid' , 'wiki-page' , 'document' + str << content_tag("span", "发表了") << + content_tag("span", find_all_event_type(event)) << + ': '.html_safe << + link_to(event.event_title, event.event_url) + when 'reply' ,'Reply', 'Memo' + str << content_tag("span", "发表了") << + content_tag("span", find_all_event_type(event)) << + ': '.html_safe << + link_to(strip_tags(event.event_description).gsub(/ /,''), event.event_url) + when 'attachment' + str << content_tag('span', '上传了') << + content_tag('span', find_all_event_type(event)) << + ': '.html_safe << + link_to(event.event_title, event.event_url) << + link_to((' ['.html_safe+l(:label_downloads_list).to_s << ']'), project_files_path(event.container.project), :class => "attachments_list_color") + else + str << content_tag("span", "更新了") << + content_tag("span", find_all_event_type(event)) << + ': '.html_safe << link_to(event.event_title, event.event_url) + end + str + rescue Exception => e + str << content_tag("span", '未知内容') + end + + def show_event_reply event + str = "回复(" + case event.event_type + when 'news' + str << link_to( event.comments.count, news_path(event)) << ")" + when "issue" + str << link_to(cal_issues_count(event), issue_path(event)) << ")" + when "Memo" + str << link_to(cal_memos_count(event), forum_memo_path(event.forum_id,event.id)) << ")" + else + str = "" + end + str.html_safe + end + + def find_new_forum_topics limit=7 + # Memo.where('memos.parent_id IS NULL').reorder('memos.created_at DESC').limit(limit) + # activity = Redmine::Activity::Fetcher.new(nil) + # activity.scope=['memos'] + # activity.events_welcome(nil, nil, {:limit => limit}) + + resultSet = Memo.where('memos.parent_id IS NULL').includes(:last_reply).order('COALESCE (last_replies_memos.created_at, memos.created_at) DESC').limit(limit) + # resultSet += Message.where('messages.parent_id IS NULL').includes(:last_reply).order('COALESCE (last_replies_messages.created_on, messages.created_on) DESC').limit(limit) + + # resultSet = Memo.includes(:children).where('parent_id IS NULL').order('updated_at DESC').limit(limit) + # resultSet += Message.includes(:children).where('parent_id IS NULL').order('updated_on DESC').limit(limit) + # resultSet.sort! {|x,y| y.event_datetime <=> x.event_datetime} + # resultSet = resultSet.to_a + # for i in 0..(resultSet.size-1) + # resultSet[i] = resultSet[i].children.last if resultSet[i].children.count > 0 + # end + # resultSet.take(limit) + end + + private + + def sort_project_by_hot limit=15,order + #'grade DESC' + sort_project_by_hot_rails 0,order , limit + end + + def sort_course_by_hot limit=15 + sort_project_by_hot_rails 1, 'course_ac_para DESC', limit + end + + def sort_bid_by_hot + sort_bid_by_hot_rails 1 + end + + def sort_contest_by_hot + sort_bid_by_hot_rails 2 + end +#new added by linchun + def sort_contest_by_time + sort_bid_by_time 2 + end + + #取得所有活动 + def find_all_activities limit=6 + # users = [] + # activities = Activity.find_by_sql("select distinct user_id from activities order by id DESC limit #{limit}" ) + # activities.each { |activity| + # users << activity.user_id + # } + # user_objs = User.find_by_sql("SELECT * FROM users WHERE (users.id IN #{"(" << users.join(',') << ")"} )") + activity = Redmine::Activity::Fetcher.new(nil) + has = { # TODO: 待完成 + "show_issues" => true, + "show_files" => true, + "show_documents" => true, + "show_messages" => true, + "show_news" => true, + "show_bids" => true, + "show_contest" => true + } + activity.scope_select{|t| ['changesets', 'documents', 'memos', 'messages', 'journals_for_messages', 'bids', 'news', 'contestnotification'].include?(t) ? + nil : 'You may think you know what the following code does, may be. but why don"t you close this file and go play with something else, Now?' } + activity.events_welcome(nil, nil, {:limit => limit, :types => 'welcome'}) + end + + #取得论坛数据 + def find_hot_forum_topics limit=9 + ## 以下语句会内链接自身查询出最后一条回复时间,没有回复的帖子不会显示 + # Memo.find_by_sql(" + # SELECT memos.*, reply.created_at AS last_reply_date FROM memos AS memos + # INNER JOIN memos + # AS reply ON memos.last_reply_id=reply.id + # WHERE memos.parent_id IS NULL + # ORDER BY memos.replies_count DESC, memos.created_at DESC + # LIMIT #{limit}") + + #Memo.order('replies_count DESC').where('replies_count <> 0').limit(limit) + + resultSet = Memo.order('replies_count DESC, created_at DESC').where('parent_id IS NULL').limit(limit) + resultSet += Message.order('replies_count DESC, created_on DESC').where('parent_id IS NULL').limit(limit) + resultSet.sort! {|x,y| (y.replies_count <=> x.replies_count).nonzero? || (y.event_datetime <=> x.event_datetime)} + resultSet.take(limit) + end + + def sort_project_by_hot_rails project_type=0, order_by='score DESC', limit=15 + # Project.find_by_sql(" + # SELECT p.id, p.name, p.description, p.identifier, t.project_id + # FROM projects AS p LEFT OUTER JOIN ( + # SELECT project_id,grade FROM project_statuses + # WHERE project_type = #{project_type} ORDER BY #{order_by} LIMIT #{limit} ) AS t ON p.id = t.project_id ") + Project.visible.joins(:project_status).joins("LEFT JOIN #{ProjectScore.table_name} ON #{Project.table_name}.id = #{ProjectScore.table_name}.project_id").where("#{Project.table_name}.project_type = ?", project_type).order(order_by).limit(limit).all + end + + def sort_bid_by_hot_rails reward_type, limit = 10 + Bid.visible.where('reward_type = ?', reward_type).reorder('bids.commit desc').limit(limit) + end + + def sort_bid_by_time reward_type, limit = 10 + Bid.visible.where('reward_type = ?', reward_type).reorder('bids.created_on desc').limit(limit) + end + + def find_all_event_type event + case event.event_type + when 'news' + '新闻' + when 'issue' + '缺陷' + when 'attachment' + '附件' + when 'message' + '主题' + when 'Reply','reply' + '回复' + when 'bid' + '作业' + when 'Memo' + '主题' + when 'document' + '文件' + when 'changeset' + '版本库' + when 'issue-note' + '问题说明' + else + event.event_type + end + end + + def newbie_send_path + create_new_forum_path '新手讨论' + end + def suggestion_send_path + create_new_forum_path '网站建议' + end + + private + + def create_new_forum_path name + # 没有论坛则返回'#' 不能发帖 + # 否则到指定论坛里发帖 + # 没有找到置顶论坛就跑默认第一个论坛发帖 + forum_relation = create_find_undefine_forum name + backUrl = '#' + backUrl = new_forum_memo_path(Forum.first) if Forum.count > 0 + backUrl = new_forum_memo_path(forum_relation.first) if !forum_relation.empty? + return backUrl + end + def create_find_undefine_forum name + Forum.where("name LIKE \'%#{name}%\'") + end +end diff --git a/app/models/activity.rb b/app/models/activity.rb index 4676ca7b8..e871ae735 100644 --- a/app/models/activity.rb +++ b/app/models/activity.rb @@ -1,8 +1,8 @@ -class Activity < ActiveRecord::Base - attr_accessible :act_id, :act_type, :user_id - belongs_to :act, :polymorphic => true - belongs_to :user - validates :act_id, presence: true - validates :act_type, presence: true - validates :user_id, presence: true -end +class Activity < ActiveRecord::Base + attr_accessible :act_id, :act_type, :user_id + belongs_to :act, :polymorphic => true + belongs_to :user + validates :act_id, presence: true + validates :act_type, presence: true + validates :user_id, presence: true +end diff --git a/app/models/attachment.rb b/app/models/attachment.rb index a0012492d..de7912667 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -1,532 +1,532 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -require "digest/md5" -require "fileutils" - -class Attachment < ActiveRecord::Base - belongs_to :container, :polymorphic => true - belongs_to :project, foreign_key: 'container_id', conditions: "attachments.container_type = 'Project'" - belongs_to :course, foreign_key: 'container_id', conditions: "attachments.container_type = 'Course'" - belongs_to :softapplication, foreign_key: 'container_id', conditions: "attachments.container_type = 'Softapplication'" - belongs_to :author, :class_name => "User", :foreign_key => "author_id" - belongs_to :attachmentstype, :foreign_key => "attachtype",:primary_key => "id" - - include UserScoreHelper - - validates :filename, presence: true, length: {maximum: 254} - validates :author, presence: true - validates :disk_filename, length: {maximum: 254} - validates :description, length: {maximum: 254} - validate :validate_max_file_size - - - acts_as_taggable - acts_as_event :title => :filename, - :url => Proc.new {|o| {:controller => 'attachments', :action => 'download', :id => o.id, :filename => o.filename}} - - #课程资源文件 - acts_as_activity_provider :type => 'course_files', - :is_public => 'attachments.is_public', - :permission => :view_files, - :author_key => :author_id, - :find_options => {:select => "#{Attachment.table_name}.*", - :joins => "LEFT JOIN #{Course.table_name} ON ( #{Attachment.table_name}.container_type='Course' AND #{Attachment.table_name}.container_id = #{Course.table_name}.id )"} - - acts_as_activity_provider :type => 'files', - :is_public => 'attachments.is_public', - :permission => :view_files, - :author_key => :author_id, - :find_options => { :select => "#{Attachment.table_name}.*", - :joins => "LEFT JOIN #{Version.table_name} ON #{Attachment.table_name}.container_type='Version' AND #{Version.table_name}.id = #{Attachment.table_name}.container_id " + - "LEFT JOIN #{Project.table_name} ON #{Version.table_name}.project_id = #{Project.table_name}.id OR ( #{Attachment.table_name}.container_type='Project' AND #{Attachment.table_name}.container_id = #{Project.table_name}.id )"} - - acts_as_activity_provider :type => 'documents', - :is_public => 'documents.is_public', - :permission => :view_documents, - :author_key => :author_id, - :find_options => {:select => "#{Attachment.table_name}.*", - :joins => "LEFT JOIN #{Document.table_name} ON #{Attachment.table_name}.container_type='Document' AND #{Document.table_name}.id = #{Attachment.table_name}.container_id " + - "LEFT JOIN #{Project.table_name} ON #{Document.table_name}.project_id = #{Project.table_name}.id"} - - cattr_accessor :storage_path - @@storage_path = Redmine::Configuration['attachments_storage_path'] || File.join(Rails.root, "files") - - cattr_accessor :thumbnails_storage_path - @@thumbnails_storage_path = File.join(Rails.root, "tmp", "thumbnails") - - before_save :files_to_final_location - after_create :be_user_score # user_score - after_update :be_user_score - after_destroy :delete_from_disk,:down_user_score - - # add by nwb - # 获取所有可公开的资源文件列表 - scope :public_attachments, lambda { - #joins(Project.table_name).where("container_type = 'Project' and ") - joins("LEFT JOIN #{Project.table_name} ON #{Attachment.table_name}.container_type='Project' AND #{Project.table_name}.id = #{Attachment.table_name}.container_id and #{Project.table_name}.is_public=1 " + - " LEFT JOIN #{Document.table_name} ON #{Attachment.table_name}.container_type='Project' AND #{Document.table_name}.project_id in "+self.public_project_id + - " LEFT JOIN #{Issue.table_name} ON #{Attachment.table_name}.container_type='Project' AND #{Issue.table_name}.project_id in "+self.public_project_id + - " LEFT JOIN #{Version.table_name} ON #{Attachment.table_name}.container_type='Project' AND #{Version.table_name}.project_id in "+self.public_project_id + - " LEFT JOIN #{WikiPage.table_name} ON #{Attachment.table_name}.container_type='WikiPage' AND #{WikiPage.table_name}.parent_id in "+self.public_wiki_id + - " LEFT JOIN #{Message.table_name} ON #{Attachment.table_name}.container_type='Message' AND #{Message.table_name}.parent_id in "+self.public_board_id + - " LEFT JOIN #{Course.table_name} ON #{Attachment.table_name}.container_type='Course' AND #{Course.table_name}.is_public=1 " + - " LEFT JOIN #{News.table_name} ON #{Attachment.table_name}.container_type='News' AND (#{News.table_name}.project_id in "+self.public_project_id + " OR #{News.table_name}.course_id in " + self.public_course_id + ")" + - " LEFT JOIN #{HomeworkAttach.table_name} ON #{Attachment.table_name}.container_type='HomeworkAttach' AND #{HomeworkAttach.table_name}.bid_id in "+self.public_bid_id) - } - - # add by nwb - # 公开的项目id列表 - def self.public_project_id - idlist = "(" - projects=Project.all_public - count = projects.count - for i in 0...count - project = projects[i] - idlist+="'" + project.id.to_s + "'" - if i != count-1 - idlist+="," - end - end - idlist += ")" - idlist - end - - # add by nwb - # 公开的课程id列表 - def self.public_course_id - idlist = "(" - courses=Course.all_public - count = courses.count - for i in 0...count - course = courses[i] - idlist+="'" + course.id.to_s + "'" - if i != count-1 - idlist = idlist + "," - end - end - idlist += ")" - idlist - end - - # add by nwb - # 公开的wiki id列表 - def self.public_wiki_id - idlist = "(" - wikis=Wiki.where("project_id in " + public_project_id) - count = wikis.count - for i in 0...count - wiki = wikis[i] - idlist+="'" + wiki.id.to_s + "'" - if i != count-1 - idlist = idlist + "," - end - end - idlist += ")" - idlist - end - - # add by nwb - # 公开的board id列表 - def self.public_board_id - idlist = "(" - boards=Board.where("project_id in " + public_project_id + " or course_id in " + public_course_id) - count = boards.count - for i in 0...count - board = boards[i] - idlist+="'" + board.id.to_s + "'" - if i != count-1 - idlist = idlist + "," - end - end - idlist += ")" - idlist - end - - # add by nwb - # 公开的bid id列表 - def self.public_bid_id - idlist = "(" - bids=Bid.where("reward_type=3") - count = bids.count - for i in 0...count - bid = bids[i] - idlist+="'" + bid.id.to_s + "'" - if i != count-1 - idlist = idlist + "," - end - end - idlist += ")" - idlist - end - - # Returns an unsaved copy of the attachment - def copy(attributes=nil) - copy = self.class.new - copy.attributes = self.attributes.dup.except("id", "downloads") - copy.attributes = attributes if attributes - copy - end - - #获取资源的后缀类型 - def suffix_type - childArr = self.filename.split('.') - suffix = '*' - if childArr.length > 1 - suffix = childArr[childArr.length-1] - end - suffix - end - - #获取用来显示的后缀名称 - def show_suffix_type - suffix = 'other' - temp = self.suffix_type.downcase - if self.attachmentstype && self.attachmentstype.suffixArr.include?(temp) - suffix = temp - end - suffix - end - - # 文件密级的字符描述 - def file_dense_str - if self.is_public == 1 - dense = l(:field_is_public) - else - dense = l(:field_is_private) - end - dense - end - - # 文件可设置的密级列表 - def file_dense_list - denselist = [l(:field_is_public),l(:field_is_private)] - end - - def suffixArr - @@SuffixArr - end - - def validate_max_file_size - if @temp_file && self.filesize > Setting.attachment_max_size.to_i.kilobytes - errors.add(:base, l(:error_attachment_too_big, :max_size => Setting.attachment_max_size.to_i.kilobytes)) - end - end - - def file=(incoming_file) - unless incoming_file.nil? - @temp_file = incoming_file - # 允许上传文件大小为0的文件 - #if @temp_file.size > 0 - if @temp_file.respond_to?(:original_filename) - self.filename = @temp_file.original_filename - self.filename.force_encoding("UTF-8") if filename.respond_to?(:force_encoding) - end - if @temp_file.respond_to?(:content_type) - self.content_type = @temp_file.content_type.to_s.chomp - end - if content_type.blank? && filename.present? - self.content_type = Redmine::MimeType.of(filename) - end - self.filesize = @temp_file.size - #end - end - end - - def file - nil - end - - def filename=(arg) - write_attribute :filename, sanitize_filename(arg.to_s) - filename - end - - # Copies the temporary file to its final location - # and computes its MD5 hash - def files_to_final_location - # # 允许上传文件大小为0的文件 - if @temp_file# && (@temp_file.size > 0) - self.disk_directory = target_directory - self.disk_filename = Attachment.disk_filename(filename, disk_directory) - logger.info("Saving attachment '#{self.diskfile}' (#{@temp_file.size} bytes)") - path = File.dirname(diskfile) - unless File.directory?(path) - FileUtils.mkdir_p(path) - end - md5 = Digest::MD5.new - File.open(diskfile, "wb") do |f| - if @temp_file.respond_to?(:read) - buffer = "" - while (buffer = @temp_file.read(8192)) - f.write(buffer) - md5.update(buffer) - end - else - f.write(@temp_file) - md5.update(@temp_file) - end - end - self.digest = md5.hexdigest - end - @temp_file = nil - # Don't save the content type if it's longer than the authorized length - if self.content_type && self.content_type.length > 255 - self.content_type = nil - end - end - - # Deletes the file from the file system if it's not referenced by other attachments - def delete_from_disk - if Attachment.where("disk_filename = ? AND id <> ?", disk_filename, id).empty? - delete_from_disk! - end - end - - # Returns file's location on disk - def diskfile - File.join(self.class.storage_path, disk_directory.to_s, disk_filename.to_s) - end - - #标题 - def title - title = filename.to_s - if description.present? - title << " (#{description})" - end - title - end - - def increment_download - increment!(:downloads) - end - - def project - container.try(:project) - end - - def course - container - end - - def visible?(user=User.current) - if container_id - container && container.attachments_visible?(user) - else - author == user - end - end - - def deletable?(user=User.current) - if container_id - container && (container.is_a?(Project) ? container.attachments_deletable?(user) : true ) - else - author == user - end - end - - def image? - !!(self.filename =~ /\.(bmp|gif|jpg|jpe|jpeg|png)$/i) - end - - def pack? - !!(self.filename =~ /\.(zip|rar|tar|gz|exe|jar|7z|iso)$/i) - end - - def thumbnailable? - image? - end - - # Returns the full path the attachment thumbnail, or nil - # if the thumbnail cannot be generated. - def thumbnail(options={}) - if thumbnailable? && readable? - size = options[:size].to_i - if size > 0 - # Limit the number of thumbnails per image - size = (size / 50) * 50 - # Maximum thumbnail size - size = 800 if size > 800 - else - size = Setting.thumbnails_size.to_i - end - size = 100 unless size > 0 - target = File.join(self.class.thumbnails_storage_path, "#{id}_#{digest}_#{size}.thumb") - begin - Redmine::Thumbnail.generate(self.diskfile, target, size) - rescue => e - logger.error "An error occured while generating thumbnail for #{disk_filename} to #{target}\nException was: #{e.message}" if logger - return nil - end - end - end - - # Deletes all thumbnails - def self.clear_thumbnails - Dir.glob(File.join(thumbnails_storage_path, "*.thumb")).each do |file| - File.delete file - end - end - - def is_text? - Redmine::MimeType.is_type?('text', filename) - end - - def is_diff? - self.filename =~ /\.(patch|diff)$/i - end - - # Returns true if the file is readable - def readable? - File.readable?(diskfile) - end - - # Returns the attachment token - def token - "#{id}.#{digest}" - end - - # Finds an attachment that matches the given token and that has no container - def self.find_by_token(token) - attachment = find_by_token_only(token) - attachment if attachment.container.nil? - end - - # Finds an attachment that matches the given token - def self.find_by_token_only(token) - if token.to_s =~ /^(\d+)\.([0-9a-f]+)$/ - attachment_id, attachment_digest = $1, $2 - attachment = Attachment.where(:id => attachment_id, :digest => attachment_digest).first - end - end - - # Bulk attaches a set of files to an object - # - # Returns a Hash of the results: - # :files => array of the attached files - # :unsaved => array of the files that could not be attached - def self.attach_files(obj, attachments) - result = obj.save_attachments(attachments, User.current) - obj.attach_saved_attachments - result - end - - - def self.attach_filesex(obj, attachments,attachment_type) - result = obj.save_attachmentsex(attachments, User.current,attachment_type) - obj.attach_saved_attachments - result - end - - def self.latest_attach(attachments, filename) - attachments.sort_by(&:created_on).reverse.detect { - |att| att.filename.downcase == filename.downcase - } - end - - def self.prune(age=1.day) - Attachment.where("created_on < ? AND (container_type IS NULL OR container_type = '')", Time.now - age).destroy_all - end - - # Moves an existing attachment to its target directory - def move_to_target_directory! - if !new_record? & readable? - src = diskfile - self.disk_directory = target_directory - dest = diskfile - if src != dest && FileUtils.mkdir_p(File.dirname(dest)) && FileUtils.mv(src, dest) - update_column :disk_directory, disk_directory - end - end - end - - # Moves existing attachments that are stored at the root of the files - # directory (ie. created before Redmine 2.3) to their target subdirectories - def self.move_from_root_to_target_directory - Attachment.where("disk_directory IS NULL OR disk_directory = ''").find_each do |attachment| - attachment.move_to_target_directory! - end - end - - private - - # Physically deletes the file from the file system - def delete_from_disk! - if disk_filename.present? && File.exist?(diskfile) - File.delete(diskfile) - end - end - - def sanitize_filename(value) - # get only the filename, not the whole path - just_filename = value.gsub(/^.*(\\|\/)/, '') - - # Finally, replace invalid characters with underscore - @filename = just_filename.gsub(/[\/\?\%\*\:\|\"\'<>]+/, '_') - end - - # Returns the subdirectory in which the attachment will be saved - def target_directory - time = created_on || DateTime.now - time.strftime("%Y/%m") - end - - # Returns an ASCII or hashed filename that do not - # exists yet in the given subdirectory - def self.disk_filename(filename, directory=nil) - timestamp = DateTime.now.strftime("%y%m%d%H%M%S") - ascii = '' - if filename =~ %r{^[a-zA-Z0-9_\.\-]*$} - ascii = filename - else - ascii = Digest::MD5.hexdigest(filename) - # keep the extension if any - ascii << $1 if filename =~ %r{(\.[a-zA-Z0-9]+)$} - end - while File.exist?(File.join(storage_path, directory.to_s, "#{timestamp}_#{ascii}")) - timestamp.succ! - end - "#{timestamp}_#{ascii}" - end - - - # update user score - def be_user_score - if self.container_id_changed? - type = self.container_type - types = %w|Document News Version Project Issue Message WikiPage| - if types.include?(type) - #UserScore.project(:push_file, self.author,self, { attachment_id: self.id }) - - end - end - update_attachment(self.author,1) - if self.container_type == 'Project' - update_attachment(self.author,2,self.container) - end - - end - - #删除附件时重新统计用户的附件数量得分 - def down_user_score - update_attachment(self.author,1) - if self.container_type == 'Project' - update_attachment(self.author,2,self.container) - end - end - -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require "digest/md5" +require "fileutils" + +class Attachment < ActiveRecord::Base + belongs_to :container, :polymorphic => true + belongs_to :project, foreign_key: 'container_id', conditions: "attachments.container_type = 'Project'" + belongs_to :course, foreign_key: 'container_id', conditions: "attachments.container_type = 'Course'" + belongs_to :softapplication, foreign_key: 'container_id', conditions: "attachments.container_type = 'Softapplication'" + belongs_to :author, :class_name => "User", :foreign_key => "author_id" + belongs_to :attachmentstype, :foreign_key => "attachtype",:primary_key => "id" + + include UserScoreHelper + + validates :filename, presence: true, length: {maximum: 254} + validates :author, presence: true + validates :disk_filename, length: {maximum: 254} + validates :description, length: {maximum: 254} + validate :validate_max_file_size + + + acts_as_taggable + acts_as_event :title => :filename, + :url => Proc.new {|o| {:controller => 'attachments', :action => 'download', :id => o.id, :filename => o.filename}} + + #课程资源文件 + acts_as_activity_provider :type => 'course_files', + :is_public => 'attachments.is_public', + :permission => :view_files, + :author_key => :author_id, + :find_options => {:select => "#{Attachment.table_name}.*", + :joins => "LEFT JOIN #{Course.table_name} ON ( #{Attachment.table_name}.container_type='Course' AND #{Attachment.table_name}.container_id = #{Course.table_name}.id )"} + + acts_as_activity_provider :type => 'files', + :is_public => 'attachments.is_public', + :permission => :view_files, + :author_key => :author_id, + :find_options => { :select => "#{Attachment.table_name}.*", + :joins => "LEFT JOIN #{Version.table_name} ON #{Attachment.table_name}.container_type='Version' AND #{Version.table_name}.id = #{Attachment.table_name}.container_id " + + "LEFT JOIN #{Project.table_name} ON #{Version.table_name}.project_id = #{Project.table_name}.id OR ( #{Attachment.table_name}.container_type='Project' AND #{Attachment.table_name}.container_id = #{Project.table_name}.id )"} + + acts_as_activity_provider :type => 'documents', + :is_public => 'documents.is_public', + :permission => :view_documents, + :author_key => :author_id, + :find_options => {:select => "#{Attachment.table_name}.*", + :joins => "LEFT JOIN #{Document.table_name} ON #{Attachment.table_name}.container_type='Document' AND #{Document.table_name}.id = #{Attachment.table_name}.container_id " + + "LEFT JOIN #{Project.table_name} ON #{Document.table_name}.project_id = #{Project.table_name}.id"} + + cattr_accessor :storage_path + @@storage_path = Redmine::Configuration['attachments_storage_path'] || File.join(Rails.root, "files") + + cattr_accessor :thumbnails_storage_path + @@thumbnails_storage_path = File.join(Rails.root, "tmp", "thumbnails") + + before_save :files_to_final_location + after_create :be_user_score # user_score + after_update :be_user_score + after_destroy :delete_from_disk,:down_user_score + + # add by nwb + # 获取所有可公开的资源文件列表 + scope :public_attachments, lambda { + #joins(Project.table_name).where("container_type = 'Project' and ") + joins("LEFT JOIN #{Project.table_name} ON #{Attachment.table_name}.container_type='Project' AND #{Project.table_name}.id = #{Attachment.table_name}.container_id and #{Project.table_name}.is_public=1 " + + " LEFT JOIN #{Document.table_name} ON #{Attachment.table_name}.container_type='Project' AND #{Document.table_name}.project_id in "+self.public_project_id + + " LEFT JOIN #{Issue.table_name} ON #{Attachment.table_name}.container_type='Project' AND #{Issue.table_name}.project_id in "+self.public_project_id + + " LEFT JOIN #{Version.table_name} ON #{Attachment.table_name}.container_type='Project' AND #{Version.table_name}.project_id in "+self.public_project_id + + " LEFT JOIN #{WikiPage.table_name} ON #{Attachment.table_name}.container_type='WikiPage' AND #{WikiPage.table_name}.parent_id in "+self.public_wiki_id + + " LEFT JOIN #{Message.table_name} ON #{Attachment.table_name}.container_type='Message' AND #{Message.table_name}.parent_id in "+self.public_board_id + + " LEFT JOIN #{Course.table_name} ON #{Attachment.table_name}.container_type='Course' AND #{Course.table_name}.is_public=1 " + + " LEFT JOIN #{News.table_name} ON #{Attachment.table_name}.container_type='News' AND (#{News.table_name}.project_id in "+self.public_project_id + " OR #{News.table_name}.course_id in " + self.public_course_id + ")" + + " LEFT JOIN #{HomeworkAttach.table_name} ON #{Attachment.table_name}.container_type='HomeworkAttach' AND #{HomeworkAttach.table_name}.bid_id in "+self.public_bid_id) + } + + # add by nwb + # 公开的项目id列表 + def self.public_project_id + idlist = "(" + projects=Project.all_public + count = projects.count + for i in 0...count + project = projects[i] + idlist+="'" + project.id.to_s + "'" + if i != count-1 + idlist+="," + end + end + idlist += ")" + idlist + end + + # add by nwb + # 公开的课程id列表 + def self.public_course_id + idlist = "(" + courses=Course.all_public + count = courses.count + for i in 0...count + course = courses[i] + idlist+="'" + course.id.to_s + "'" + if i != count-1 + idlist = idlist + "," + end + end + idlist += ")" + idlist + end + + # add by nwb + # 公开的wiki id列表 + def self.public_wiki_id + idlist = "(" + wikis=Wiki.where("project_id in " + public_project_id) + count = wikis.count + for i in 0...count + wiki = wikis[i] + idlist+="'" + wiki.id.to_s + "'" + if i != count-1 + idlist = idlist + "," + end + end + idlist += ")" + idlist + end + + # add by nwb + # 公开的board id列表 + def self.public_board_id + idlist = "(" + boards=Board.where("project_id in " + public_project_id + " or course_id in " + public_course_id) + count = boards.count + for i in 0...count + board = boards[i] + idlist+="'" + board.id.to_s + "'" + if i != count-1 + idlist = idlist + "," + end + end + idlist += ")" + idlist + end + + # add by nwb + # 公开的bid id列表 + def self.public_bid_id + idlist = "(" + bids=Bid.where("reward_type=3") + count = bids.count + for i in 0...count + bid = bids[i] + idlist+="'" + bid.id.to_s + "'" + if i != count-1 + idlist = idlist + "," + end + end + idlist += ")" + idlist + end + + # Returns an unsaved copy of the attachment + def copy(attributes=nil) + copy = self.class.new + copy.attributes = self.attributes.dup.except("id", "downloads") + copy.attributes = attributes if attributes + copy + end + + #获取资源的后缀类型 + def suffix_type + childArr = self.filename.split('.') + suffix = '*' + if childArr.length > 1 + suffix = childArr[childArr.length-1] + end + suffix + end + + #获取用来显示的后缀名称 + def show_suffix_type + suffix = 'other' + temp = self.suffix_type.downcase + if self.attachmentstype && self.attachmentstype.suffixArr.include?(temp) + suffix = temp + end + suffix + end + + # 文件密级的字符描述 + def file_dense_str + if self.is_public == 1 + dense = l(:field_is_public) + else + dense = l(:field_is_private) + end + dense + end + + # 文件可设置的密级列表 + def file_dense_list + denselist = [l(:field_is_public),l(:field_is_private)] + end + + def suffixArr + @@SuffixArr + end + + def validate_max_file_size + if @temp_file && self.filesize > Setting.attachment_max_size.to_i.kilobytes + errors.add(:base, l(:error_attachment_too_big, :max_size => Setting.attachment_max_size.to_i.kilobytes)) + end + end + + def file=(incoming_file) + unless incoming_file.nil? + @temp_file = incoming_file + # 允许上传文件大小为0的文件 + #if @temp_file.size > 0 + if @temp_file.respond_to?(:original_filename) + self.filename = @temp_file.original_filename + self.filename.force_encoding("UTF-8") if filename.respond_to?(:force_encoding) + end + if @temp_file.respond_to?(:content_type) + self.content_type = @temp_file.content_type.to_s.chomp + end + if content_type.blank? && filename.present? + self.content_type = Redmine::MimeType.of(filename) + end + self.filesize = @temp_file.size + #end + end + end + + def file + nil + end + + def filename=(arg) + write_attribute :filename, sanitize_filename(arg.to_s) + filename + end + + # Copies the temporary file to its final location + # and computes its MD5 hash + def files_to_final_location + # # 允许上传文件大小为0的文件 + if @temp_file# && (@temp_file.size > 0) + self.disk_directory = target_directory + self.disk_filename = Attachment.disk_filename(filename, disk_directory) + logger.info("Saving attachment '#{self.diskfile}' (#{@temp_file.size} bytes)") + path = File.dirname(diskfile) + unless File.directory?(path) + FileUtils.mkdir_p(path) + end + md5 = Digest::MD5.new + File.open(diskfile, "wb") do |f| + if @temp_file.respond_to?(:read) + buffer = "" + while (buffer = @temp_file.read(8192)) + f.write(buffer) + md5.update(buffer) + end + else + f.write(@temp_file) + md5.update(@temp_file) + end + end + self.digest = md5.hexdigest + end + @temp_file = nil + # Don't save the content type if it's longer than the authorized length + if self.content_type && self.content_type.length > 255 + self.content_type = nil + end + end + + # Deletes the file from the file system if it's not referenced by other attachments + def delete_from_disk + if Attachment.where("disk_filename = ? AND id <> ?", disk_filename, id).empty? + delete_from_disk! + end + end + + # Returns file's location on disk + def diskfile + File.join(self.class.storage_path, disk_directory.to_s, disk_filename.to_s) + end + + #标题 + def title + title = filename.to_s + if description.present? + title << " (#{description})" + end + title + end + + def increment_download + increment!(:downloads) + end + + def project + container.try(:project) + end + + def course + container + end + + def visible?(user=User.current) + if container_id + container && container.attachments_visible?(user) + else + author == user + end + end + + def deletable?(user=User.current) + if container_id + container && (container.is_a?(Project) ? container.attachments_deletable?(user) : true ) + else + author == user + end + end + + def image? + !!(self.filename =~ /\.(bmp|gif|jpg|jpe|jpeg|png)$/i) + end + + def pack? + !!(self.filename =~ /\.(zip|rar|tar|gz|exe|jar|7z|iso)$/i) + end + + def thumbnailable? + image? + end + + # Returns the full path the attachment thumbnail, or nil + # if the thumbnail cannot be generated. + def thumbnail(options={}) + if thumbnailable? && readable? + size = options[:size].to_i + if size > 0 + # Limit the number of thumbnails per image + size = (size / 50) * 50 + # Maximum thumbnail size + size = 800 if size > 800 + else + size = Setting.thumbnails_size.to_i + end + size = 100 unless size > 0 + target = File.join(self.class.thumbnails_storage_path, "#{id}_#{digest}_#{size}.thumb") + begin + Redmine::Thumbnail.generate(self.diskfile, target, size) + rescue => e + logger.error "An error occured while generating thumbnail for #{disk_filename} to #{target}\nException was: #{e.message}" if logger + return nil + end + end + end + + # Deletes all thumbnails + def self.clear_thumbnails + Dir.glob(File.join(thumbnails_storage_path, "*.thumb")).each do |file| + File.delete file + end + end + + def is_text? + Redmine::MimeType.is_type?('text', filename) + end + + def is_diff? + self.filename =~ /\.(patch|diff)$/i + end + + # Returns true if the file is readable + def readable? + File.readable?(diskfile) + end + + # Returns the attachment token + def token + "#{id}.#{digest}" + end + + # Finds an attachment that matches the given token and that has no container + def self.find_by_token(token) + attachment = find_by_token_only(token) + attachment if attachment.container.nil? + end + + # Finds an attachment that matches the given token + def self.find_by_token_only(token) + if token.to_s =~ /^(\d+)\.([0-9a-f]+)$/ + attachment_id, attachment_digest = $1, $2 + attachment = Attachment.where(:id => attachment_id, :digest => attachment_digest).first + end + end + + # Bulk attaches a set of files to an object + # + # Returns a Hash of the results: + # :files => array of the attached files + # :unsaved => array of the files that could not be attached + def self.attach_files(obj, attachments) + result = obj.save_attachments(attachments, User.current) + obj.attach_saved_attachments + result + end + + + def self.attach_filesex(obj, attachments,attachment_type) + result = obj.save_attachmentsex(attachments, User.current,attachment_type) + obj.attach_saved_attachments + result + end + + def self.latest_attach(attachments, filename) + attachments.sort_by(&:created_on).reverse.detect { + |att| att.filename.downcase == filename.downcase + } + end + + def self.prune(age=1.day) + Attachment.where("created_on < ? AND (container_type IS NULL OR container_type = '')", Time.now - age).destroy_all + end + + # Moves an existing attachment to its target directory + def move_to_target_directory! + if !new_record? & readable? + src = diskfile + self.disk_directory = target_directory + dest = diskfile + if src != dest && FileUtils.mkdir_p(File.dirname(dest)) && FileUtils.mv(src, dest) + update_column :disk_directory, disk_directory + end + end + end + + # Moves existing attachments that are stored at the root of the files + # directory (ie. created before Redmine 2.3) to their target subdirectories + def self.move_from_root_to_target_directory + Attachment.where("disk_directory IS NULL OR disk_directory = ''").find_each do |attachment| + attachment.move_to_target_directory! + end + end + + private + + # Physically deletes the file from the file system + def delete_from_disk! + if disk_filename.present? && File.exist?(diskfile) + File.delete(diskfile) + end + end + + def sanitize_filename(value) + # get only the filename, not the whole path + just_filename = value.gsub(/^.*(\\|\/)/, '') + + # Finally, replace invalid characters with underscore + @filename = just_filename.gsub(/[\/\?\%\*\:\|\"\'<>]+/, '_') + end + + # Returns the subdirectory in which the attachment will be saved + def target_directory + time = created_on || DateTime.now + time.strftime("%Y/%m") + end + + # Returns an ASCII or hashed filename that do not + # exists yet in the given subdirectory + def self.disk_filename(filename, directory=nil) + timestamp = DateTime.now.strftime("%y%m%d%H%M%S") + ascii = '' + if filename =~ %r{^[a-zA-Z0-9_\.\-]*$} + ascii = filename + else + ascii = Digest::MD5.hexdigest(filename) + # keep the extension if any + ascii << $1 if filename =~ %r{(\.[a-zA-Z0-9]+)$} + end + while File.exist?(File.join(storage_path, directory.to_s, "#{timestamp}_#{ascii}")) + timestamp.succ! + end + "#{timestamp}_#{ascii}" + end + + + # update user score + def be_user_score + if self.container_id_changed? + type = self.container_type + types = %w|Document News Version Project Issue Message WikiPage| + if types.include?(type) + #UserScore.project(:push_file, self.author,self, { attachment_id: self.id }) + + end + end + update_attachment(self.author,1) + if self.container_type == 'Project' + update_attachment(self.author,2,self.container) + end + + end + + #删除附件时重新统计用户的附件数量得分 + def down_user_score + update_attachment(self.author,1) + if self.container_type == 'Project' + update_attachment(self.author,2,self.container) + end + end + +end diff --git a/app/models/auth_source.rb b/app/models/auth_source.rb index fdaf622b3..796099a05 100644 --- a/app/models/auth_source.rb +++ b/app/models/auth_source.rb @@ -1,90 +1,90 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -# Generic exception for when the AuthSource can not be reached -# (eg. can not connect to the LDAP) -class AuthSourceException < Exception; end -class AuthSourceTimeoutException < AuthSourceException; end - -class AuthSource < ActiveRecord::Base - include Redmine::SubclassFactory - include Redmine::Ciphering - - has_many :users - - validates :name, presence: true, uniqueness: true, length: {maximum: 60} - - def authenticate(login, password) - end - - def test_connection - end - - def auth_method_name - "Abstract" - end - - def account_password - read_ciphered_attribute(:account_password) - end - - def account_password=(arg) - write_ciphered_attribute(:account_password, arg) - end - - def searchable? - false - end - - def self.search(q) - results = [] - AuthSource.all.each do |source| - begin - if source.searchable? - results += source.search(q) - end - rescue AuthSourceException => e - logger.error "Error while searching users in #{source.name}: #{e.message}" - end - end - results - end - - def allow_password_changes? - self.class.allow_password_changes? - end - - # Does this auth source backend allow password changes? - def self.allow_password_changes? - false - end - - # Try to authenticate a user not yet registered against available sources - def self.authenticate(login, password) - AuthSource.where(:onthefly_register => true).all.each do |source| - begin - logger.debug "Authenticating '#{login}' against '#{source.name}'" if logger && logger.debug? - attrs = source.authenticate(login, password) - rescue => e - logger.error "Error during authentication: #{e.message}" - attrs = nil - end - return attrs if attrs - end - return nil - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# Generic exception for when the AuthSource can not be reached +# (eg. can not connect to the LDAP) +class AuthSourceException < Exception; end +class AuthSourceTimeoutException < AuthSourceException; end + +class AuthSource < ActiveRecord::Base + include Redmine::SubclassFactory + include Redmine::Ciphering + + has_many :users + + validates :name, presence: true, uniqueness: true, length: {maximum: 60} + + def authenticate(login, password) + end + + def test_connection + end + + def auth_method_name + "Abstract" + end + + def account_password + read_ciphered_attribute(:account_password) + end + + def account_password=(arg) + write_ciphered_attribute(:account_password, arg) + end + + def searchable? + false + end + + def self.search(q) + results = [] + AuthSource.all.each do |source| + begin + if source.searchable? + results += source.search(q) + end + rescue AuthSourceException => e + logger.error "Error while searching users in #{source.name}: #{e.message}" + end + end + results + end + + def allow_password_changes? + self.class.allow_password_changes? + end + + # Does this auth source backend allow password changes? + def self.allow_password_changes? + false + end + + # Try to authenticate a user not yet registered against available sources + def self.authenticate(login, password) + AuthSource.where(:onthefly_register => true).all.each do |source| + begin + logger.debug "Authenticating '#{login}' against '#{source.name}'" if logger && logger.debug? + attrs = source.authenticate(login, password) + rescue => e + logger.error "Error during authentication: #{e.message}" + attrs = nil + end + return attrs if attrs + end + return nil + end +end diff --git a/app/models/auth_source_ldap.rb b/app/models/auth_source_ldap.rb index 8eae422e5..08c94abfd 100644 --- a/app/models/auth_source_ldap.rb +++ b/app/models/auth_source_ldap.rb @@ -1,206 +1,206 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -require 'net/ldap' -require 'net/ldap/dn' -require 'timeout' - -class AuthSourceLdap < AuthSource - validates :host, presence: true, length: {maximum: 60, allow_nil: true} - validates :port, presence: true, numericality: {only_integer: true} - validates :attr_login, presence: true - validates :name, length: {maximum: 60, allow_nil: true} - validates :account, length: {maximum: 255, allow_blank: true} - validates :account_password, length: {maximum: 255, allow_blank: true} - validates :base_dn, length: {maximum: 255, allow_blank: true} - validates :filter, length: {maximum: 255, allow_blank: true} - validates :attr_login, length: {maximum: 30, allow_nil: true} - validates :attr_firstname, length: {maximum: 30, allow_nil: true} - validates :attr_lastname, length: {maximum: 30, allow_nil: true} - validates :attr_mail, length: {maximum: 30, allow_nil: true} - validates :timeout, numericality: { only_integer: true, allow_blank: true} - validate :validate_filter - before_validation :strip_ldap_attributes - - def initialize(attributes=nil, *args) - super - self.port = 389 if self.port == 0 - end - - def authenticate(login, password) - return nil if login.blank? || password.blank? - - with_timeout do - attrs = get_user_dn(login, password) - if attrs && attrs[:dn] && authenticate_dn(attrs[:dn], password) - logger.debug "Authentication successful for '#{login}'" if logger && logger.debug? - return attrs.except(:dn) - end - end - rescue Net::LDAP::LdapError => e - raise AuthSourceException.new(e.message) - end - - # test the connection to the LDAP - def test_connection - with_timeout do - ldap_con = initialize_ldap_con(self.account, self.account_password) - ldap_con.open { } - end - rescue Net::LDAP::LdapError => e - raise AuthSourceException.new(e.message) - end - - def auth_method_name - "LDAP" - end - - # Returns true if this source can be searched for users - def searchable? - !account.to_s.include?("$login") && %w(login firstname lastname mail).all? {|a| send("attr_#{a}?")} - end - - # Searches the source for users and returns an array of results - def search(q) - q = q.to_s.strip - return [] unless searchable? && q.present? - - results = [] - search_filter = base_filter & Net::LDAP::Filter.begins(self.attr_login, q) - ldap_con = initialize_ldap_con(self.account, self.account_password) - ldap_con.search(:base => self.base_dn, - :filter => search_filter, - :attributes => ['dn', self.attr_login, self.attr_firstname, self.attr_lastname, self.attr_mail], - :size => 10) do |entry| - attrs = get_user_attributes_from_ldap_entry(entry) - attrs[:login] = AuthSourceLdap.get_attr(entry, self.attr_login) - results << attrs - end - results - rescue Net::LDAP::LdapError => e - raise AuthSourceException.new(e.message) - end - - private - - def with_timeout(&block) - timeout = self.timeout - timeout = 20 unless timeout && timeout > 0 - Timeout.timeout(timeout) do - return yield - end - rescue Timeout::Error => e - raise AuthSourceTimeoutException.new(e.message) - end - - def ldap_filter - if filter.present? - Net::LDAP::Filter.construct(filter) - end - rescue Net::LDAP::LdapError - nil - end - - def base_filter - filter = Net::LDAP::Filter.eq("objectClass", "*") - if f = ldap_filter - filter = filter & f - end - filter - end - - def validate_filter - if filter.present? && ldap_filter.nil? - errors.add(:filter, :invalid) - end - end - - def strip_ldap_attributes - [:attr_login, :attr_firstname, :attr_lastname, :attr_mail].each do |attr| - write_attribute(attr, read_attribute(attr).strip) unless read_attribute(attr).nil? - end - end - - def initialize_ldap_con(ldap_user, ldap_password) - options = { :host => self.host, - :port => self.port, - :encryption => (self.tls ? :simple_tls : nil) - } - options.merge!(:auth => { :method => :simple, :username => ldap_user, :password => ldap_password }) unless ldap_user.blank? && ldap_password.blank? - Net::LDAP.new options - end - - def get_user_attributes_from_ldap_entry(entry) - { - :dn => entry.dn, - :firstname => AuthSourceLdap.get_attr(entry, self.attr_firstname), - :lastname => AuthSourceLdap.get_attr(entry, self.attr_lastname), - :mail => AuthSourceLdap.get_attr(entry, self.attr_mail), - :auth_source_id => self.id - } - end - - # Return the attributes needed for the LDAP search. It will only - # include the user attributes if on-the-fly registration is enabled - def search_attributes - if onthefly_register? - ['dn', self.attr_firstname, self.attr_lastname, self.attr_mail] - else - ['dn'] - end - end - - # Check if a DN (user record) authenticates with the password - def authenticate_dn(dn, password) - if dn.present? && password.present? - initialize_ldap_con(dn, password).bind - end - end - - # Get the user's dn and any attributes for them, given their login - def get_user_dn(login, password) - ldap_con = nil - if self.account && self.account.include?("$login") - ldap_con = initialize_ldap_con(self.account.sub("$login", Net::LDAP::DN.escape(login)), password) - else - ldap_con = initialize_ldap_con(self.account, self.account_password) - end - attrs = {} - search_filter = base_filter & Net::LDAP::Filter.eq(self.attr_login, login) - - ldap_con.search( :base => self.base_dn, - :filter => search_filter, - :attributes=> search_attributes) do |entry| - - if onthefly_register? - attrs = get_user_attributes_from_ldap_entry(entry) - else - attrs = {:dn => entry.dn} - end - - logger.debug "DN found for #{login}: #{attrs[:dn]}" if logger && logger.debug? - end - - attrs - end - - def self.get_attr(entry, attr_name) - if !attr_name.blank? - entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name] - end - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'net/ldap' +require 'net/ldap/dn' +require 'timeout' + +class AuthSourceLdap < AuthSource + validates :host, presence: true, length: {maximum: 60, allow_nil: true} + validates :port, presence: true, numericality: {only_integer: true} + validates :attr_login, presence: true + validates :name, length: {maximum: 60, allow_nil: true} + validates :account, length: {maximum: 255, allow_blank: true} + validates :account_password, length: {maximum: 255, allow_blank: true} + validates :base_dn, length: {maximum: 255, allow_blank: true} + validates :filter, length: {maximum: 255, allow_blank: true} + validates :attr_login, length: {maximum: 30, allow_nil: true} + validates :attr_firstname, length: {maximum: 30, allow_nil: true} + validates :attr_lastname, length: {maximum: 30, allow_nil: true} + validates :attr_mail, length: {maximum: 30, allow_nil: true} + validates :timeout, numericality: { only_integer: true, allow_blank: true} + validate :validate_filter + before_validation :strip_ldap_attributes + + def initialize(attributes=nil, *args) + super + self.port = 389 if self.port == 0 + end + + def authenticate(login, password) + return nil if login.blank? || password.blank? + + with_timeout do + attrs = get_user_dn(login, password) + if attrs && attrs[:dn] && authenticate_dn(attrs[:dn], password) + logger.debug "Authentication successful for '#{login}'" if logger && logger.debug? + return attrs.except(:dn) + end + end + rescue Net::LDAP::LdapError => e + raise AuthSourceException.new(e.message) + end + + # test the connection to the LDAP + def test_connection + with_timeout do + ldap_con = initialize_ldap_con(self.account, self.account_password) + ldap_con.open { } + end + rescue Net::LDAP::LdapError => e + raise AuthSourceException.new(e.message) + end + + def auth_method_name + "LDAP" + end + + # Returns true if this source can be searched for users + def searchable? + !account.to_s.include?("$login") && %w(login firstname lastname mail).all? {|a| send("attr_#{a}?")} + end + + # Searches the source for users and returns an array of results + def search(q) + q = q.to_s.strip + return [] unless searchable? && q.present? + + results = [] + search_filter = base_filter & Net::LDAP::Filter.begins(self.attr_login, q) + ldap_con = initialize_ldap_con(self.account, self.account_password) + ldap_con.search(:base => self.base_dn, + :filter => search_filter, + :attributes => ['dn', self.attr_login, self.attr_firstname, self.attr_lastname, self.attr_mail], + :size => 10) do |entry| + attrs = get_user_attributes_from_ldap_entry(entry) + attrs[:login] = AuthSourceLdap.get_attr(entry, self.attr_login) + results << attrs + end + results + rescue Net::LDAP::LdapError => e + raise AuthSourceException.new(e.message) + end + + private + + def with_timeout(&block) + timeout = self.timeout + timeout = 20 unless timeout && timeout > 0 + Timeout.timeout(timeout) do + return yield + end + rescue Timeout::Error => e + raise AuthSourceTimeoutException.new(e.message) + end + + def ldap_filter + if filter.present? + Net::LDAP::Filter.construct(filter) + end + rescue Net::LDAP::LdapError + nil + end + + def base_filter + filter = Net::LDAP::Filter.eq("objectClass", "*") + if f = ldap_filter + filter = filter & f + end + filter + end + + def validate_filter + if filter.present? && ldap_filter.nil? + errors.add(:filter, :invalid) + end + end + + def strip_ldap_attributes + [:attr_login, :attr_firstname, :attr_lastname, :attr_mail].each do |attr| + write_attribute(attr, read_attribute(attr).strip) unless read_attribute(attr).nil? + end + end + + def initialize_ldap_con(ldap_user, ldap_password) + options = { :host => self.host, + :port => self.port, + :encryption => (self.tls ? :simple_tls : nil) + } + options.merge!(:auth => { :method => :simple, :username => ldap_user, :password => ldap_password }) unless ldap_user.blank? && ldap_password.blank? + Net::LDAP.new options + end + + def get_user_attributes_from_ldap_entry(entry) + { + :dn => entry.dn, + :firstname => AuthSourceLdap.get_attr(entry, self.attr_firstname), + :lastname => AuthSourceLdap.get_attr(entry, self.attr_lastname), + :mail => AuthSourceLdap.get_attr(entry, self.attr_mail), + :auth_source_id => self.id + } + end + + # Return the attributes needed for the LDAP search. It will only + # include the user attributes if on-the-fly registration is enabled + def search_attributes + if onthefly_register? + ['dn', self.attr_firstname, self.attr_lastname, self.attr_mail] + else + ['dn'] + end + end + + # Check if a DN (user record) authenticates with the password + def authenticate_dn(dn, password) + if dn.present? && password.present? + initialize_ldap_con(dn, password).bind + end + end + + # Get the user's dn and any attributes for them, given their login + def get_user_dn(login, password) + ldap_con = nil + if self.account && self.account.include?("$login") + ldap_con = initialize_ldap_con(self.account.sub("$login", Net::LDAP::DN.escape(login)), password) + else + ldap_con = initialize_ldap_con(self.account, self.account_password) + end + attrs = {} + search_filter = base_filter & Net::LDAP::Filter.eq(self.attr_login, login) + + ldap_con.search( :base => self.base_dn, + :filter => search_filter, + :attributes=> search_attributes) do |entry| + + if onthefly_register? + attrs = get_user_attributes_from_ldap_entry(entry) + else + attrs = {:dn => entry.dn} + end + + logger.debug "DN found for #{login}: #{attrs[:dn]}" if logger && logger.debug? + end + + attrs + end + + def self.get_attr(entry, attr_name) + if !attr_name.blank? + entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name] + end + end +end diff --git a/app/models/biding_project.rb b/app/models/biding_project.rb index 9ebd1b73c..decf85812 100644 --- a/app/models/biding_project.rb +++ b/app/models/biding_project.rb @@ -1,59 +1,59 @@ -## fq -class BidingProject < ActiveRecord::Base - attr_accessible :bid_id, :project_id, :user_id, :description,:reward - - belongs_to :bid - belongs_to :project - belongs_to :user - - DESCRIPTION_LENGTH_LIMIT = 500 - validates :description, length: {maximum: DESCRIPTION_LENGTH_LIMIT} - validates :user_id, presence: true - validates :bid_id, presence: true, :uniqueness => { :scope => :project_id} - validates :project_id, presence: true - validate :validate_user - validate :validate_bid - validate :validate_project - - def self.cerate_bidding(bid_id, project_id, description = nil) - self.create(:user_id => User.current.id, :bid_id => bid_id, - :project_id => project_id, :description => description) - end - - # used to update the reward ,the value varies from 0,1,2,3,4,5 - # added by william - def update_reward(which) - self.update_attribute(:reward,which) - end - - # return the reward,the value is a type of string - # added by william - def get_reward - self.reward - end - - def cancel_bidding - unless self.nil? - if User.current.id == self.user_id - self.destroy - end - end - end - - private - - def validate_user - errors.add :user_id, :invalid if user.nil? || !user.active? - end - - def validate_bid - errors.add :bid_id, :invalid if bid.nil? - end - - def validate_project - errors.add :project_id, :invalid if project.nil? - end - -end - - +## fq +class BidingProject < ActiveRecord::Base + attr_accessible :bid_id, :project_id, :user_id, :description,:reward + + belongs_to :bid + belongs_to :project + belongs_to :user + + DESCRIPTION_LENGTH_LIMIT = 500 + validates :description, length: {maximum: DESCRIPTION_LENGTH_LIMIT} + validates :user_id, presence: true + validates :bid_id, presence: true, :uniqueness => { :scope => :project_id} + validates :project_id, presence: true + validate :validate_user + validate :validate_bid + validate :validate_project + + def self.cerate_bidding(bid_id, project_id, description = nil) + self.create(:user_id => User.current.id, :bid_id => bid_id, + :project_id => project_id, :description => description) + end + + # used to update the reward ,the value varies from 0,1,2,3,4,5 + # added by william + def update_reward(which) + self.update_attribute(:reward,which) + end + + # return the reward,the value is a type of string + # added by william + def get_reward + self.reward + end + + def cancel_bidding + unless self.nil? + if User.current.id == self.user_id + self.destroy + end + end + end + + private + + def validate_user + errors.add :user_id, :invalid if user.nil? || !user.active? + end + + def validate_bid + errors.add :bid_id, :invalid if bid.nil? + end + + def validate_project + errors.add :project_id, :invalid if project.nil? + end + +end + + diff --git a/app/models/board.rb b/app/models/board.rb index 0d8c21ab2..edcbe0c9d 100644 --- a/app/models/board.rb +++ b/app/models/board.rb @@ -1,90 +1,90 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class Board < ActiveRecord::Base - include Redmine::SafeAttributes - belongs_to :project - belongs_to :course - has_many :topics, :class_name => 'Message', :conditions => "#{Message.table_name}.parent_id IS NULL", :order => "#{Message.table_name}.created_on DESC" - has_many :messages, :dependent => :destroy, :order => "#{Message.table_name}.created_on DESC" - belongs_to :last_message, :class_name => 'Message', :foreign_key => :last_message_id - acts_as_tree :dependent => :nullify - acts_as_list :scope => '(project_id = #{project_id} AND parent_id #{parent_id ? "= #{parent_id}" : "IS NULL"})' - acts_as_watchable - - validates :name, presence: true, length: {maximum: 30} - validates :description, presence: true, length: {maximum: 255} - validate :validate_board - - scope :visible, lambda {|*args| - includes(:project).where(Project.allowed_to_condition(args.shift || User.current, :view_messages, *args)) - } - - safe_attributes 'name', 'description', 'parent_id', 'move_to' - - def visible?(user=User.current) - !user.nil? && user.allowed_to?(:view_messages, project) - end - - def reload(*args) - @valid_parents = nil - super - end - - def to_s - name - end - - def valid_parents - @valid_parents ||= project.boards - self_and_descendants - end - - def reset_counters! - self.class.reset_counters!(id) - end - - # Updates topics_count, messages_count and last_message_id attributes for +board_id+ - def self.reset_counters!(board_id) - board_id = board_id.to_i - update_all("topics_count = (SELECT COUNT(*) FROM #{Message.table_name} WHERE board_id=#{board_id} AND parent_id IS NULL)," + - " messages_count = (SELECT COUNT(*) FROM #{Message.table_name} WHERE board_id=#{board_id})," + - " last_message_id = (SELECT MAX(id) FROM #{Message.table_name} WHERE board_id=#{board_id})", - ["id = ?", board_id]) - end - - def self.board_tree(boards, parent_id=nil, level=0) - tree = [] - boards.select {|board| board.parent_id == parent_id}.sort_by(&:position).each do |board| - tree << [board, level] - tree += board_tree(boards, board.id, level+1) - end - if block_given? - tree.each do |board, level| - yield board, level - end - end - tree - end - - protected - - def validate_board - if parent_id && parent_id_changed? - errors.add(:parent_id, :invalid) unless valid_parents.include?(parent) - end - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Board < ActiveRecord::Base + include Redmine::SafeAttributes + belongs_to :project + belongs_to :course + has_many :topics, :class_name => 'Message', :conditions => "#{Message.table_name}.parent_id IS NULL", :order => "#{Message.table_name}.created_on DESC" + has_many :messages, :dependent => :destroy, :order => "#{Message.table_name}.created_on DESC" + belongs_to :last_message, :class_name => 'Message', :foreign_key => :last_message_id + acts_as_tree :dependent => :nullify + acts_as_list :scope => '(project_id = #{project_id} AND parent_id #{parent_id ? "= #{parent_id}" : "IS NULL"})' + acts_as_watchable + + validates :name, presence: true, length: {maximum: 30} + validates :description, presence: true, length: {maximum: 255} + validate :validate_board + + scope :visible, lambda {|*args| + includes(:project).where(Project.allowed_to_condition(args.shift || User.current, :view_messages, *args)) + } + + safe_attributes 'name', 'description', 'parent_id', 'move_to' + + def visible?(user=User.current) + !user.nil? && user.allowed_to?(:view_messages, project) + end + + def reload(*args) + @valid_parents = nil + super + end + + def to_s + name + end + + def valid_parents + @valid_parents ||= project.boards - self_and_descendants + end + + def reset_counters! + self.class.reset_counters!(id) + end + + # Updates topics_count, messages_count and last_message_id attributes for +board_id+ + def self.reset_counters!(board_id) + board_id = board_id.to_i + update_all("topics_count = (SELECT COUNT(*) FROM #{Message.table_name} WHERE board_id=#{board_id} AND parent_id IS NULL)," + + " messages_count = (SELECT COUNT(*) FROM #{Message.table_name} WHERE board_id=#{board_id})," + + " last_message_id = (SELECT MAX(id) FROM #{Message.table_name} WHERE board_id=#{board_id})", + ["id = ?", board_id]) + end + + def self.board_tree(boards, parent_id=nil, level=0) + tree = [] + boards.select {|board| board.parent_id == parent_id}.sort_by(&:position).each do |board| + tree << [board, level] + tree += board_tree(boards, board.id, level+1) + end + if block_given? + tree.each do |board, level| + yield board, level + end + end + tree + end + + protected + + def validate_board + if parent_id && parent_id_changed? + errors.add(:parent_id, :invalid) unless valid_parents.include?(parent) + end + end +end diff --git a/app/models/bug_to_osp.rb b/app/models/bug_to_osp.rb index 3d93957cf..98a80965b 100644 --- a/app/models/bug_to_osp.rb +++ b/app/models/bug_to_osp.rb @@ -1,11 +1,11 @@ -class BugToOsp < ActiveRecord::Base - # attr_accessible :title, :body - belongs_to :open_source_project, :foreign_key => "osp_id" - belongs_to :bug, :class_name => 'RelativeMemo', :foreign_key => "relative_memo_id" - validates :osp_id, presence: true - validates :relative_memo_id, presence: true - - scope :visible, lambda {|*args| - nil - } -end +class BugToOsp < ActiveRecord::Base + # attr_accessible :title, :body + belongs_to :open_source_project, :foreign_key => "osp_id" + belongs_to :bug, :class_name => 'RelativeMemo', :foreign_key => "relative_memo_id" + validates :osp_id, presence: true + validates :relative_memo_id, presence: true + + scope :visible, lambda {|*args| + nil + } +end diff --git a/app/models/change.rb b/app/models/change.rb index 304a2fb59..8beede196 100644 --- a/app/models/change.rb +++ b/app/models/change.rb @@ -1,39 +1,39 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class Change < ActiveRecord::Base - belongs_to :changeset - - validates :changeset_id, presence: true - validates :action, presence: true - validates :path, presence: true - before_save :init_path - before_validation :replace_invalid_utf8_of_path - - def relative_path - changeset.repository.relative_path(path) - end - - def replace_invalid_utf8_of_path - self.path = Redmine::CodesetUtil.replace_invalid_utf8(self.path) - self.from_path = Redmine::CodesetUtil.replace_invalid_utf8(self.from_path) - end - - def init_path - self.path ||= "" - end -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Change < ActiveRecord::Base + belongs_to :changeset + + validates :changeset_id, presence: true + validates :action, presence: true + validates :path, presence: true + before_save :init_path + before_validation :replace_invalid_utf8_of_path + + def relative_path + changeset.repository.relative_path(path) + end + + def replace_invalid_utf8_of_path + self.path = Redmine::CodesetUtil.replace_invalid_utf8(self.path) + self.from_path = Redmine::CodesetUtil.replace_invalid_utf8(self.from_path) + end + + def init_path + self.path ||= "" + end +end diff --git a/app/models/changeset.rb b/app/models/changeset.rb index 5a617b790..e05a7d2da 100644 --- a/app/models/changeset.rb +++ b/app/models/changeset.rb @@ -1,332 +1,332 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class Changeset < ActiveRecord::Base - belongs_to :repository - belongs_to :user - include UserScoreHelper - #after_save :be_user_score # user_score - - has_many :filechanges, :class_name => 'Change', :dependent => :delete_all - # fq - has_many :acts, :class_name => 'Activity', :as => :act, :dependent => :destroy - # end - - #Added by nie - has_one :project_status, :dependent => :destroy - has_one :users_status - #end - - has_and_belongs_to_many :issues - has_and_belongs_to_many :parents, - :class_name => "Changeset", - :join_table => "#{table_name_prefix}changeset_parents#{table_name_suffix}", - :association_foreign_key => 'parent_id', :foreign_key => 'changeset_id' - has_and_belongs_to_many :children, - :class_name => "Changeset", - :join_table => "#{table_name_prefix}changeset_parents#{table_name_suffix}", - :association_foreign_key => 'changeset_id', :foreign_key => 'parent_id' - - acts_as_event :title => Proc.new {|o| o.title}, - :description => :long_comments, - :datetime => :committed_on, - :url => Proc.new {|o| {:controller => 'repositories', :action => 'revision', :id => o.repository.project, :repository_id => o.repository.identifier_param, :rev => o.identifier}} - - acts_as_searchable :columns => 'comments', - :include => {:repository => :project}, - :project_key => "#{Repository.table_name}.project_id", - :date_column => 'committed_on' - - acts_as_activity_provider :timestamp => "#{table_name}.committed_on", - :author_key => :user_id, - :find_options => {:include => [:user, {:repository => :project}]} - validates :repository_id, presence: true - validates :revision, presence: true, uniqueness: {scope: :repository_id} - validates :committed_on, presence: true - validates :commit_date, presence: true - validates :scmid, uniqueness: {scope: :repository_id, allow_nil: true} - - scope :visible, lambda {|*args| - includes(:repository => :project).where(Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args)) - } - - after_create :scan_for_issues,:refresh_changests#:be_user_score # user_score - after_update :be_user_score - after_destroy :down_user_score - before_create :before_create_cs - - # fq - # after_create :act_as_activity - # end - - def revision=(r) - write_attribute :revision, (r.nil? ? nil : r.to_s) - end - - # Returns the identifier of this changeset; depending on repository backends - def identifier - if repository.class.respond_to? :changeset_identifier - repository.class.changeset_identifier self - else - revision.to_s - end - end - - def committed_on=(date) - self.commit_date = date - super - end - - # Returns the readable identifier - def format_identifier - if repository.class.respond_to? :format_changeset_identifier - repository.class.format_changeset_identifier self - else - identifier - end - end - - def project - unless repository.nil? - repository.project - end - end - - def author - user || committer.to_s.split('<').first - end - - def before_create_cs - self.committer = self.class.to_utf8(self.committer, repository.repo_log_encoding) - self.comments = self.class.normalize_comments( - self.comments, repository.repo_log_encoding) - self.user = repository.find_committer_user(self.committer) - end - - def scan_for_issues - scan_comment_for_issue_ids - end - - TIMELOG_RE = / - ( - ((\d+)(h|hours?))((\d+)(m|min)?)? - | - ((\d+)(h|hours?|m|min)) - | - (\d+):(\d+) - | - (\d+([\.,]\d+)?)h? - ) - /x - - def scan_comment_for_issue_ids - return if comments.blank? - # keywords used to reference issues - ref_keywords = Setting.commit_ref_keywords.downcase.split(",").collect(&:strip) - ref_keywords_any = ref_keywords.delete('*') - # keywords used to fix issues - fix_keywords = Setting.commit_fix_keywords.downcase.split(",").collect(&:strip) - - kw_regexp = (ref_keywords + fix_keywords).collect{|kw| Regexp.escape(kw)}.join("|") - - referenced_issues = [] - - comments.scan(/([\s\(\[,-]|^)((#{kw_regexp})[\s:]+)?(#\d+(\s+@#{TIMELOG_RE})?([\s,;&]+#\d+(\s+@#{TIMELOG_RE})?)*)(?=[[:punct:]]|\s|<|$)/i) do |match| - action, refs = match[2], match[3] - next unless action.present? || ref_keywords_any - - refs.scan(/#(\d+)(\s+@#{TIMELOG_RE})?/).each do |m| - issue, hours = find_referenced_issue_by_id(m[0].to_i), m[2] - if issue - referenced_issues << issue - fix_issue(issue) if fix_keywords.include?(action.to_s.downcase) - log_time(issue, hours) if hours && Setting.commit_logtime_enabled? - end - end - end - - referenced_issues.uniq! - self.issues = referenced_issues unless referenced_issues.empty? - end - - def short_comments - @short_comments || split_comments.first - end - - def long_comments - @long_comments || split_comments.last - end - - def text_tag(ref_project=nil) - tag = if scmid? - "commit:#{scmid}" - else - "r#{revision}" - end - if repository && repository.identifier.present? - tag = "#{repository.identifier}|#{tag}" - end - if ref_project && project && ref_project != project - tag = "#{project.identifier}:#{tag}" - end - tag - end - - # Returns the title used for the changeset in the activity/search results - def title - repo = (repository && repository.identifier.present?) ? " (#{repository.identifier})" : '' - comm = short_comments.blank? ? '' : (': ' + short_comments) - "#{l(:label_revision)} #{format_identifier}#{repo}#{comm}" - end - - # Returns the previous changeset - def previous - @previous ||= Changeset.where(["id < ? AND repository_id = ?", id, repository_id]).order('id DESC').first - end - - # Returns the next changeset - def next - @next ||= Changeset.where(["id > ? AND repository_id = ?", id, repository_id]).order('id ASC').first - end - - # Creates a new Change from it's common parameters - def create_change(change) - Change.create(:changeset => self, - :action => change[:action], - :path => change[:path], - :from_path => change[:from_path], - :from_revision => change[:from_revision]) - end - - # Finds an issue that can be referenced by the commit message - def find_referenced_issue_by_id(id) - return nil if id.blank? - issue = Issue.find_by_id(id.to_i, :include => :project) - if Setting.commit_cross_project_ref? - # all issues can be referenced/fixed - elsif issue - # issue that belong to the repository project, a subproject or a parent project only - unless issue.project && - (project == issue.project || project.is_ancestor_of?(issue.project) || - project.is_descendant_of?(issue.project)) - issue = nil - end - end - issue - end - - private - - def act_as_activity - self.acts << Activity.new(:user_id => self.user_id) - end - - def fix_issue(issue) - status = IssueStatus.find_by_id(Setting.commit_fix_status_id.to_i) - if status.nil? - logger.warn("No status matches commit_fix_status_id setting (#{Setting.commit_fix_status_id})") if logger - return issue - end - - # the issue may have been updated by the closure of another one (eg. duplicate) - issue.reload - # don't change the status is the issue is closed - return if issue.status && issue.status.is_closed? - - journal = issue.init_journal(user || User.anonymous, ll(Setting.default_language, :text_status_changed_by_changeset, text_tag(issue.project))) - issue.status = status - unless Setting.commit_fix_done_ratio.blank? - issue.done_ratio = Setting.commit_fix_done_ratio.to_i - end - Redmine::Hook.call_hook(:model_changeset_scan_commit_for_issue_ids_pre_issue_update, - { :changeset => self, :issue => issue }) - unless issue.save - logger.warn("Issue ##{issue.id} could not be saved by changeset #{id}: #{issue.errors.full_messages}") if logger - end - issue - end - - def log_time(issue, hours) - time_entry = TimeEntry.new( - :user => user, - :hours => hours, - :issue => issue, - :spent_on => commit_date, - :comments => l(:text_time_logged_by_changeset, :value => text_tag(issue.project), - :locale => Setting.default_language) - ) - time_entry.activity = log_time_activity unless log_time_activity.nil? - - unless time_entry.save - logger.warn("TimeEntry could not be created by changeset #{id}: #{time_entry.errors.full_messages}") if logger - end - time_entry - end - - def log_time_activity - if Setting.commit_logtime_activity_id.to_i > 0 - TimeEntryActivity.find_by_id(Setting.commit_logtime_activity_id.to_i) - end - end - - def split_comments - comments =~ /\A(.+?)\r?\n(.*)$/m - @short_comments = $1 || comments - @long_comments = $2.to_s.strip - return @short_comments, @long_comments - end - - public - - # Strips and reencodes a commit log before insertion into the database - def self.normalize_comments(str, encoding) - Changeset.to_utf8(str.to_s.strip, encoding) - end - - def self.to_utf8(str, encoding) - Redmine::CodesetUtil.to_utf8(str, encoding) - end - - private - - # update user score - def be_user_score - UserScore.project(:push_code, self.user,self, { changeset_id: self.id }) - unless self.user.nil? - #更新用户等级 - UserLevels.update_user_level(self.user) - update_changeset(self.user,1) - update_changeset(self.user,2,self.repository.project) - end - - end - - #积分刷新 - def down_user_score - UserLevels.update_user_level(self.user) - update_changeset(self.user,1) - update_changeset(self.user,2,self.repository.project) - end - - #刷新本次提交(补全相关信息如:user_id等) - def refresh_changests - unless self.repository.nil? - self.repository.fetch_changesets if Setting.autofetch_changesets? - end - end - -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Changeset < ActiveRecord::Base + belongs_to :repository + belongs_to :user + include UserScoreHelper + #after_save :be_user_score # user_score + + has_many :filechanges, :class_name => 'Change', :dependent => :delete_all + # fq + has_many :acts, :class_name => 'Activity', :as => :act, :dependent => :destroy + # end + + #Added by nie + has_one :project_status, :dependent => :destroy + has_one :users_status + #end + + has_and_belongs_to_many :issues + has_and_belongs_to_many :parents, + :class_name => "Changeset", + :join_table => "#{table_name_prefix}changeset_parents#{table_name_suffix}", + :association_foreign_key => 'parent_id', :foreign_key => 'changeset_id' + has_and_belongs_to_many :children, + :class_name => "Changeset", + :join_table => "#{table_name_prefix}changeset_parents#{table_name_suffix}", + :association_foreign_key => 'changeset_id', :foreign_key => 'parent_id' + + acts_as_event :title => Proc.new {|o| o.title}, + :description => :long_comments, + :datetime => :committed_on, + :url => Proc.new {|o| {:controller => 'repositories', :action => 'revision', :id => o.repository.project, :repository_id => o.repository.identifier_param, :rev => o.identifier}} + + acts_as_searchable :columns => 'comments', + :include => {:repository => :project}, + :project_key => "#{Repository.table_name}.project_id", + :date_column => 'committed_on' + + acts_as_activity_provider :timestamp => "#{table_name}.committed_on", + :author_key => :user_id, + :find_options => {:include => [:user, {:repository => :project}]} + validates :repository_id, presence: true + validates :revision, presence: true, uniqueness: {scope: :repository_id} + validates :committed_on, presence: true + validates :commit_date, presence: true + validates :scmid, uniqueness: {scope: :repository_id, allow_nil: true} + + scope :visible, lambda {|*args| + includes(:repository => :project).where(Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args)) + } + + after_create :scan_for_issues,:refresh_changests#:be_user_score # user_score + after_update :be_user_score + after_destroy :down_user_score + before_create :before_create_cs + + # fq + # after_create :act_as_activity + # end + + def revision=(r) + write_attribute :revision, (r.nil? ? nil : r.to_s) + end + + # Returns the identifier of this changeset; depending on repository backends + def identifier + if repository.class.respond_to? :changeset_identifier + repository.class.changeset_identifier self + else + revision.to_s + end + end + + def committed_on=(date) + self.commit_date = date + super + end + + # Returns the readable identifier + def format_identifier + if repository.class.respond_to? :format_changeset_identifier + repository.class.format_changeset_identifier self + else + identifier + end + end + + def project + unless repository.nil? + repository.project + end + end + + def author + user || committer.to_s.split('<').first + end + + def before_create_cs + self.committer = self.class.to_utf8(self.committer, repository.repo_log_encoding) + self.comments = self.class.normalize_comments( + self.comments, repository.repo_log_encoding) + self.user = repository.find_committer_user(self.committer) + end + + def scan_for_issues + scan_comment_for_issue_ids + end + + TIMELOG_RE = / + ( + ((\d+)(h|hours?))((\d+)(m|min)?)? + | + ((\d+)(h|hours?|m|min)) + | + (\d+):(\d+) + | + (\d+([\.,]\d+)?)h? + ) + /x + + def scan_comment_for_issue_ids + return if comments.blank? + # keywords used to reference issues + ref_keywords = Setting.commit_ref_keywords.downcase.split(",").collect(&:strip) + ref_keywords_any = ref_keywords.delete('*') + # keywords used to fix issues + fix_keywords = Setting.commit_fix_keywords.downcase.split(",").collect(&:strip) + + kw_regexp = (ref_keywords + fix_keywords).collect{|kw| Regexp.escape(kw)}.join("|") + + referenced_issues = [] + + comments.scan(/([\s\(\[,-]|^)((#{kw_regexp})[\s:]+)?(#\d+(\s+@#{TIMELOG_RE})?([\s,;&]+#\d+(\s+@#{TIMELOG_RE})?)*)(?=[[:punct:]]|\s|<|$)/i) do |match| + action, refs = match[2], match[3] + next unless action.present? || ref_keywords_any + + refs.scan(/#(\d+)(\s+@#{TIMELOG_RE})?/).each do |m| + issue, hours = find_referenced_issue_by_id(m[0].to_i), m[2] + if issue + referenced_issues << issue + fix_issue(issue) if fix_keywords.include?(action.to_s.downcase) + log_time(issue, hours) if hours && Setting.commit_logtime_enabled? + end + end + end + + referenced_issues.uniq! + self.issues = referenced_issues unless referenced_issues.empty? + end + + def short_comments + @short_comments || split_comments.first + end + + def long_comments + @long_comments || split_comments.last + end + + def text_tag(ref_project=nil) + tag = if scmid? + "commit:#{scmid}" + else + "r#{revision}" + end + if repository && repository.identifier.present? + tag = "#{repository.identifier}|#{tag}" + end + if ref_project && project && ref_project != project + tag = "#{project.identifier}:#{tag}" + end + tag + end + + # Returns the title used for the changeset in the activity/search results + def title + repo = (repository && repository.identifier.present?) ? " (#{repository.identifier})" : '' + comm = short_comments.blank? ? '' : (': ' + short_comments) + "#{l(:label_revision)} #{format_identifier}#{repo}#{comm}" + end + + # Returns the previous changeset + def previous + @previous ||= Changeset.where(["id < ? AND repository_id = ?", id, repository_id]).order('id DESC').first + end + + # Returns the next changeset + def next + @next ||= Changeset.where(["id > ? AND repository_id = ?", id, repository_id]).order('id ASC').first + end + + # Creates a new Change from it's common parameters + def create_change(change) + Change.create(:changeset => self, + :action => change[:action], + :path => change[:path], + :from_path => change[:from_path], + :from_revision => change[:from_revision]) + end + + # Finds an issue that can be referenced by the commit message + def find_referenced_issue_by_id(id) + return nil if id.blank? + issue = Issue.find_by_id(id.to_i, :include => :project) + if Setting.commit_cross_project_ref? + # all issues can be referenced/fixed + elsif issue + # issue that belong to the repository project, a subproject or a parent project only + unless issue.project && + (project == issue.project || project.is_ancestor_of?(issue.project) || + project.is_descendant_of?(issue.project)) + issue = nil + end + end + issue + end + + private + + def act_as_activity + self.acts << Activity.new(:user_id => self.user_id) + end + + def fix_issue(issue) + status = IssueStatus.find_by_id(Setting.commit_fix_status_id.to_i) + if status.nil? + logger.warn("No status matches commit_fix_status_id setting (#{Setting.commit_fix_status_id})") if logger + return issue + end + + # the issue may have been updated by the closure of another one (eg. duplicate) + issue.reload + # don't change the status is the issue is closed + return if issue.status && issue.status.is_closed? + + journal = issue.init_journal(user || User.anonymous, ll(Setting.default_language, :text_status_changed_by_changeset, text_tag(issue.project))) + issue.status = status + unless Setting.commit_fix_done_ratio.blank? + issue.done_ratio = Setting.commit_fix_done_ratio.to_i + end + Redmine::Hook.call_hook(:model_changeset_scan_commit_for_issue_ids_pre_issue_update, + { :changeset => self, :issue => issue }) + unless issue.save + logger.warn("Issue ##{issue.id} could not be saved by changeset #{id}: #{issue.errors.full_messages}") if logger + end + issue + end + + def log_time(issue, hours) + time_entry = TimeEntry.new( + :user => user, + :hours => hours, + :issue => issue, + :spent_on => commit_date, + :comments => l(:text_time_logged_by_changeset, :value => text_tag(issue.project), + :locale => Setting.default_language) + ) + time_entry.activity = log_time_activity unless log_time_activity.nil? + + unless time_entry.save + logger.warn("TimeEntry could not be created by changeset #{id}: #{time_entry.errors.full_messages}") if logger + end + time_entry + end + + def log_time_activity + if Setting.commit_logtime_activity_id.to_i > 0 + TimeEntryActivity.find_by_id(Setting.commit_logtime_activity_id.to_i) + end + end + + def split_comments + comments =~ /\A(.+?)\r?\n(.*)$/m + @short_comments = $1 || comments + @long_comments = $2.to_s.strip + return @short_comments, @long_comments + end + + public + + # Strips and reencodes a commit log before insertion into the database + def self.normalize_comments(str, encoding) + Changeset.to_utf8(str.to_s.strip, encoding) + end + + def self.to_utf8(str, encoding) + Redmine::CodesetUtil.to_utf8(str, encoding) + end + + private + + # update user score + def be_user_score + UserScore.project(:push_code, self.user,self, { changeset_id: self.id }) + unless self.user.nil? + #更新用户等级 + UserLevels.update_user_level(self.user) + update_changeset(self.user,1) + update_changeset(self.user,2,self.repository.project) + end + + end + + #积分刷新 + def down_user_score + UserLevels.update_user_level(self.user) + update_changeset(self.user,1) + update_changeset(self.user,2,self.repository.project) + end + + #刷新本次提交(补全相关信息如:user_id等) + def refresh_changests + unless self.repository.nil? + self.repository.fetch_changesets if Setting.autofetch_changesets? + end + end + +end diff --git a/app/models/comment.rb b/app/models/comment.rb index f261fcb9e..539c62e85 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -1,24 +1,24 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class Comment < ActiveRecord::Base - include Redmine::SafeAttributes - belongs_to :commented, :polymorphic => true, :counter_cache => true - belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' - validates_presence_of :commented, :author, :comments - safe_attributes 'comments' -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Comment < ActiveRecord::Base + include Redmine::SafeAttributes + belongs_to :commented, :polymorphic => true, :counter_cache => true + belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' + validates_presence_of :commented, :author, :comments + safe_attributes 'comments' +end diff --git a/app/models/contest.rb b/app/models/contest.rb index 59f8ee470..ad54e8fb4 100644 --- a/app/models/contest.rb +++ b/app/models/contest.rb @@ -1,134 +1,134 @@ -class Contest < ActiveRecord::Base - attr_accessible :author_id, :budget, :commit, :deadline, :description, :name, :password - include Redmine::SafeAttributes - - belongs_to :author, :class_name => 'User', :foreign_key => :author_id - has_many :contesting_projects, :dependent => :destroy - has_many :projects, :through => :contesting_projects - has_many :contesting_softapplications, :dependent => :destroy - has_many :softapplications, :through => :contesting_softapplications, :dependent => :destroy - has_many :projects_member, :class_name => 'User', :through => :projects - has_many :journals_for_messages, :as => :jour, :dependent => :destroy - has_many :acts, :class_name => 'Activity', :as => :act, :dependent => :destroy - has_many :join_in_competitions, foreign_key: 'competition_id', :dependent => :destroy - has_many :join_in_contests, class_name: 'JoinInCompetition', foreign_key: 'competition_id', :dependent => :destroy - has_many :praise_tread, as: :praise_tread_object, dependent: :destroy - has_many :contestnotifications, :dependent => :destroy, :include => :author - - - - acts_as_attachable - - NAME_LENGTH_LIMIT = 60 - DESCRIPTION_LENGTH_LIMIT = 250 - validates :name, length: {maximum: NAME_LENGTH_LIMIT}, presence: true - validates :description, length: {maximum: DESCRIPTION_LENGTH_LIMIT} - validates :author_id, presence: true - validates :budget, presence: true - validates :deadline, format: {:with =>/^[1-9][0-9]{3}\-0?[1-9]|1[12]\-0?[1-9]|[12]\d|3[01]$/} - validate :validate_user - after_create :act_as_activity - - scope :visible, lambda {|*args| - nil - } - - scope :like, lambda {|arg| - if arg.blank? - where(nil) - else - pattern = "%#{arg.to_s.strip.downcase}%" - where("LOWER(id) LIKE :p OR LOWER(name) LIKE :p OR LOWER(description) LIKE :p", :p => pattern) - end - } - - acts_as_watchable - acts_as_taggable - - acts_as_event :title => Proc.new {|o| "#{l(:label_requirement)} ##{o.id}: #{o.name}" }, - :description => :description, - :author => :author, - :url => Proc.new {|o| {:controller => 'contests', :action => 'show_contest', :id => o.id}} - - acts_as_activity_provider :find_options => {:include => [:projects, :author]}, - :author_key => :author_id - - safe_attributes 'name', - 'description', - 'budget', - 'deadline', - 'password' - - - def add_jour(user, notes, reference_user_id = 0, options = {}) - if options.count == 0 - self.journals_for_messages << JournalsForMessage.new(:user_id => user.id, :notes => notes, :reply_id => reference_user_id) - else - jfm = self.journals_for_messages.build(options) - jfm.save - jfm - end - end - - # modified by longjun - # 这个函数没有用到 - # def self.creat_contests(budget, deadline, name, description=nil) - # self.create(:author_id => User.current.id, :budget => budget, - # :deadline => deadline, :name => name, :description => description, :commit => 0) - # end - # end longjun - - def update_contests(budget, deadline, name, description=nil) - if(User.current.id == self.author_id) - self.name = name - self.budget = budget - self.deadline = deadline - self.description = description - self.save - end - end - - def delete_contests - unless self.nil? - if User.current.id == self.author_id - self.destroy - end - end - end - - # Closes open and locked project versions that are completed - def close_completed_versions_contest - Version.transaction do - versions.where(:status => %w(open locked)).all.each do |version| - if version.completed? - version.update_attribute(:status, 'closed') - end - end - end - end - - def set_commit(commit) - self.update_attribute(:commit, commit) - end - - private - - def validate_user - errors.add :author_id, :invalid if author.nil? || !author.active? - end - - - def act_as_activity - self.acts << Activity.new(:user_id => self.author_id) - end - - def validate_contest_manager(user_id) - unless user_id.nil? - if self.author_id == user_id - return true - else - return false - end - end - end -end +class Contest < ActiveRecord::Base + attr_accessible :author_id, :budget, :commit, :deadline, :description, :name, :password + include Redmine::SafeAttributes + + belongs_to :author, :class_name => 'User', :foreign_key => :author_id + has_many :contesting_projects, :dependent => :destroy + has_many :projects, :through => :contesting_projects + has_many :contesting_softapplications, :dependent => :destroy + has_many :softapplications, :through => :contesting_softapplications, :dependent => :destroy + has_many :projects_member, :class_name => 'User', :through => :projects + has_many :journals_for_messages, :as => :jour, :dependent => :destroy + has_many :acts, :class_name => 'Activity', :as => :act, :dependent => :destroy + has_many :join_in_competitions, foreign_key: 'competition_id', :dependent => :destroy + has_many :join_in_contests, class_name: 'JoinInCompetition', foreign_key: 'competition_id', :dependent => :destroy + has_many :praise_tread, as: :praise_tread_object, dependent: :destroy + has_many :contestnotifications, :dependent => :destroy, :include => :author + + + + acts_as_attachable + + NAME_LENGTH_LIMIT = 60 + DESCRIPTION_LENGTH_LIMIT = 250 + validates :name, length: {maximum: NAME_LENGTH_LIMIT}, presence: true + validates :description, length: {maximum: DESCRIPTION_LENGTH_LIMIT} + validates :author_id, presence: true + validates :budget, presence: true + validates :deadline, format: {:with =>/^[1-9][0-9]{3}\-0?[1-9]|1[12]\-0?[1-9]|[12]\d|3[01]$/} + validate :validate_user + after_create :act_as_activity + + scope :visible, lambda {|*args| + nil + } + + scope :like, lambda {|arg| + if arg.blank? + where(nil) + else + pattern = "%#{arg.to_s.strip.downcase}%" + where("LOWER(id) LIKE :p OR LOWER(name) LIKE :p OR LOWER(description) LIKE :p", :p => pattern) + end + } + + acts_as_watchable + acts_as_taggable + + acts_as_event :title => Proc.new {|o| "#{l(:label_requirement)} ##{o.id}: #{o.name}" }, + :description => :description, + :author => :author, + :url => Proc.new {|o| {:controller => 'contests', :action => 'show_contest', :id => o.id}} + + acts_as_activity_provider :find_options => {:include => [:projects, :author]}, + :author_key => :author_id + + safe_attributes 'name', + 'description', + 'budget', + 'deadline', + 'password' + + + def add_jour(user, notes, reference_user_id = 0, options = {}) + if options.count == 0 + self.journals_for_messages << JournalsForMessage.new(:user_id => user.id, :notes => notes, :reply_id => reference_user_id) + else + jfm = self.journals_for_messages.build(options) + jfm.save + jfm + end + end + + # modified by longjun + # 这个函数没有用到 + # def self.creat_contests(budget, deadline, name, description=nil) + # self.create(:author_id => User.current.id, :budget => budget, + # :deadline => deadline, :name => name, :description => description, :commit => 0) + # end + # end longjun + + def update_contests(budget, deadline, name, description=nil) + if(User.current.id == self.author_id) + self.name = name + self.budget = budget + self.deadline = deadline + self.description = description + self.save + end + end + + def delete_contests + unless self.nil? + if User.current.id == self.author_id + self.destroy + end + end + end + + # Closes open and locked project versions that are completed + def close_completed_versions_contest + Version.transaction do + versions.where(:status => %w(open locked)).all.each do |version| + if version.completed? + version.update_attribute(:status, 'closed') + end + end + end + end + + def set_commit(commit) + self.update_attribute(:commit, commit) + end + + private + + def validate_user + errors.add :author_id, :invalid if author.nil? || !author.active? + end + + + def act_as_activity + self.acts << Activity.new(:user_id => self.author_id) + end + + def validate_contest_manager(user_id) + unless user_id.nil? + if self.author_id == user_id + return true + else + return false + end + end + end +end diff --git a/app/models/contest_notification.rb b/app/models/contest_notification.rb index 79d8bc254..1613f1378 100644 --- a/app/models/contest_notification.rb +++ b/app/models/contest_notification.rb @@ -1,4 +1,4 @@ -class ContestNotification < ActiveRecord::Base - attr_accessible :content, :title - validates :title, length: {maximum: 30} -end +class ContestNotification < ActiveRecord::Base + attr_accessible :content, :title + validates :title, length: {maximum: 30} +end diff --git a/app/models/contesting_project.rb b/app/models/contesting_project.rb index 9828bb598..ced787cbd 100644 --- a/app/models/contesting_project.rb +++ b/app/models/contesting_project.rb @@ -1,53 +1,53 @@ -class ContestingProject < ActiveRecord::Base - attr_accessible :contest_id, :description, :project_id, :user_id, :reward - - belongs_to :contest - belongs_to :project - belongs_to :user - - DESCRIPTION_LENGTH_LIMIT = 500 - validates :description, length: {maximum:DESCRIPTION_LENGTH_LIMIT } - validates :user_id, presence: true - validates :contest_id, presence: true, uniqueness: {scope: :project_id} - validates :project_id, presence: true - - validate :validate_user - validate :validate_contest - validate :validate_project - - def self.create_contesting(contest_id, project_id, description = nil) - self.create(:user_id => User.current.id, :contest_id => contest_id, - :project_id => project_id, :description => description) - end - - - def update_reward(which) - self.update_attribute(:reward,which) - end - - def get_reward - self.reward - end - - def cancel_contesting - unless self.nil? - if User.current.id == self.user_id - self.destroy - end - end - end - - private - - def validate_user - errors.add :user_id, :invalid if user.nil? || !user.active? - end - - def validate_contest - errors.add :contest_id, :invalid if contest.nil? - end - - def validate_project - errors.add :project_id, :invalid if project.nil? - end -end +class ContestingProject < ActiveRecord::Base + attr_accessible :contest_id, :description, :project_id, :user_id, :reward + + belongs_to :contest + belongs_to :project + belongs_to :user + + DESCRIPTION_LENGTH_LIMIT = 500 + validates :description, length: {maximum:DESCRIPTION_LENGTH_LIMIT } + validates :user_id, presence: true + validates :contest_id, presence: true, uniqueness: {scope: :project_id} + validates :project_id, presence: true + + validate :validate_user + validate :validate_contest + validate :validate_project + + def self.create_contesting(contest_id, project_id, description = nil) + self.create(:user_id => User.current.id, :contest_id => contest_id, + :project_id => project_id, :description => description) + end + + + def update_reward(which) + self.update_attribute(:reward,which) + end + + def get_reward + self.reward + end + + def cancel_contesting + unless self.nil? + if User.current.id == self.user_id + self.destroy + end + end + end + + private + + def validate_user + errors.add :user_id, :invalid if user.nil? || !user.active? + end + + def validate_contest + errors.add :contest_id, :invalid if contest.nil? + end + + def validate_project + errors.add :project_id, :invalid if project.nil? + end +end diff --git a/app/models/course.rb b/app/models/course.rb index 36329ccda..1f0cb0979 100644 --- a/app/models/course.rb +++ b/app/models/course.rb @@ -1,310 +1,310 @@ -class Course < ActiveRecord::Base - include Redmine::SafeAttributes - - STATUS_ACTIVE = 1 - STATUS_CLOSED = 5 - STATUS_ARCHIVED = 9 - - attr_accessible :code, :extra, :name, :state, :tea_id, :time , :location, :state, :term, :password,:is_public,:description,:class_period - belongs_to :project, :class_name => 'Course', :foreign_key => :extra, primary_key: :identifier - belongs_to :teacher, :class_name => 'User', :foreign_key => :tea_id # 定义一个方法teacher,该方法通过tea_id来调用User表 - belongs_to :school, :class_name => 'School', :foreign_key => :school_id #定义一个方法school,该方法通过school_id来调用School表 - has_many :bid - has_many :members, :include => [:principal, :roles], :conditions => "#{Principal.table_name}.type='User' AND #{Principal.table_name}.status=#{Principal::STATUS_ACTIVE}" - has_many :memberships, :class_name => 'Member' - has_many :member_principals, :class_name => 'Member', - :include => :principal, - :conditions => "#{Principal.table_name}.type='Group' OR (#{Principal.table_name}.type='User' AND #{Principal.table_name}.status=#{Principal::STATUS_ACTIVE})" - has_many :principals, :through => :member_principals, :source => :principal - has_many :users, :through => :members - has_many :homeworks, :through => :homework_for_courses, :source => :bid, :dependent => :destroy - has_many :journals_for_messages, :as => :jour, :dependent => :destroy - has_many :homework_for_courses, :dependent => :destroy - has_many :student, :class_name => 'StudentsForCourse', :source => :user - has_many :course_infos, :class_name => 'CourseInfos',:dependent => :destroy - has_many :enabled_modules, :dependent => :delete_all - has_many :boards, :dependent => :destroy, :order => "position ASC" - #has_many :course_journals_for_messages, :class_name => 'CourseJournalsForMessage', :as => :jour, :dependent => :destroy - has_many :news, :dependent => :destroy, :include => :author - has_one :course_status, :class_name => "CourseStatus", :dependent => :destroy - - acts_as_taggable - acts_as_nested_set :order => 'name', :dependent => :destroy - acts_as_attachable :view_permission => :view_files, - :delete_permission => :manage_files - - validates :password, presence: true - validates :term, presence: true - validates :name, presence: true - validates :class_period, presence: true,format: {:with =>/^\d*$/} - before_save :self_validate - after_create :create_board_sync - before_destroy :delete_all_members - - safe_attributes 'extra', - 'time', - 'name', - 'extra', - 'code', - 'location', - 'tea_id', - 'password', - 'term', - 'is_public', - 'description', - 'class_period' - - acts_as_customizable - - scope :all_course - scope :active, lambda { where(:status => STATUS_ACTIVE) } - scope :status, lambda {|arg| where(arg.blank? ? nil : {:status => arg.to_i}) } - scope :all_public, lambda { where(:is_public => true) } - scope :visible, lambda {|*args| where(Course.visible_condition(args.shift || User.current, *args)) } - scope :allowed_to, lambda {|*args| - user = User.current - permission = nil - if args.first.is_a?(Symbol) - permission = args.shift - else - user = args.shift - permission = args.shift - end - where(Course.allowed_to_condition(user, permission, *args)) - } - scope :like, lambda {|arg| - if arg.blank? - where(nil) - else - pattern = "%#{arg.to_s.strip.downcase}%" - where(" LOWER(name) LIKE :p ", :p => pattern) - end - } - - def visible?(user=User.current) - user.allowed_to?(:view_course, self) - end - - def parent_id_changed? - false - end - - # Returns the mail adresses of users that should be always notified on project events - def recipients - notified_users.collect {|user| user.mail} - end - - # Returns the users that should be notified on project events - def notified_users - # TODO: User part should be extracted to User#notify_about? - members.select {|m| m.principal.present? && (m.mail_notification? || m.principal.mail_notification == 'all')}.collect {|m| m.principal} - end - - - # 课程的短描述信息 - def short_description(length = 255) - description.gsub(/<\/?.*?>/,"").html_safe if description - #description.gsub(/^(.{#{length}}[^\n\r]*).*$/m, '\1...').strip if description - end - - # 课程的短名称信息 - def short_name(length = 8) - name.gsub(/<\/?.*?>/,"").html_safe if name - end - - def strip_html(html) - return html if html.empty? || !html.include?('<') - output = "" - tokenizer = HTML::Tokenizer.new(html) - while token = tokenizer.next - node = HTML::Node.parse(nil, 0, 0, token, false) - output += token unless (node.kind_of? HTML::Tag) or (token =~ /^ ["#{Attachmentstype.table_name}.typeId= ?",self.attachmenttype ]) - end - - - # 获取资源后缀名列表 - def contenttypes - attachmenttypes - if @attachmenttypes.length >0 - @attachmenttypes.last().suffixArr - end - end - - def active? - self.status == STATUS_ACTIVE - end - - #课程权限判断 - def allows_to?(action) - if archived? - # No action allowed on archived projects - return false - end - unless active? || Redmine::AccessControl.read_action?(action) - # No write action allowed on closed projects - return false - end - # No action allowed on disabled modules - if action.is_a? Hash - allowed_actions.include? "#{action[:controller]}/#{action[:action]}" - else - allowed_permissions.include? action - end - end - - # 课程允许的权限集合 - def allowed_permissions - @allowed_permissions ||= begin - module_names = enabled_modules.all(:select => :name).collect {|m| m.name} - Redmine::AccessControl.modules_permissions(module_names).collect {|p| p.name} - end - end - - # 课程允许的动作集合 - def allowed_actions - @actions_allowed ||= allowed_permissions.inject([]) { |actions, permission| actions += Redmine::AccessControl.allowed_actions(permission) }.flatten - end - - # 返回用户组可以访问的课程 - def users_by_role - members.includes(:user, :roles).all.inject({}) do |h, m| - m.roles.each do |r| - h[r] ||= [] - h[r] << m.user - end - h - end - end - - #自定义验证 - def self_validate - - end - - # 创建课程讨论区 - def create_board_sync - @board = self.boards.build - self.name=" #{l(:label_borad_course) }" - @board.name = self.name - @board.description = self.name.to_s - @board.project_id = -1 - if @board.save - logger.debug "[Course Model] ===> #{@board.to_json}" - else - logger.error "[Course Model] ===> Auto create board when course saved, because #{@board.full_messages}" - end - end - - # 新增课程留言 - # add by nwb - def self.add_new_jour(user, notes, id, options={}) - course = Course.find(id) - if options.count == 0 - pjfm = course.journals_for_messages.build(:user_id => user.id, :notes => notes, :reply_id => 0) - else - pjfm = course.journals_for_messages.build(options) - end - pjfm.save - pjfm - end - - # 删除课程所有成员 - def delete_all_members - if self.members && self.members.count > 0 - me, mr = Member.table_name, MemberRole.table_name - connection.delete("DELETE FROM #{mr} WHERE #{mr}.member_id IN (SELECT #{me}.id FROM #{me} WHERE #{me}.course_id = #{id})") - Member.delete_all(['course_id = ?', id]) - end - end - - def get_endup_time - begin - end_time = Time.parse(self.endup_time) - rescue Exception => e - end_time = Time.parse("3000-01-01") - Rails.logger.error "[Error] course endup_time error. ===> #{e}" - ensure - return end_time - end - end - - def get_time - begin - time = Date.new(self.time).to_time - rescue Exception => e - time = Time.parse("3000-01-01") - Rails.logger.error "[Error] course time error. ===> #{e}" - ensure - return time - end - end - - def self.allowed_to_condition(user, permission, options={}) - perm = Redmine::AccessControl.permission(permission) - base_statement = (perm && perm.read? ? "#{Course.table_name}.status <> #{Course::STATUS_ARCHIVED}" : "#{Course.table_name}.status = #{Course::STATUS_ACTIVE}") - if perm && perm.course_module - base_statement << " AND #{Course.table_name}.id IN (SELECT em.course_id FROM #{EnabledModule.table_name} em WHERE em.name='#{perm.course_module}')" - end - - if options[:course] - course_statement = "#{Course.table_name}.id = #{options[:course].id}" - course_statement << " OR (#{Course.table_name}.lft > #{options[:course].lft} AND #{Course.table_name}.rgt < #{options[:course].rgt})" if options[:with_subcourses] - base_statement = "(#{course_statement}) AND (#{base_statement})" - end - - if user.admin? - base_statement - else - statement_by_role = {} - unless options[:member] - role = user.logged? ? Role.non_member : Role.anonymous - if role.allowed_to?(permission) - statement_by_role[role] = "#{Course.table_name}.is_public = #{connection.quoted_true}" - end - end - if user.logged? - user.courses_by_role.each do |role, courses| - if role.allowed_to?(permission) && courses.any? - statement_by_role[role] = "#{Course.table_name}.id IN (#{courses.collect(&:id).join(',')})" - end - end - end - if statement_by_role.empty? - "1=0" - else - if block_given? - statement_by_role.each do |role, statement| - if s = yield(role, user) - statement_by_role[role] = "(#{statement} AND (#{s}))" - end - end - end - "((#{base_statement}) AND (#{statement_by_role.values.join(' OR ')}))" - end - end - end - - #项目与课程分离后,很多课程的名称等信息为空,这些数据信息存储在项目表中!!就是数据兼容的问题 - #def name - # read_attribute('name') || Project.find_by_identifier(self.extra).try(:name) - #end -end +class Course < ActiveRecord::Base + include Redmine::SafeAttributes + + STATUS_ACTIVE = 1 + STATUS_CLOSED = 5 + STATUS_ARCHIVED = 9 + + attr_accessible :code, :extra, :name, :state, :tea_id, :time , :location, :state, :term, :password,:is_public,:description,:class_period + belongs_to :project, :class_name => 'Course', :foreign_key => :extra, primary_key: :identifier + belongs_to :teacher, :class_name => 'User', :foreign_key => :tea_id # 定义一个方法teacher,该方法通过tea_id来调用User表 + belongs_to :school, :class_name => 'School', :foreign_key => :school_id #定义一个方法school,该方法通过school_id来调用School表 + has_many :bid + has_many :members, :include => [:principal, :roles], :conditions => "#{Principal.table_name}.type='User' AND #{Principal.table_name}.status=#{Principal::STATUS_ACTIVE}" + has_many :memberships, :class_name => 'Member' + has_many :member_principals, :class_name => 'Member', + :include => :principal, + :conditions => "#{Principal.table_name}.type='Group' OR (#{Principal.table_name}.type='User' AND #{Principal.table_name}.status=#{Principal::STATUS_ACTIVE})" + has_many :principals, :through => :member_principals, :source => :principal + has_many :users, :through => :members + has_many :homeworks, :through => :homework_for_courses, :source => :bid, :dependent => :destroy + has_many :journals_for_messages, :as => :jour, :dependent => :destroy + has_many :homework_for_courses, :dependent => :destroy + has_many :student, :class_name => 'StudentsForCourse', :source => :user + has_many :course_infos, :class_name => 'CourseInfos',:dependent => :destroy + has_many :enabled_modules, :dependent => :delete_all + has_many :boards, :dependent => :destroy, :order => "position ASC" + #has_many :course_journals_for_messages, :class_name => 'CourseJournalsForMessage', :as => :jour, :dependent => :destroy + has_many :news, :dependent => :destroy, :include => :author + has_one :course_status, :class_name => "CourseStatus", :dependent => :destroy + + acts_as_taggable + acts_as_nested_set :order => 'name', :dependent => :destroy + acts_as_attachable :view_permission => :view_files, + :delete_permission => :manage_files + + validates :password, presence: true + validates :term, presence: true + validates :name, presence: true + validates :class_period, presence: true,format: {:with =>/^\d*$/} + before_save :self_validate + after_create :create_board_sync + before_destroy :delete_all_members + + safe_attributes 'extra', + 'time', + 'name', + 'extra', + 'code', + 'location', + 'tea_id', + 'password', + 'term', + 'is_public', + 'description', + 'class_period' + + acts_as_customizable + + scope :all_course + scope :active, lambda { where(:status => STATUS_ACTIVE) } + scope :status, lambda {|arg| where(arg.blank? ? nil : {:status => arg.to_i}) } + scope :all_public, lambda { where(:is_public => true) } + scope :visible, lambda {|*args| where(Course.visible_condition(args.shift || User.current, *args)) } + scope :allowed_to, lambda {|*args| + user = User.current + permission = nil + if args.first.is_a?(Symbol) + permission = args.shift + else + user = args.shift + permission = args.shift + end + where(Course.allowed_to_condition(user, permission, *args)) + } + scope :like, lambda {|arg| + if arg.blank? + where(nil) + else + pattern = "%#{arg.to_s.strip.downcase}%" + where(" LOWER(name) LIKE :p ", :p => pattern) + end + } + + def visible?(user=User.current) + user.allowed_to?(:view_course, self) + end + + def parent_id_changed? + false + end + + # Returns the mail adresses of users that should be always notified on project events + def recipients + notified_users.collect {|user| user.mail} + end + + # Returns the users that should be notified on project events + def notified_users + # TODO: User part should be extracted to User#notify_about? + members.select {|m| m.principal.present? && (m.mail_notification? || m.principal.mail_notification == 'all')}.collect {|m| m.principal} + end + + + # 课程的短描述信息 + def short_description(length = 255) + description.gsub(/<\/?.*?>/,"").html_safe if description + #description.gsub(/^(.{#{length}}[^\n\r]*).*$/m, '\1...').strip if description + end + + # 课程的短名称信息 + def short_name(length = 8) + name.gsub(/<\/?.*?>/,"").html_safe if name + end + + def strip_html(html) + return html if html.empty? || !html.include?('<') + output = "" + tokenizer = HTML::Tokenizer.new(html) + while token = tokenizer.next + node = HTML::Node.parse(nil, 0, 0, token, false) + output += token unless (node.kind_of? HTML::Tag) or (token =~ /^ ["#{Attachmentstype.table_name}.typeId= ?",self.attachmenttype ]) + end + + + # 获取资源后缀名列表 + def contenttypes + attachmenttypes + if @attachmenttypes.length >0 + @attachmenttypes.last().suffixArr + end + end + + def active? + self.status == STATUS_ACTIVE + end + + #课程权限判断 + def allows_to?(action) + if archived? + # No action allowed on archived projects + return false + end + unless active? || Redmine::AccessControl.read_action?(action) + # No write action allowed on closed projects + return false + end + # No action allowed on disabled modules + if action.is_a? Hash + allowed_actions.include? "#{action[:controller]}/#{action[:action]}" + else + allowed_permissions.include? action + end + end + + # 课程允许的权限集合 + def allowed_permissions + @allowed_permissions ||= begin + module_names = enabled_modules.all(:select => :name).collect {|m| m.name} + Redmine::AccessControl.modules_permissions(module_names).collect {|p| p.name} + end + end + + # 课程允许的动作集合 + def allowed_actions + @actions_allowed ||= allowed_permissions.inject([]) { |actions, permission| actions += Redmine::AccessControl.allowed_actions(permission) }.flatten + end + + # 返回用户组可以访问的课程 + def users_by_role + members.includes(:user, :roles).all.inject({}) do |h, m| + m.roles.each do |r| + h[r] ||= [] + h[r] << m.user + end + h + end + end + + #自定义验证 + def self_validate + + end + + # 创建课程讨论区 + def create_board_sync + @board = self.boards.build + self.name=" #{l(:label_borad_course) }" + @board.name = self.name + @board.description = self.name.to_s + @board.project_id = -1 + if @board.save + logger.debug "[Course Model] ===> #{@board.to_json}" + else + logger.error "[Course Model] ===> Auto create board when course saved, because #{@board.full_messages}" + end + end + + # 新增课程留言 + # add by nwb + def self.add_new_jour(user, notes, id, options={}) + course = Course.find(id) + if options.count == 0 + pjfm = course.journals_for_messages.build(:user_id => user.id, :notes => notes, :reply_id => 0) + else + pjfm = course.journals_for_messages.build(options) + end + pjfm.save + pjfm + end + + # 删除课程所有成员 + def delete_all_members + if self.members && self.members.count > 0 + me, mr = Member.table_name, MemberRole.table_name + connection.delete("DELETE FROM #{mr} WHERE #{mr}.member_id IN (SELECT #{me}.id FROM #{me} WHERE #{me}.course_id = #{id})") + Member.delete_all(['course_id = ?', id]) + end + end + + def get_endup_time + begin + end_time = Time.parse(self.endup_time) + rescue Exception => e + end_time = Time.parse("3000-01-01") + Rails.logger.error "[Error] course endup_time error. ===> #{e}" + ensure + return end_time + end + end + + def get_time + begin + time = Date.new(self.time).to_time + rescue Exception => e + time = Time.parse("3000-01-01") + Rails.logger.error "[Error] course time error. ===> #{e}" + ensure + return time + end + end + + def self.allowed_to_condition(user, permission, options={}) + perm = Redmine::AccessControl.permission(permission) + base_statement = (perm && perm.read? ? "#{Course.table_name}.status <> #{Course::STATUS_ARCHIVED}" : "#{Course.table_name}.status = #{Course::STATUS_ACTIVE}") + if perm && perm.course_module + base_statement << " AND #{Course.table_name}.id IN (SELECT em.course_id FROM #{EnabledModule.table_name} em WHERE em.name='#{perm.course_module}')" + end + + if options[:course] + course_statement = "#{Course.table_name}.id = #{options[:course].id}" + course_statement << " OR (#{Course.table_name}.lft > #{options[:course].lft} AND #{Course.table_name}.rgt < #{options[:course].rgt})" if options[:with_subcourses] + base_statement = "(#{course_statement}) AND (#{base_statement})" + end + + if user.admin? + base_statement + else + statement_by_role = {} + unless options[:member] + role = user.logged? ? Role.non_member : Role.anonymous + if role.allowed_to?(permission) + statement_by_role[role] = "#{Course.table_name}.is_public = #{connection.quoted_true}" + end + end + if user.logged? + user.courses_by_role.each do |role, courses| + if role.allowed_to?(permission) && courses.any? + statement_by_role[role] = "#{Course.table_name}.id IN (#{courses.collect(&:id).join(',')})" + end + end + end + if statement_by_role.empty? + "1=0" + else + if block_given? + statement_by_role.each do |role, statement| + if s = yield(role, user) + statement_by_role[role] = "(#{statement} AND (#{s}))" + end + end + end + "((#{base_statement}) AND (#{statement_by_role.values.join(' OR ')}))" + end + end + end + + #项目与课程分离后,很多课程的名称等信息为空,这些数据信息存储在项目表中!!就是数据兼容的问题 + #def name + # read_attribute('name') || Project.find_by_identifier(self.extra).try(:name) + #end +end diff --git a/app/models/course_status.rb b/app/models/course_status.rb index 85969e55e..2f9bdf564 100644 --- a/app/models/course_status.rb +++ b/app/models/course_status.rb @@ -1,5 +1,5 @@ -class CourseStatus < ActiveRecord::Base - attr_accessible :changesets_count, :course_ac_para, :course_id, :grade, :watchers_count - belongs_to :course - validates :course_id, presence: true,uniqueness: true -end +class CourseStatus < ActiveRecord::Base + attr_accessible :changesets_count, :course_ac_para, :course_id, :grade, :watchers_count + belongs_to :course + validates :course_id, presence: true,uniqueness: true +end diff --git a/app/models/enabled_module.rb b/app/models/enabled_module.rb index fe668e02c..e0353fa75 100644 --- a/app/models/enabled_module.rb +++ b/app/models/enabled_module.rb @@ -1,39 +1,39 @@ -# Redmine - project management software -# Copyright (C) 2006-2013 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class EnabledModule < ActiveRecord::Base - belongs_to :project - - validates_presence_of :name - validates_uniqueness_of :name, :scope => :project_id - - after_create :module_enabled - private - - # after_create callback used to do things when a module is enabled - def module_enabled - case name - when 'wiki' - # Create a wiki with a default start page - if project && project.wiki.nil? - Wiki.create(:project => project, :start_page => 'Wiki') - end - end - end - - -end +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class EnabledModule < ActiveRecord::Base + belongs_to :project + + validates_presence_of :name + validates_uniqueness_of :name, :scope => :project_id + + after_create :module_enabled + private + + # after_create callback used to do things when a module is enabled + def module_enabled + case name + when 'wiki' + # Create a wiki with a default start page + if project && project.wiki.nil? + Wiki.create(:project => project, :start_page => 'Wiki') + end + end + end + + +end diff --git a/app/models/softapplication.rb b/app/models/softapplication.rb index 9e469d2ac..c52d5e9aa 100644 --- a/app/models/softapplication.rb +++ b/app/models/softapplication.rb @@ -1,39 +1,39 @@ -class Softapplication < ActiveRecord::Base - attr_accessible :android_min_version_available, :app_type_id, :app_type_name, :description, :name, :user_id, :contest_id, :application_developers, :deposit_project_url, :deposit_project - acts_as_attachable :view_permission => :view_files - seems_rateable :allow_update => true, :dimensions => :quality - - - has_many :journals_for_messages, :as => :jour, :dependent => :destroy - has_many :contesting_softapplications, :dependent => :destroy - #has_many :projecting_softapplications, :dependent => :destroy - belongs_to :user - belongs_to :project - has_many :contests, :through => :contesting_softapplications - - validates_length_of :name, :maximum => 25 - validates_length_of :application_developers, :maximum => 125 - validates_length_of :android_min_version_available, :maximum => 125 - - def add_jour(user, notes, reference_user_id = 0, options = {}) - if options.count == 0 - self.journals_for_messages << JournalsForMessage.new(:user_id => user.id, :notes => notes, :reply_id => reference_user_id) - else - jfm = self.journals_for_messages.build(options) - jfm.save - jfm - end - end - def set_commit(commit) - self.update_attribute(:commit, commit) - end - - def editable_by? usr - usr.admin? || self.user == usr - end - - def destroyable_by? usr - self.user == usr || usr.admin? - end - -end +class Softapplication < ActiveRecord::Base + attr_accessible :android_min_version_available, :app_type_id, :app_type_name, :description, :name, :user_id, :contest_id, :application_developers, :deposit_project_url, :deposit_project + acts_as_attachable :view_permission => :view_files + seems_rateable :allow_update => true, :dimensions => :quality + + + has_many :journals_for_messages, :as => :jour, :dependent => :destroy + has_many :contesting_softapplications, :dependent => :destroy + #has_many :projecting_softapplications, :dependent => :destroy + belongs_to :user + belongs_to :project + has_many :contests, :through => :contesting_softapplications + + validates_length_of :name, :maximum => 25 + validates_length_of :application_developers, :maximum => 125 + validates_length_of :android_min_version_available, :maximum => 125 + + def add_jour(user, notes, reference_user_id = 0, options = {}) + if options.count == 0 + self.journals_for_messages << JournalsForMessage.new(:user_id => user.id, :notes => notes, :reply_id => reference_user_id) + else + jfm = self.journals_for_messages.build(options) + jfm.save + jfm + end + end + def set_commit(commit) + self.update_attribute(:commit, commit) + end + + def editable_by? usr + usr.admin? || self.user == usr + end + + def destroyable_by? usr + self.user == usr || usr.admin? + end + +end diff --git a/app/models/web_footer_company.rb b/app/models/web_footer_company.rb index bca8dfb5d..0743b6a9c 100644 --- a/app/models/web_footer_company.rb +++ b/app/models/web_footer_company.rb @@ -1,8 +1,8 @@ -class WebFooterCompany < ActiveRecord::Base - attr_accessible :logo_size, :name, :url - validates :name, presence: true, length: { maximum: 500 } - validates :url, length: { maximum: 500 }, - format: { with: /(http|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:\/~\+#]*[\w\-\@?^=%&\/~\+#])?/, - message: l(:is_not_url_error) - } -end +class WebFooterCompany < ActiveRecord::Base + attr_accessible :logo_size, :name, :url + validates :name, presence: true, length: { maximum: 500 } + validates :url, length: { maximum: 500 }, + format: { with: /(http|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:\/~\+#]*[\w\-\@?^=%&\/~\+#])?/, + message: l(:is_not_url_error) + } +end diff --git a/app/models/web_footer_oranizer.rb b/app/models/web_footer_oranizer.rb index f47d4131f..9a014ca83 100644 --- a/app/models/web_footer_oranizer.rb +++ b/app/models/web_footer_oranizer.rb @@ -1,3 +1,3 @@ -class WebFooterOranizer < ActiveRecord::Base - attr_accessible :description, :name -end +class WebFooterOranizer < ActiveRecord::Base + attr_accessible :description, :name +end diff --git a/app/views/admin/_tab_partial.html.erb b/app/views/admin/_tab_partial.html.erb index 86191fdb5..6b8788a90 100644 --- a/app/views/admin/_tab_partial.html.erb +++ b/app/views/admin/_tab_partial.html.erb @@ -1,8 +1,8 @@ ---
+- <%= link_to l(:label_project_first_page), {:action => 'first_page_made'}, class: "#{current_page?(first_page_made_path)? 'selected' : nil }" %>
-- <%= link_to l(:label_course_first_page), {:action => 'course_page_made'}, class: "#{current_page?(course_page_made_path)? 'selected' : nil }" %>
-- <%= link_to l(:label_contest_first_page), {:action => 'contest_page_made'}, class: "#{current_page?(contest_page_made_path)? 'selected' : nil }" %>
-- <%= link_to l(:label_web_footer_page), {:action => 'web_footer_made'}, class: "#{current_page?(web_footer_made_path)? 'selected' : nil }" %>
-+\ No newline at end of file diff --git a/app/views/admin/contest_page_made.html.erb b/app/views/admin/contest_page_made.html.erb index a25f149ed..77e0ce041 100644 --- a/app/views/admin/contest_page_made.html.erb +++ b/app/views/admin/contest_page_made.html.erb @@ -1,41 +1,41 @@ -+
- <%= link_to l(:label_project_first_page), {:action => 'first_page_made'}, class: "#{current_page?(first_page_made_path)? 'selected' : nil }" %>
+- <%= link_to l(:label_course_first_page), {:action => 'course_page_made'}, class: "#{current_page?(course_page_made_path)? 'selected' : nil }" %>
+- <%= link_to l(:label_contest_first_page), {:action => 'contest_page_made'}, class: "#{current_page?(contest_page_made_path)? 'selected' : nil }" %>
+- <%= link_to l(:label_web_footer_page), {:action => 'web_footer_made'}, class: "#{current_page?(web_footer_made_path)? 'selected' : nil }" %>
+<%=l(:label_first_page_made)%>
- -<%= form_tag(:controller => 'admin', :action => 'contest_page_made') do%> -- - <%= text_field_tag 'web_title', params[:wbe_title],:value => @first_page.web_title, :size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> -
- <%= render 'tab_partial' %> - -<%=l(:label_contest_first_page)%>
-- -
-- <%= render :partial=>"avatar/avatar_form",:style => "display:inline",:locals=> {source:@contest_page} %> --- - <%= text_field_tag 'image_width', params[:label_image_width],:value => @contest_page.image_width,:size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> -
-- - <%= text_field_tag 'image_height', params[:label_imgae_height], :value => @contest_page.image_height,:size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> -
-- - <%= text_field_tag 'contest_title', params[:label_site_title], :value => @contest_page.title,:size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> -
- -- - <%= text_area_tag 'contest_description',@contest_page.description,:rows => 8, :size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> -
- - <%= submit_tag l(:button_save), :class => "small", :name => nil %> -<% end %> -- - - +<%=l(:label_first_page_made)%>
+ +<%= form_tag(:controller => 'admin', :action => 'contest_page_made') do%> ++ + <%= text_field_tag 'web_title', params[:wbe_title],:value => @first_page.web_title, :size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> +
+ <%= render 'tab_partial' %> + +<%=l(:label_contest_first_page)%>
++ +
++ <%= render :partial=>"avatar/avatar_form",:style => "display:inline",:locals=> {source:@contest_page} %> +++ + <%= text_field_tag 'image_width', params[:label_image_width],:value => @contest_page.image_width,:size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> +
++ + <%= text_field_tag 'image_height', params[:label_imgae_height], :value => @contest_page.image_height,:size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> +
++ + <%= text_field_tag 'contest_title', params[:label_site_title], :value => @contest_page.title,:size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> +
+ ++ + <%= text_area_tag 'contest_description',@contest_page.description,:rows => 8, :size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> +
+ + <%= submit_tag l(:button_save), :class => "small", :name => nil %> +<% end %> ++ + +\ No newline at end of file diff --git a/app/views/admin/course_page_made.html.erb b/app/views/admin/course_page_made.html.erb index 8b91e2600..ce067eeb2 100644 --- a/app/views/admin/course_page_made.html.erb +++ b/app/views/admin/course_page_made.html.erb @@ -1,39 +1,39 @@ -<%=l(:label_first_page_made)%>
- -<%= form_tag(:controller => 'admin', :action => 'course_page_made') do %> -- - <%= text_field_tag 'web_title', params[:wbe_title],:value => @first_page.web_title, :size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> -
- <%= render 'tab_partial' %> -<%=l(:label_course_first_page)%>
-- -
-- <%= render :partial=>"avatar/avatar_form",:style => "display:inline",:locals=> {source:@course_page} %> --- - <%= text_field_tag 'image_width', params[:label_image_width],:value => @course_page.image_width,:size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> -
-- - <%= text_field_tag 'image_height', params[:label_imgae_height], :value => @course_page.image_height,:size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> -
-- - <%= text_field_tag 'course_title', params[:label_site_title], :value => @course_page.title,:size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> -
-- - <%= text_area_tag 'course_description',@course_page.description,:rows => 8, :size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> -
- - <%= submit_tag l(:button_save), :class => "small", :name => nil %> -<% end %> -- - - +<%=l(:label_first_page_made)%>
+ +<%= form_tag(:controller => 'admin', :action => 'course_page_made') do %> ++ + <%= text_field_tag 'web_title', params[:wbe_title],:value => @first_page.web_title, :size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> +
+ <%= render 'tab_partial' %> +<%=l(:label_course_first_page)%>
++ +
++ <%= render :partial=>"avatar/avatar_form",:style => "display:inline",:locals=> {source:@course_page} %> +++ + <%= text_field_tag 'image_width', params[:label_image_width],:value => @course_page.image_width,:size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> +
++ + <%= text_field_tag 'image_height', params[:label_imgae_height], :value => @course_page.image_height,:size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> +
++ + <%= text_field_tag 'course_title', params[:label_site_title], :value => @course_page.title,:size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> +
++ + <%= text_area_tag 'course_description',@course_page.description,:rows => 8, :size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> +
+ + <%= submit_tag l(:button_save), :class => "small", :name => nil %> +<% end %> ++ + +\ No newline at end of file diff --git a/app/views/admin/first_page_made.html.erb b/app/views/admin/first_page_made.html.erb index d8fbc0533..77bd41aa5 100644 --- a/app/views/admin/first_page_made.html.erb +++ b/app/views/admin/first_page_made.html.erb @@ -1,60 +1,60 @@ -<%=l(:label_first_page_made)%>
- -<%= form_tag(:controller => 'admin', :action => 'first_page_made') do %> -- - <%= text_field_tag 'web_title', params[:wbe_title],:value => @first_page.web_title, :size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> -
- <%= render 'tab_partial' %> -<%=l(:label_project_first_page)%>
-- -
-- <%= render :partial=>"avatar/avatar_form",:style => "display:inline",:locals=> {source:@first_page} %> --- - <%= text_field_tag 'image_width', params[:label_image_width],:value => @first_page.image_width,:size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> -
-- - <%= text_field_tag 'image_height', params[:label_imgae_height], :value => @first_page.image_height,:size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> -
-- - -
-- - -
-- - -
-- - - <%= text_area 'first_page', 'description', :value => @first_page.description,:cols => 80, :rows => 15, :class => 'wiki-edit' %> - <%= wikitoolbar_for 'first_page_description' %> -
- - - <%= submit_tag l(:button_save), :class => "small", :name => nil %> -<% end %> -- - - +<%=l(:label_first_page_made)%>
+ +<%= form_tag(:controller => 'admin', :action => 'first_page_made') do %> ++ + <%= text_field_tag 'web_title', params[:wbe_title],:value => @first_page.web_title, :size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> +
+ <%= render 'tab_partial' %> +<%=l(:label_project_first_page)%>
++ +
++ <%= render :partial=>"avatar/avatar_form",:style => "display:inline",:locals=> {source:@first_page} %> +++ + <%= text_field_tag 'image_width', params[:label_image_width],:value => @first_page.image_width,:size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> +
++ + <%= text_field_tag 'image_height', params[:label_imgae_height], :value => @first_page.image_height,:size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> +
++ + +
++ + +
++ + +
++ + + <%= text_area 'first_page', 'description', :value => @first_page.description,:cols => 80, :rows => 15, :class => 'wiki-edit' %> + <%= wikitoolbar_for 'first_page_description' %> +
+ + + <%= submit_tag l(:button_save), :class => "small", :name => nil %> +<% end %> ++ + +\ No newline at end of file diff --git a/app/views/admin/users.html.erb b/app/views/admin/users.html.erb index c70196a2f..7bbdf1c3e 100644 --- a/app/views/admin/users.html.erb +++ b/app/views/admin/users.html.erb @@ -1,69 +1,69 @@ -<% if User.current.admin? %> -- <%= link_to l(:label_user_new), new_user_path, :class => 'icon icon-add' %> -- -<%= l(:label_user_plural)%>
- - <%= form_tag(:controller => 'admin', :action => 'search') do %> - - <% end %> - - ---- -
-- <%= sort_header_tag('login', :caption => l(:field_login)) %> - <%= sort_header_tag('firstname', :caption => l(:field_firstname)) %> - <%= sort_header_tag('lastname', :caption => l(:field_lastname)) %> - <%= sort_header_tag('mail', :caption => l(:field_mail)) %> - - <%= sort_header_tag('admin', :caption => l(:field_admin), :default_order => 'desc') %> - <%= sort_header_tag('created_on', :caption => l(:field_created_on), :default_order => 'desc') %> - <%= sort_header_tag('last_login_on', :caption => l(:field_last_login_on), :default_order => 'desc') %> - - - - <% for user in @users -%> -- "> - - <% end -%> - - - - - - - - -<%= change_status_link(user) %> - <%= delete_link user_path(user, :back_url => admin_users_path(params)) unless User.current == user %> --- - <% html_title(l(:label_user_plural)) -%> -<%else %> - -<% end%> +<% if User.current.admin? %> +- <%= pagination_links_full @user_pages, @user_count %> -
-+ <%= link_to l(:label_user_new), new_user_path, :class => 'icon icon-add' %> ++ +<%= l(:label_user_plural)%>
+ + <%= form_tag(:controller => 'admin', :action => 'search') do %> + + <% end %> + + ++++ +
++ <%= sort_header_tag('login', :caption => l(:field_login)) %> + <%= sort_header_tag('firstname', :caption => l(:field_firstname)) %> + <%= sort_header_tag('lastname', :caption => l(:field_lastname)) %> + <%= sort_header_tag('mail', :caption => l(:field_mail)) %> + + <%= sort_header_tag('admin', :caption => l(:field_admin), :default_order => 'desc') %> + <%= sort_header_tag('created_on', :caption => l(:field_created_on), :default_order => 'desc') %> + <%= sort_header_tag('last_login_on', :caption => l(:field_last_login_on), :default_order => 'desc') %> + + + + <% for user in @users -%> ++ "> + + <% end -%> + + + + + + + + +<%= change_status_link(user) %> + <%= delete_link user_path(user, :back_url => admin_users_path(params)) unless User.current == user %> +++ + <% html_title(l(:label_user_plural)) -%> +<%else %> + +<% end%> diff --git a/app/views/admin/web_footer_made.html.erb b/app/views/admin/web_footer_made.html.erb index 65e77631c..90c9b5787 100644 --- a/app/views/admin/web_footer_made.html.erb +++ b/app/views/admin/web_footer_made.html.erb @@ -1,28 +1,28 @@ -+ <%= pagination_links_full @user_pages, @user_count %> +
+<%=l(:label_first_page_made)%>
- -<%= form_tag(:controller => 'admin', :action => 'web_footer_made') do%> -- - <%= text_field_tag 'web_title', params[:wbe_title],:value => @first_page.web_title, :size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> -
- <%= render 'tab_partial' %> -<%= link_to l(:label_cooperation_compnay), web_footer_companies_path %>-<%=l(:label_web_footer_page)%>
- -- - <%= text_field_tag 'organizer_name', params[:label_organizer_name], :value => @organizer.nil? ? "":@organizer.name,:size => 30,:style => "font-size:small;width:497px;margin-left:80px;" %> -
-- - - <%= text_area 'web_footer_oranizer', 'description', :value => @organizer.nil? ? "" : @organizer.description,:cols => 80, :rows => 15, :class => 'wiki-edit' %> - <%= wikitoolbar_for 'web_footer_oranizer_description' %> -
- <%= submit_tag l(:button_save), :class => "small", :name => nil %> -<% end %> -- - - +<%=l(:label_first_page_made)%>
+ +<%= form_tag(:controller => 'admin', :action => 'web_footer_made') do%> ++ + <%= text_field_tag 'web_title', params[:wbe_title],:value => @first_page.web_title, :size => 30,:style => "font-size:small;width:490px;margin-left:10px;" %> +
+ <%= render 'tab_partial' %> +<%= link_to l(:label_cooperation_compnay), web_footer_companies_path %>+<%=l(:label_web_footer_page)%>
+ ++ + <%= text_field_tag 'organizer_name', params[:label_organizer_name], :value => @organizer.nil? ? "":@organizer.name,:size => 30,:style => "font-size:small;width:497px;margin-left:80px;" %> +
++ + + <%= text_area 'web_footer_oranizer', 'description', :value => @organizer.nil? ? "" : @organizer.description,:cols => 80, :rows => 15, :class => 'wiki-edit' %> + <%= wikitoolbar_for 'web_footer_oranizer_description' %> +
+ <%= submit_tag l(:button_save), :class => "small", :name => nil %> +<% end %> ++ + +\ No newline at end of file diff --git a/app/views/attachments/_app_link.html.erb b/app/views/attachments/_app_link.html.erb index 263f51dc8..28a2d2c8b 100644 --- a/app/views/attachments/_app_link.html.erb +++ b/app/views/attachments/_app_link.html.erb @@ -1,17 +1,17 @@ - -<% for attachment in attachments %> - <% if attachments.count > 1 && attachment != attachments.first%> -
- <% end %> - <%= link_to_short_attachment attachment, :class => 'icon icon-attachment', :download => true -%> - <% if attachment.is_text? %> - <%= link_to image_tag('magnifier.png'), - :controller => 'attachments', :action => 'show', - :id => attachment, :filename => attachment.filename %> - <% end %> - - <%= h(truncate(" - #{attachment.description}", length: 20, omission: '...')) unless attachment.description.blank? %> - - (<%= number_to_human_size attachment.filesize %>) - - <% end -%> + +<% for attachment in attachments %> + <% if attachments.count > 1 && attachment != attachments.first%> +
+ <% end %> + <%= link_to_short_attachment attachment, :class => 'icon icon-attachment', :download => true -%> + <% if attachment.is_text? %> + <%= link_to image_tag('magnifier.png'), + :controller => 'attachments', :action => 'show', + :id => attachment, :filename => attachment.filename %> + <% end %> + + <%= h(truncate(" - #{attachment.description}", length: 20, omission: '...')) unless attachment.description.blank? %> + + (<%= number_to_human_size attachment.filesize %>) + + <% end -%> diff --git a/app/views/attachments/_form_course.html.erb b/app/views/attachments/_form_course.html.erb index 0446db37d..b2089d629 100644 --- a/app/views/attachments/_form_course.html.erb +++ b/app/views/attachments/_form_course.html.erb @@ -1,63 +1,63 @@ - -<% if defined?(container) && container && container.saved_attachments %> - <% if isReply %> - <% container.saved_attachments.each_with_index do |attachment, i| %> - - - - <% end %> - <% else %> - <% container.attachments.each_with_index do |attachment, i| %> - - <% end %> - <% end %> -<% end %> - - -<% content_for :header_tags do %> - <%= javascript_include_tag 'attachments' %> -<% end %> - - + +<% if defined?(container) && container && container.saved_attachments %> + <% if isReply %> + <% container.saved_attachments.each_with_index do |attachment, i| %> + + + + <% end %> + <% else %> + <% container.attachments.each_with_index do |attachment, i| %> + + <% end %> + <% end %> +<% end %> + + +<% content_for :header_tags do %> + <%= javascript_include_tag 'attachments' %> +<% end %> + + diff --git a/app/views/attachments/_links.html.erb b/app/views/attachments/_links.html.erb index f6b7ee7dd..30e60190d 100644 --- a/app/views/attachments/_links.html.erb +++ b/app/views/attachments/_links.html.erb @@ -1,53 +1,53 @@ - + diff --git a/app/views/bids/_form.html.erb b/app/views/bids/_form.html.erb index 98277d315..86bac9731 100644 --- a/app/views/bids/_form.html.erb +++ b/app/views/bids/_form.html.erb @@ -1,35 +1,35 @@ - -<% else %> - -<%= error_messages_for 'bid' %> - -<%= l(:label_bids_form_new_description) %>
-<%= f.text_field :name, :required => true, :size => 60, :style => "width:490px;", :maxlength => Bid::NAME_LENGTH_LIMIT, :placeholder => "#{l(:label_requirement_name)}" %>
- -<%= f.text_area :description, :rows => 8, :class => 'wiki-edit', :style => "font-size:small;width:490px;margin-left:10px;", :maxlength => Bid::DESCRIPTION_LENGTH_LIMIT, :placeholder => "#{l(:label_requirement_description)}" %>
-<%= f.text_field :budget, :required => true, :size => 60, :style => "width:350px;", :placeholder => l(:label_bids_new_money) %> - - - -
-<%= f.text_field :deadline, :required => true, :size => 60, :style => "width:150px;", :placeholder => "#{l(:label_deadline)}", :readonly => true %><%= calendar_for('bid_deadline')%> -
- + +<% else %> + +<%= error_messages_for 'bid' %> + +<%= l(:label_bids_form_new_description) %>
+<%= f.text_field :name, :required => true, :size => 60, :style => "width:490px;", :maxlength => Bid::NAME_LENGTH_LIMIT, :placeholder => "#{l(:label_requirement_name)}" %>
+ +<%= f.text_area :description, :rows => 8, :class => 'wiki-edit', :style => "font-size:small;width:490px;margin-left:10px;", :maxlength => Bid::DESCRIPTION_LENGTH_LIMIT, :placeholder => "#{l(:label_requirement_description)}" %>
+<%= f.text_field :budget, :required => true, :size => 60, :style => "width:350px;", :placeholder => l(:label_bids_new_money) %> + + + +
+<%= f.text_field :deadline, :required => true, :size => 60, :style => "width:150px;", :placeholder => "#{l(:label_deadline)}", :readonly => true %><%= calendar_for('bid_deadline')%> +
+ diff --git a/app/views/bids/_form_contest.html.erb b/app/views/bids/_form_contest.html.erb index e2dba9271..ccd16f15e 100644 --- a/app/views/bids/_form_contest.html.erb +++ b/app/views/bids/_form_contest.html.erb @@ -1,36 +1,36 @@ - - -<%= error_messages_for 'bid' %> - -<%= l(:label_bids_form_contest_new_description) %>
-<%= f.text_field :name, :required => true, :size => 60, :style => "width:490px;", :maxlength => Bid::NAME_LENGTH_LIMIT, :placeholder => "#{l(:label_contest_name)}" %>
- -<%= f.text_area :description, :rows => 8, :class => 'wiki-edit', :style => "font-size:small;width:490px;margin-left:10px;", :maxlength => Bid::DESCRIPTION_LENGTH_LIMIT, :placeholder => "#{l(:label_contest_description)}" %>
- -<%= f.text_field :password, :size => 60, :style => "width:488px;margin-left: 10px;" %>
- -- <%= f.text_field :budget, :required => true, :size => 60, :style => "width:350px;", :placeholder => l(:label_bids_reward_what) %> - - -
- -<%= f.text_field :deadline, :required => true, :size => 60, :style => "width:150px;", :readonly => true, :placeholder => "#{l(:label_deadline)}" %><%= calendar_for('bid_deadline')%>
+ + +<%= error_messages_for 'bid' %> + +<%= l(:label_bids_form_contest_new_description) %>
+<%= f.text_field :name, :required => true, :size => 60, :style => "width:490px;", :maxlength => Bid::NAME_LENGTH_LIMIT, :placeholder => "#{l(:label_contest_name)}" %>
+ +<%= f.text_area :description, :rows => 8, :class => 'wiki-edit', :style => "font-size:small;width:490px;margin-left:10px;", :maxlength => Bid::DESCRIPTION_LENGTH_LIMIT, :placeholder => "#{l(:label_contest_description)}" %>
+ +<%= f.text_field :password, :size => 60, :style => "width:488px;margin-left: 10px;" %>
+ ++ <%= f.text_field :budget, :required => true, :size => 60, :style => "width:350px;", :placeholder => l(:label_bids_reward_what) %> + + +
+ +<%= f.text_field :deadline, :required => true, :size => 60, :style => "width:150px;", :readonly => true, :placeholder => "#{l(:label_deadline)}" %><%= calendar_for('bid_deadline')%>
diff --git a/app/views/bids/_history.html.erb b/app/views/bids/_history.html.erb index b67421823..784fb7ff8 100644 --- a/app/views/bids/_history.html.erb +++ b/app/views/bids/_history.html.erb @@ -1,66 +1,66 @@ -<% reply_allow = JournalsForMessage.create_by_user? User.current %> -<% tip1 = (@bid.reward_type == 3) ? l(:label_student_response) : l(:label_user_response) %> -<%=tip1%>
- -- <%= render :partial => 'new', :locals => {:bid => @bid, :sta => @state} %> --<% label = '' - case @bid.reward_type - when 1 - label = l(:label_respond_requirement) - when 2 - label = l(:label_contest_requirement) - when 3 - label = l(:label_question_requirement) - else - end -%> - - -<% if journals.size >0 %> - -<% end %> +<% reply_allow = JournalsForMessage.create_by_user? User.current %> +<% tip1 = (@bid.reward_type == 3) ? l(:label_student_response) : l(:label_user_response) %> +<%=tip1%>
+ ++ <%= render :partial => 'new', :locals => {:bid => @bid, :sta => @state} %> ++<% label = '' + case @bid.reward_type + when 1 + label = l(:label_respond_requirement) + when 2 + label = l(:label_contest_requirement) + when 3 + label = l(:label_question_requirement) + else + end +%> + + +<% if journals.size >0 %> + +<% end %> diff --git a/app/views/bids/_homework_form.html.erb b/app/views/bids/_homework_form.html.erb index 29033ec59..3a9158349 100644 --- a/app/views/bids/_homework_form.html.erb +++ b/app/views/bids/_homework_form.html.erb @@ -1,56 +1,56 @@ - - - - -<%= error_messages_for 'bid' %> -- <%= f.text_field :name, :required => true, :size => 60, :style => "width:490px;", :maxlength => Bid::NAME_LENGTH_LIMIT, :onblur => "regexName();" %> -
-- -
- -- <%= f.text_area :description, :rows => 8, :class => 'wiki-edit', :style => "font-size:small;width:490px;", :maxlength => Bid::DESCRIPTION_LENGTH_LIMIT %> -
-- <%= f.text_field(:deadline, :required => true, :size => 60, :style => "width:150px;", :readonly => true, :onchange => "regexDeadLine();") %> - <%= calendar_for('bid_deadline')%> - - -
-- <%= f.select :is_evaluation, is_evaluation_option %> -
-- <%= f.select :proportion, proportion_option %> -
-- <%= hidden_field_tag 'course_id', @course.id %> -
-