diff --git a/Gemfile b/Gemfile index 3027c16cd..0125e9d60 100644 --- a/Gemfile +++ b/Gemfile @@ -30,11 +30,21 @@ gem 'rails_kindeditor',path:'lib/rails_kindeditor' #gem "rmagick", ">= 2.0.0" gem 'binding_of_caller' gem 'chinese_pinyin' +# gem 'sunspot_rails', '~> 1.3.3' +# gem 'sunspot_solr' +# gem 'sunspot' +# gem 'progress_bar' +gem 'ansi' + +gem 'kaminari' +gem 'elasticsearch-model' +gem 'elasticsearch-rails' group :development do gem 'grape-swagger' gem 'better_errors', '~> 1.1.0' gem 'rack-mini-profiler', '~> 0.9.3' + gem 'win32console' end group :development, :test do diff --git a/app/assets/javascripts/org_subfields.js.coffee b/app/assets/javascripts/org_subfields.js.coffee new file mode 100644 index 000000000..761567942 --- /dev/null +++ b/app/assets/javascripts/org_subfields.js.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/app/assets/stylesheets/org_subfields.css.scss b/app/assets/stylesheets/org_subfields.css.scss new file mode 100644 index 000000000..19263385e --- /dev/null +++ b/app/assets/stylesheets/org_subfields.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the org_subfields controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/courses_controller.rb b/app/controllers/courses_controller.rb index cd1de16fc..0c61c449e 100644 --- a/app/controllers/courses_controller.rb +++ b/app/controllers/courses_controller.rb @@ -374,6 +374,7 @@ class CoursesController < ApplicationController def settings if User.current.allowed_to?(:as_teacher,@course) + @select_tab = params[:tab] @issue_custom_fields = IssueCustomField.sorted.all @issue_category ||= IssueCategory.new @member ||= @course.members.new diff --git a/app/controllers/exercise_controller.rb b/app/controllers/exercise_controller.rb index d53dc067c..a99ab32ec 100644 --- a/app/controllers/exercise_controller.rb +++ b/app/controllers/exercise_controller.rb @@ -1,18 +1,33 @@ class ExerciseController < ApplicationController layout "base_courses" - before_filter :find_exercise_and_course, :only => [:create_exercise_question, :edit, :update, :show, :destroy, :commit_exercise, :commit_answer,:publish_exercise,:republish_exercise] + before_filter :find_exercise_and_course, :only => [:create_exercise_question, :edit, :update, :show, :destroy, :commit_exercise, :commit_answer,:publish_exercise,:republish_exercise,:show_student_result] before_filter :find_course, :only => [:index,:new,:create,:student_exercise_list] include ExerciseHelper - include ExerciseHelper def index + publish_exercises = Exercise.where("publish_time is not null and exercise_status = 1 and publish_time <=?",Time.now) + publish_exercises.each do |exercise| + exercise.update_column('exercise_status', 2) + course = exercise.course + course.members.each do |m| + exercise.course_messages << CourseMessage.new(:user_id => m.user_id, :course_id => course.id, :viewed => false, :status => 2) + end + end + end_exercises = Exercise.where("end_time <=? and exercise_status = 2",Time.now) + end_exercises.each do |exercise| + exercise.update_column('exercise_status', 3) + end + if @course.is_public == 0 && !User.current.member_of_course?(@course) + render_403 + return + end remove_invalid_exercise(@course) @is_teacher = User.current.allowed_to?(:as_teacher,@course) if @is_teacher - exercises = @course.exercises + exercises = @course.exercises.order("created_at asc") else - exercises = @course.exercises.where(:exercise_status => 2) + exercises = @course.exercises.where(:exercise_status => 2).order("created_at asc") end @exercises = paginateHelper exercises,20 #分页 respond_to do |format| @@ -21,6 +36,18 @@ class ExerciseController < ApplicationController end def show + publish_exercises = Exercise.where("publish_time is not null and exercise_status = 1 and publish_time <=?",Time.now) + publish_exercises.each do |exercise| + exercise.update_column('exercise_status', 2) + course = exercise.course + course.members.each do |m| + exercise.course_messages << CourseMessage.new(:user_id => m.user_id, :course_id => course.id, :viewed => false, :status => 2) + end + end + end_exercises = Exercise.where("end_time <=? and exercise_status = 2",Time.now) + end_exercises.each do |exercise| + exercise.update_column('exercise_status', 3) + end unless User.current.member_of_course?(@course) render_403 return @@ -31,17 +58,24 @@ class ExerciseController < ApplicationController render_403 return end - @can_edit_excercise = (!has_commit_exercise?(@exercise.id,User.current.id)) || User.current.admin? + exercise_end = @exercise.end_time > Time.now + if @exercise.time == -1 + @can_edit_excercise = exercise_end + else + @can_edit_excercise = (!has_commit_exercise?(@exercise.id,User.current.id)&& exercise_end) || User.current.admin? + end @exercise_user = ExerciseUser.where("user_id=? and exercise_id=?", User.current.id, @exercise.id).first # 学生点击的时候即创建关联,自动保存 #eu = ExerciseUser.create(:user_id => User.current, :exercise_id => @exercise.id, :start_at => Time.now, :status => false) # 已提交问卷的用户不能再访问该界面 +=begin if has_commit_exercise?(@exercise.id, User.current.id) && (!User.current.admin?) respond_to do |format| format.html {render :layout => 'base_courses'} end else +=end if !@is_teacher && !has_click_exercise?(@exercise.id, User.current.id) eu = ExerciseUser.create(:user_id => User.current.id, :exercise_id => @exercise.id, :start_at => Time.now, :status => false) @exercise_user = ExerciseUser.where("user_id=? and exercise_id=?", User.current.id, @exercise.id).first @@ -49,10 +83,13 @@ class ExerciseController < ApplicationController # @percent = get_percent(@exercise,User.current) exercise_questions = @exercise.exercise_questions @exercise_questions = paginateHelper exercise_questions,5 #分页 + score = calculate_student_score(@exercise, User.current) + eu = get_exercise_user(@exercise.id, User.current.id) + eu.update_attributes(:score => score) respond_to do |format| format.html {render :layout => 'base_courses'} end - end + #end end def new @@ -65,7 +102,6 @@ class ExerciseController < ApplicationController :end_time => "", :publish_time => "", :exercise_description => "", - :show_result => "", :show_result => 1 } @exercise = Exercise.create option @@ -80,7 +116,7 @@ class ExerciseController < ApplicationController exercise ||= Exercise.new exercise.exercise_name = params[:exercise][:exercise_name] exercise.exercise_description = params[:exercise][:exercise_description] - exercise.end_time = params[:exercise][:end_time] + exercise.end_time = Time.at(params[:exercise][:end_time].to_time.to_i + 16*60*60 -1) exercise.publish_time = params[:exercise][:publish_time] exercise.user_id = User.current.id exercise.time = params[:exercise][:time] @@ -104,10 +140,10 @@ class ExerciseController < ApplicationController def update @exercise.exercise_name = params[:exercise][:exercise_name] @exercise.exercise_description = params[:exercise][:exercise_description] - @exercise.time = params[:exercise][:time] - @exercise.end_time = params[:exercise][:end_time] + @exercise.time = params[:exercise][:time].blank? ? -1 : params[:exercise][:time] + @exercise.end_time = Time.at(params[:exercise][:end_time].to_time.to_i + 16*60*60 -1) @exercise.publish_time = params[:exercise][:publish_time] - @exercise.show_result = params[:exercise][:show_result] + @exercise.show_result = params[:exercise][:show_result].blank? ? 1 : params[:exercise][:show_result] if @exercise.save respond_to do |format| format.js @@ -300,9 +336,13 @@ class ExerciseController < ApplicationController # 发布试卷 def publish_exercise @is_teacher = User.current.allowed_to?(:as_teacher,@course) + @index = params[:index] @exercise.exercise_status = 2 @exercise.publish_time = Time.now if @exercise.save + @exercise.course.members.each do |m| + @exercise.course_messages << CourseMessage.create(:user_id =>m.user_id, :course_id => @exercise.course.id, :viewed => false,:status=>2) + end #redirect_to exercise_index_url(:course_id=> @course.id) respond_to do |format| format.js @@ -314,11 +354,14 @@ class ExerciseController < ApplicationController # 重新发布的时候会删除所有的答题 def republish_exercise @is_teacher = User.current.allowed_to?(:as_teacher,@course) + @index = params[:index] @exercise.exercise_questions.each do |exercise_question| exercise_question.exercise_answers.destroy_all end + @exercise.course_messages.destroy_all @exercise.exercise_users.destroy_all @exercise.exercise_status = 1 + @exercise.publish_time = nil @exercise.save respond_to do |format| format.js @@ -328,12 +371,12 @@ class ExerciseController < ApplicationController def student_exercise_list @is_teacher = User.current.allowed_to?(:as_teacher,@course) || User.current.admin? @exercise = Exercise.find params[:id] - @all_exercises = @course.exercises.order("created_at desc") + @all_exercises = @course.exercises.where("exercise_status > 1").order("created_at desc") @exercise_count = @exercise.exercise_users.where('score is not NULL').count - if @is_teacher || (!@exercise.exercise_users.where(:user_id => User.current.id).empty? && Time.parse(@exercise.end_time.to_s).strftime("%Y-%m-%d-%H-%M-%S") <= Time.now.strftime("%Y-%m-%d-%H-%M-%S")) + if @is_teacher || (!@exercise.exercise_users.where(:user_id => User.current.id).empty? && @exercise.end_time <= Time.now) @exercise_users_list = @exercise.exercise_users.where('score is not NULL') @show_all = true; - elsif !@exercise.exercise_users.where(:user_id => User.current.id).empty? && Time.parse(@exercise.end_time.to_s).strftime("%Y-%m-%d-%H-%M-%S") > Time.now.strftime("%Y-%m-%d-%H-%M-%S") + elsif !@exercise.exercise_users.where(:user_id => User.current.id).empty? && @exercise.end_time > Time.now @exercise_users_list = @exercise.exercise_users.where("user_id = ? and score is not NULL",User.current.id) else @exercise_users_list = [] @@ -346,8 +389,8 @@ class ExerciseController < ApplicationController # 学生提交答卷,选中答案的过程中提交 def commit_answer eq = ExerciseQuestion.find(params[:exercise_question_id]) - # 已提交过的则不允许答题 - if has_commit_exercise?(@exercise.id,User.current.id) && (!User.current.admin?) + # 已提交过的且是限时的则不允许答题 + if (has_commit_exercise?(@exercise.id,User.current.id) && (!User.current.admin?) && @exercise.time != -1) || @exercise.end_time < Time.now render :json => {:text => "failure"} return end @@ -364,8 +407,14 @@ class ExerciseController < ApplicationController ea.exercise_choice_id = params[:exercise_choice_id] if ea.save # 保存成功返回成功信息及当前以答题百分比 + uncomplete_question = get_uncomplete_question(@exercise, User.current) + if uncomplete_question.count < 1 + complete = 1; + else + complete = 0; + end @percent = get_percent(@exercise,User.current) - render :json => {:text => "ok" ,:percent => format("%.2f" ,@percent)} + render :json => {:text => "ok" ,:complete => complete,:percent => format("%.2f" ,@percent)} else #返回失败信息 render :json => {:text => "failure"} @@ -380,8 +429,14 @@ class ExerciseController < ApplicationController ea.exercise_question_id = params[:exercise_question_id] ea.exercise_choice_id = params[:exercise_choice_id] if ea.save + uncomplete_question = get_uncomplete_question(@exercise, User.current) + if uncomplete_question.count < 1 + complete = 1; + else + complete = 0; + end @percent = get_percent(@exercise,User.current) - render :json => {:text => "ok",:percent => format("%.2f" ,@percent)} + render :json => {:text => "ok",:complete => complete,:percent => format("%.2f" ,@percent)} else render :json => {:text => "failure"} end @@ -410,8 +465,14 @@ class ExerciseController < ApplicationController ea.exercise_question_id = params[:exercise_question_id] ea.answer_text = params[:answer_text] if ea.save + uncomplete_question = get_uncomplete_question(@exercise, User.current) + if uncomplete_question.count < 1 + complete = 1; + else + complete = 0; + end @percent = get_percent(@exercise,User.current) - render :json => {:text => ea.answer_text,:percent => format("%.2f",@percent)} + render :json => {:text => ea.answer_text,:complete => complete,:percent => format("%.2f",@percent)} else render :json => {:text => "failure"} end @@ -447,6 +508,21 @@ class ExerciseController < ApplicationController def commit_exercise # 老师不需要提交 if User.current.allowed_to?(:as_teacher,@course) + if @exercise.publish_time.nil? + @exercise.update_attributes(:show_result => params[:show_result]) + @exercise.update_attributes(:exercise_status => 2) + @exercise.update_attributes(:publish_time => Time.now) + course = @exercise.course + course.members.each do |m| + @exercise.course_messages << CourseMessage.new(:user_id => m.user_id, :course_id => course.id, :viewed => false, :status => 2) + end + redirect_to exercise_url(@exercise) + return + elsif @exercise.publish_time > Time.now + @exercise.update_attributes(:show_result => params[:show_result]) + redirect_to exercise_url(@exercise) + return + end @exercise.update_attributes(:show_result => params[:show_result]) redirect_to exercise_url(@exercise) # REDO: 提示提交成功 @@ -480,6 +556,20 @@ class ExerciseController < ApplicationController end end + #查看学生的答卷情况 + def show_student_result + @user = User.find params[:user_id] + @can_edit_excercise = false + @exercise_user = ExerciseUser.where("user_id =? and exercise_id=?", @user.id, @exercise.id).first + @exercise_questions = @exercise.exercise_questions + score = calculate_student_score(@exercise, @user) + eu = get_exercise_user(@exercise.id, @user.id) + eu.update_attributes(:score => score) + respond_to do |format| + format.html {render :layout => 'base_courses'} + end + end + # 计算学生得分 def calculate_student_score(exercise, user) score = 0 @@ -490,7 +580,7 @@ class ExerciseController < ApplicationController exercise_qustions.each do |question| answer = get_user_answer(question, user) standard_answer = get_user_standard_answer(question, user) - unless answer.nil? + unless answer.empty? # 问答题有多个答案 if question.question_type == 3 if standard_answer.include?(answer.first.answer_text) @@ -532,19 +622,6 @@ class ExerciseController < ApplicationController eu end - #获取未完成的题目 - def get_uncomplete_question exercise,user - all_questions = exercise.exercise_questions - uncomplete_question = [] - all_questions.each do |question| - answers = get_user_answer(question, user) - if answers.nil? - uncomplete_question << question - end - end - uncomplete_question - end - # 获取当前学生回答问题的答案 def get_user_answer(question,user) # user_answer = ExerciseAnswer.where("user_id=? and exercise_question_id=?", user.id, question.id).first @@ -563,7 +640,8 @@ class ExerciseController < ApplicationController standard_answer = question.exercise_standard_answers.first end standard_answer - end # 是否完成了答题 + end + # 是否完成了答题 def get_complete_question(exercise,user) questions = exercise.exercise_questions complete_question = [] diff --git a/app/controllers/files_controller.rb b/app/controllers/files_controller.rb index a2902e3fc..b15be4896 100644 --- a/app/controllers/files_controller.rb +++ b/app/controllers/files_controller.rb @@ -374,6 +374,9 @@ class FilesController < ApplicationController if !attachments.empty? && !attachments[:files].blank? && Setting.notified_events.include?('file_added') Mailer.run.attachments_added(attachments[:files]) end + # 更新课程英雄榜得分 + update_contributor_score(@course, attachments[:files].first) + # end if params[:course_attachment_type] && params[:course_attachment_type].is_a?(Array) params[:course_attachment_type].each do |type| tag_name = get_tag_name_by_type_number type @@ -423,6 +426,20 @@ class FilesController < ApplicationController end end + def update_contributor_score(course, file ) + unless file.author.allowed_to?(:as_teacher, course) + course_contributor_score = CourseContributorScore.where("course_id =? and user_id =?", course.id, file.author.id).first + if course_contributor_score.nil? + CourseContributorScore.create(:course_id => course.id, :user_id => file.author.id, :message_num => 0, :message_reply_num => 0, + :news_reply_num => 0, :resource_num => 5, :journal_num => 0, :journal_reply_num => 0, :total_score => 5) + else + score = course_contributor_score.resource_num + 5 + total_score = course_contributor_score.total_score + 5 + course_contributor_score.update_attributes(:resource_num => score, :total_score => total_score) + end + end + end + def get_tag_name_by_type_number type case type when "1" diff --git a/app/controllers/homework_common_controller.rb b/app/controllers/homework_common_controller.rb index 687ef9503..67499655f 100644 --- a/app/controllers/homework_common_controller.rb +++ b/app/controllers/homework_common_controller.rb @@ -262,6 +262,7 @@ class HomeworkCommonController < ApplicationController @user_activity_id = -1 end @is_in_course = params[:is_in_course] + @course_activity = params[:course_activity].to_i end private diff --git a/app/controllers/memos_controller.rb b/app/controllers/memos_controller.rb index 4181090a5..2d2c058d4 100644 --- a/app/controllers/memos_controller.rb +++ b/app/controllers/memos_controller.rb @@ -73,6 +73,7 @@ class MemosController < ApplicationController end end #end + format.js format.html { redirect_to back_memo_url, notice: "#{l :label_memo_create_succ}" } format.json { render json: @memo, status: :created, location: @memo } else @@ -152,6 +153,7 @@ class MemosController < ApplicationController end def update + @flag = false respond_to do |format| if( #@memo.update_column(:subject, params[:memo][:subject]) && @memo.update_column(:content, params[:memo][:content]) && @@ -159,10 +161,12 @@ class MemosController < ApplicationController @memo.update_column(:lock, params[:memo][:lock]) && @memo.update_column(:subject,params[:memo][:subject])) @memo.save_attachments(params[:attachments] || (params[:memo] && params[:memo][:uploads])) - @memo.save + @flag = @memo.save # @memo.root.update_attribute(:updated_at, @memo.updated_at) + format.js format.html {redirect_to back_memo_url, notice: "#{l :label_memo_create_succ}"} else + format.js format.html { render action: "edit" } format.json { render json: @person.errors, status: :unprocessable_entity } end diff --git a/app/controllers/messages_controller.rb b/app/controllers/messages_controller.rb index 9b090de9a..6f173b7c2 100644 --- a/app/controllers/messages_controller.rb +++ b/app/controllers/messages_controller.rb @@ -169,6 +169,11 @@ class MessagesController < ApplicationController course_activity.updated_at = Time.now course_activity.save end + forge_activity = ForgeActivity.where("forge_act_type='Message' and forge_act_id=#{@topic.id}").first + if forge_activity + forge_activity.updated_at = Time.now + forge_activity.save + end user_activity = UserActivity.where("act_type='Message' and act_id =#{@topic.id}").first if user_activity user_activity.updated_at = Time.now diff --git a/app/controllers/org_courses_controller.rb b/app/controllers/org_courses_controller.rb index 3d1d313c5..d054e41de 100644 --- a/app/controllers/org_courses_controller.rb +++ b/app/controllers/org_courses_controller.rb @@ -3,7 +3,9 @@ class OrgCoursesController < ApplicationController org_ids = params[:orgNames] @course = Course.find(params[:course_id]) org_ids.each do |org_id| - OrgCourse.create(:organization_id => org_id.to_i, :course_id => params[:course_id].to_i, :created_at => Time.now) + if OrgCourse.where("organization_id =? and course_id =?", org_id.to_i, params[:course_id].to_i).count == 0 + OrgCourse.create(:organization_id => org_id.to_i, :course_id => params[:course_id].to_i, :created_at => Time.now) + end end respond_to do |format| format.js diff --git a/app/controllers/org_document_comments_controller.rb b/app/controllers/org_document_comments_controller.rb index 61a27c433..29b728268 100644 --- a/app/controllers/org_document_comments_controller.rb +++ b/app/controllers/org_document_comments_controller.rb @@ -13,7 +13,7 @@ class OrgDocumentCommentsController < ApplicationController @org_document_comment.content = params[:org_document_comment][:content] if @org_document_comment.save flash.keep[:notice] = l(:notice_successful_create) - OrgActivity + EditorOfDocument.create(:editor_id => User.current.id, :org_document_comment_id => @org_document_comment.id, :created_at => @org_document_comment.updated_at) redirect_to organization_org_document_comments_path(@organization) else redirect_to new_org_document_comment_path(:organization_id => @organization.id) @@ -36,14 +36,26 @@ class OrgDocumentCommentsController < ApplicationController if @org_document.parent.nil? act = OrgActivity.where("org_act_type='OrgDocumentComment' and org_act_id =?", @org_document.id).first act.update_attributes(:updated_at => @org_document.updated_at) + EditorOfDocument.create(:editor_id => User.current.id, :org_document_comment_id => @org_document.id, :created_at => Time.now) end respond_to do |format| - format.html {redirect_to organization_org_document_comments_path(:organization_id => @org_document.organization.id)} + format.html { + if params[:flag].to_i == 0 + redirect_to organization_org_document_comments_path(:organization_id => @org_document.organization.id) + else + if params[:flag].to_i == 1 + redirect_to org_document_comment_path(@org_document.root.id, :organization_id => @org_document.organization.id) + else + redirect_to organization_path(@org_document.organization.id) + end + end + } end end def edit @org_document = OrgDocumentComment.find(params[:id]) + @flag = params[:flag] @organization = Organization.find(params[:organization_id]) end @@ -74,10 +86,10 @@ class OrgDocumentCommentsController < ApplicationController def destroy @org_document_comment = OrgDocumentComment.find(params[:id]) org = @org_document_comment.organization + if @org_document_comment.id == org.home_id + org.update_attributes(:home_id => nil) + end if @org_document_comment.destroy - if @org_document_comment.id == org.id - org.home_id == nil - end end respond_to do |format| format.js diff --git a/app/controllers/org_projects_controller.rb b/app/controllers/org_projects_controller.rb index 29e60a62a..a455ce408 100644 --- a/app/controllers/org_projects_controller.rb +++ b/app/controllers/org_projects_controller.rb @@ -3,7 +3,9 @@ class OrgProjectsController < ApplicationController org_ids = params[:orgNames] @project = Project.find(params[:project_id]) org_ids.each do |org_id| - OrgProject.create(:organization_id => org_id.to_i, :project_id => params[:project_id].to_i, :created_at => Time.now) + if OrgProject.where("organization_id =? and project_id =?", org_id.to_i, @project.id).count == 0 + OrgProject.create(:organization_id => org_id.to_i, :project_id => params[:project_id].to_i, :created_at => Time.now) + end end respond_to do |format| format.js diff --git a/app/controllers/org_subfields_controller.rb b/app/controllers/org_subfields_controller.rb new file mode 100644 index 000000000..6fdf0ae40 --- /dev/null +++ b/app/controllers/org_subfields_controller.rb @@ -0,0 +1,20 @@ +class OrgSubfieldsController < ApplicationController + def create + @subfield = OrgSubfield.create(:name => params[:name]) + @organization = Organization.find(params[:organization_id]) + @organization.org_subfields << @subfield + @subfield.update_attributes(:priority => @subfield.id) + end + + def destroy + @subfield = OrgSubfield.find(params[:id]) + @organization = Organization.find(@subfield.organization_id) + @subfield.destroy + end + + def update + @subfield = OrgSubfield.find(params[:id]) + @organization = Organization.find(@subfield.organization_id) + @subfield.update_attributes(:name => params[:name]) + end +end diff --git a/app/controllers/organizations_controller.rb b/app/controllers/organizations_controller.rb index 0d22ab461..d182640ed 100644 --- a/app/controllers/organizations_controller.rb +++ b/app/controllers/organizations_controller.rb @@ -37,6 +37,19 @@ class OrganizationsController < ApplicationController @organization = Organization.new render :layout => 'new_base' end + + def edit + @organization = Organization.find(params[:id]) + end + + def destroy + @organization = Organization.find(params[:id]) + @organization.destroy + respond_to do |format| + format.html{ redirect_to admin_organization_path } + end + end + def create @organization = Organization.new @organization.name = params[:organization][:name] @@ -142,6 +155,12 @@ class OrganizationsController < ApplicationController # end end + def cancel_homepage + @org = Organization.find(params[:id]) + @org.home_id = nil + @org.save + end + def autocomplete_search @project = Project.find(params[:project_id]) #@flag = params[:flag] || false @@ -161,7 +180,7 @@ class OrganizationsController < ApplicationController def more_org_projects @organization = Organization.find params[:id] @page = params[:page] - @org_projects = @organization.projects.reorder('created_at').page((params[:page].to_i || 1) +1).per(5) + @org_projects = @organization.projects.reorder('created_at').uniq.page((params[:page].to_i || 1) +1).per(5) respond_to do |format| format.js end @@ -170,7 +189,88 @@ class OrganizationsController < ApplicationController def more_org_courses @organization = Organization.find(params[:id]) @page = params[:page] - @org_courses = @organization.courses.reorder('created_at').page((params[:page].to_i || 1) + 1 ).per(5) + @org_courses = @organization.courses.reorder('created_at').uniq.page((params[:page].to_i || 1) + 1 ).per(5) + respond_to do |format| + format.js + end + end + + def join_course_menu + @organization = Organization.find(params[:id]) + respond_to do |format| + format.js + end + end + + def search_courses + @organization = Organization.find(params[:id]) + condition = '%%' + if !params[:name].nil? + condition = "%#{params[:name].strip}%".gsub(" ","") + end + sql = "select courses.* from courses inner join members on courses.id = members.course_id where members.user_id = #{User.current.id} and courses.name like '#{condition}'"+ + "and courses.id not in (select distinct org_courses.course_id from org_courses where org_courses.organization_id = #{@organization.id})" + #user_courses = Course.find_by_sql(sql) + @courses = Course.find_by_sql(sql) + # @added_course_ids = @organization.courses.map(&:id) + # @courses = [] + # user_courses.each do |course| + # if !@added_course_ids.include?(course.id) + # @courses << course + # end + # end + end + + def join_courses + @organization = Organization.find(params[:id]) + course_ids = params[:courseNames] + course_ids.each do |id| + OrgCourse.create(:organization_id => @organization.id, :course_id => id.to_i, :created_at => Time.now) + end + respond_to do |format| + format.js + end + end + + def join_project_menu + @organization = Organization.find(params[:id]) + respond_to do |format| + format.js + end + end + + def logout + logout_user + respond_to do |format| + format.html {redirect_to organization_path(params[:id])} + end + end + + def search_projects + @organization = Organization.find(params[:id]) + condition = '%%' + if !params[:name].nil? + condition = "%#{params[:name].strip}%".gsub(" ","") + end + sql = "select projects.* from projects inner join members on projects.id = members.project_id where members.user_id = #{User.current.id} and projects.status != 9 and projects.name like '#{condition}'" + + " and projects.id not in (select org_projects.project_id from org_projects where organization_id = #{@organization.id})" + #user_projects = Course.find_by_sql(sql) + @projects = Course.find_by_sql(sql) + # @added_course_ids = @organization.projects.map(&:id) + # @projects = [] + # user_projects.each do |project| + # if !@added_course_ids.include?(project.id) + # @projects << project + # end + # end + end + + def join_projects + @organization = Organization.find(params[:id]) + project_ids = params[:projectNames] + project_ids.each do |id| + OrgProject.create(:organization_id => @organization.id, :project_id => id.to_i, :created_at => Time.now) + end respond_to do |format| format.js end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 715f56d3d..200bd4d69 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -320,9 +320,20 @@ class ProjectsController < ApplicationController @activity.scope_select {|t| !has["show_#{t}"].nil?} =end + @page = params[:page] ? params[:page].to_i + 1 : 0 # 根据私密性,取出符合条件的所有数据 if User.current.member_of?(@project) || User.current.admin? - @events_pages = ForgeActivity.where("project_id = ? and forge_act_type != ?",@project, "Document" ).order("created_at desc").page(params['page'|| 1]).per(20); + case params[:type] + when nil + @events_pages = ForgeActivity.where("project_id = ? and forge_act_type in ('Issue', 'Message','News', 'ProjectCreateInfo')",@project).order("updated_at desc").limit(10).offset(@page * 10) + when 'issue' + @events_pages = ForgeActivity.where("project_id = ? and forge_act_type = 'Issue'",@project).order("updated_at desc").limit(10).offset(@page * 10) + when 'news' + @events_pages = ForgeActivity.where("project_id = ? and forge_act_type = 'News'",@project).order("updated_at desc").limit(10).offset(@page * 10) + when 'message' + @events_pages = ForgeActivity.where("project_id = ? and forge_act_type = 'Message'",@project).order("updated_at desc").limit(10).offset(@page * 10) + end + #events = @activity.events(@date_from, @date_to) else @events_pages = ForgeActivity.includes(:project).where("forge_activities.project_id = ? and projects.is_public diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb index 1f252cc24..ca07dccdc 100644 --- a/app/controllers/repositories_controller.rb +++ b/app/controllers/repositories_controller.rb @@ -31,10 +31,10 @@ class RepositoriesController < ApplicationController default_search_scope :changesets before_filter :find_project_by_project_id, :only => [:new, :create, :newrepo] - before_filter :find_repository, :only => [:edit, :update, :destroy, :committers] + before_filter :find_repository, :only => [:edit, :update, :destroy, :committers, :forked] before_filter :find_project_repository, :except => [:new, :create, :newcreate, :edit, :update, :destroy, :committers, :newrepo,:to_gitlab] before_filter :find_changeset, :only => [:revision, :add_related_issue, :remove_related_issue] - before_filter :authorize , :except => [:newrepo,:newcreate,:fork, :to_gitlab] + before_filter :authorize , :except => [:newrepo,:newcreate,:fork, :to_gitlab, :forked] accept_rss_auth :revisions # hidden repositories filter // 隐藏代码过滤器 before_filter :check_hidden_repo, :only => [:show, :stats, :revisions, :revision, :diff ] @@ -42,7 +42,7 @@ class RepositoriesController < ApplicationController include RepositoriesHelper helper :project_score #@root_path = RepositoriesHelper::ROOT_PATH - + $g=Gitlab.client rescue_from Redmine::Scm::Adapters::CommandFailed, :with => :show_error_command_failed def new @@ -63,6 +63,98 @@ class RepositoriesController < ApplicationController end + def forked + # 如果当前用户已经fork过该项目,不会新fork项目,则跳至已fork的项 + unless has_forked?(@project, User.current) + project = project_from_current_project(@project.id, User.current.id) + redirect_to project_path(project) + else + # 自己不能fork自己的项目 + if User.current.id == @project.user_id + flash[:notice] = l(:project_gitlab_fork_own) + redirect_to repository_url(@repository) + else + g = Gitlab.client + gproject = g.fork(@project.gpid, User.current.gid) + if gproject + copy_project(@project, gproject) + forked_count = @project.forked_count.to_i + 1 + @project.update_attributes(:forked_count => forked_count) + end + end + end + + end + + # 判断用户是否已经fork过该项目 + def has_forked?(project, user) + projects = Project.where("user_id =?", user) + projects.map(&:forked_from_project_id).detect{|s| s == @project.id}.nil? ? true : false + end + + # 获取当前用户fork过的项目 + def project_from_current_project(project, user) + project = Project.where("user_id =? and forked_from_project_id =?",user, project).first + end + + # copy a project for fork + def copy_project(tproject, gproject) + project = Project.new + project.name = tproject.name + project.is_public = tproject.is_public + project.status = tproject.status + project.description = tproject.description + project.hidden_repo = tproject.hidden_repo + project.user_id = User.current.id + project.project_type = 0 + project.project_new_type = tproject.project_new_type + project.gpid = gproject.id + project.forked_from_project_id = tproject.id + if project.save + r = Role.givable.find_by_id(Setting.new_project_user_role_id.to_i) || Role.givable.first + m = Member.new(:user => User.current, :roles => [r]) + project_info = ProjectInfo.new(:user_id => User.current.id, :project_id => project.id) + user_grades = UserGrade.create(:user_id => User.current.id, :project_id => project.id) + Rails.logger.debug "UserGrade created: #{user_grades.to_json}" + project_status = ProjectStatus.create(:project_id => @project.id, :watchers_count => 0, :changesets_count => 0, :project_type => @project.project_type,:grade => 0) + Rails.logger.debug "ProjectStatus created: #{project_status.to_json}" + project.members << m + project.project_infos << project_info + copy_repository(project, gproject) + respond_to do |format| + format.html { + flash[:notice] = l(:notice_successful_create) + if params[:continue] + attrs = {:parent_id => project.parent_id}.reject {|k,v| v.nil?} + redirect_to new_project_url(attrs, :course => '0') + else + redirect_to settings_project_url(project) + end + } + format.api { render :action => 'show', :status => :created, :location => url_for(:controller => 'projects', :action => 'show', :id => project.id) } + format.js + end + else + respond_to do |format| + format.html { render :action => 'forked', :layout => 'base_projects'} + format.api { render_validation_errors(@project) } + end + end + end + + def copy_repository(project, gproject) + # 避免 + # if is_sigle_identifier?(project.user_id, gproject.name) + repository = Repository.factory('Git') + repository.project_id = project.id + repository.type = 'Repository::Gitlab' + repository.url = gproject.name + repository.identifier = gproject.name + repository = repository.save + # else + # flash[:notice] = l(:project_gitlab_create_double_message) + # end + end def newrepo scm = params[:repository_scm] || (Redmine::Scm::Base.all & Setting.enabled_scm).first @@ -115,21 +207,27 @@ update } def create - attrs = pickup_extra_info - @repository = Repository.factory('Git') - @repository.safe_attributes = params[:repository] - if attrs[:attrs_extra].keys.any? - @repository.merge_extra_info(attrs[:attrs_extra]) - end - @repository.project = @project - @repository.type = 'Repository::Gitlab' - @repository.url = @repository.identifier - if request.post? && @repository.save - s = Trustie::Gitlab::Sync.new - s.create_project(@project, @repository) + # 判断版本库创建者是否有同名版本库,避免版本库路径一致问题 + unless is_sigle_identifier?(@project.user_id, params[:repository].first[1]) + flash[:notice] = l(:project_gitlab_create_double_message) redirect_to settings_project_url(@project, :tab => 'repositories') else - redirect_to settings_project_url(@project, :tab => 'repositories',:repository_error_message=>@repository.errors.full_messages) + attrs = pickup_extra_info + @repository = Repository.factory('Git') + @repository.safe_attributes = params[:repository] + if attrs[:attrs_extra].keys.any? + @repository.merge_extra_info(attrs[:attrs_extra]) + end + @repository.project = @project + @repository.type = 'Repository::Gitlab' + @repository.url = @repository.identifier + if request.post? && @repository.save + s = Trustie::Gitlab::Sync.new + s.create_project(@project, @repository) + redirect_to settings_project_url(@project, :tab => 'repositories') + else + redirect_to settings_project_url(@project, :tab => 'repositories',:repository_error_message=>@repository.errors.full_messages) + end end end @@ -237,14 +335,34 @@ update #Modified by young # (show_error_not_found; return) unless @entries g = Gitlab.client - count = 0 - (0..100).each do |page| - if g.commits(@project.gpid,:page => page).count == 0 - break - else - count = count + g.commits(@project.gpid,:page => page).count - end + + # count = 0 + # (0..100).each do |page| + # if g.commits(@project.gpid,:page => page).count == 0 + # break + # else + # count = count + g.commits(@project.gpid,:page => page).count + # end + # end + + + #add by hx + if g.commits(@project.gpid , :page=>25).count==0 + count = count_commits(@project.gpid , 0 , 25) + elsif g.commits(@project.gpid , :page=>50).count ==0 + count = count_commits(@project.gpid , 25 , 50)+ 25 * 20 + elsif g.commits(@project.gpid , :page=>75).count ==0 + count = count_commits(@project.gpid , 50 , 75)+ 50 * 20 + elsif g.commits(@project.gpid , :page=>100).count== 0 + count = count_commits(@project.gpid , 75 , 100) + 75 * 20 + elsif g.commits(@project.gpid , :page=>125).count==0 + count = count_commits(@project.gpid , 100 , 125) + 100 * 20 + elsif g.commits(@project.gpid , :page=>150).count==0 + count = count_commits(@project.gpid , 125 , 150) + 125 * 20 + else + count = count_commits(@project.gpid , 150 ,200) + 150 * 20 end + @changesets = g.commits(@project.gpid) # @changesets = @repository.latest_changesets(@path, @rev) # @changesets_count = @repository.latest_changesets(@path, @rev).count @@ -271,11 +389,30 @@ update alias_method :browse, :show + #add by hx + def count_commits(project_id , left , right) + count = 0 + (left..right).each do |page| + if $g.commits(project_id,:page => page).count == 0 + break + else + count = count + $g.commits(project_id,:page => page).count + end + end + return count + end + def changes @entry = @repository.entry(@path, @rev) (show_error_not_found; return) unless @entry g = Gitlab.client - @commits = g.commits(@project.gpid, page:params[:pamge]) + limit = 20 + #每次页面的换回值从1开始,但是gitlab的页面查询是从0开始,所以先改变page的类型减一在改回来 + @commits = g.commits(@project.gpid, page:(params[:page].to_i - 1).to_s) + #页面传递必须要str类型,但是Paginator的初始化必须要num类型,需要类型转化 + @commits_count = params[:commit_count].to_i + @commits_pages = Redmine::Pagination::Paginator.new @commits_count,limit,params[:page] + @commit = g.commit(@project.gpid,@rev) # @changesets = g.get ("/projects/#{@project.gpid}/repository/commits?#{@rev}") #@changesets = @repository.latest_changesets(@path, @rev, Setting.repository_log_display_limit.to_i) @@ -284,6 +421,7 @@ update render :layout => 'base_projects' end + def revisions @changeset_count = @repository.changesets.count @changeset_pages = Paginator.new @changeset_count, @@ -467,8 +605,8 @@ update def find_repository @repository = Repository.find(params[:id]) @project = @repository.project - rescue ActiveRecord::RecordNotFound - render_404 + rescue ActiveRecord::RecordNotFound + render_404 end REV_PARAM_RE = %r{\A[a-f0-9]*\Z}i diff --git a/app/controllers/student_work_controller.rb b/app/controllers/student_work_controller.rb index 87d13e169..77868c689 100644 --- a/app/controllers/student_work_controller.rb +++ b/app/controllers/student_work_controller.rb @@ -3,8 +3,8 @@ class StudentWorkController < ApplicationController include StudentWorkHelper require 'bigdecimal' require "base64" - before_filter :find_homework, :only => [:new, :index, :create, :student_work_absence_penalty, :absence_penalty_list, :evaluation_list, :program_test,:set_score_rule,:forbidden_anonymous_comment] - before_filter :find_work, :only => [:edit, :update, :show, :destroy, :add_score, :praise_student_work] + before_filter :find_homework, :only => [:new, :index, :create, :student_work_absence_penalty, :absence_penalty_list, :evaluation_list, :program_test,:set_score_rule,:forbidden_anonymous_comment,:delete_work] + before_filter :find_work, :only => [:edit, :update, :show, :destroy, :add_score, :praise_student_work,:retry_work,:revise_attachment] before_filter :member_of_course, :only => [:index, :new, :create, :show, :add_score, :praise_student_work] before_filter :author_of_work, :only => [:edit, :update, :destroy] before_filter :teacher_of_course, :only => [:student_work_absence_penalty, :absence_penalty_list, :evaluation_list, :set_score_rule, :forbidden_anonymous_comment] @@ -76,7 +76,7 @@ class StudentWorkController < ApplicationController end ################################################################################################################## @order,@b_sort,@name,@group = params[:order] || "score",params[:sort] || "desc",params[:name] || "",params[:group] - @homework_commons = @course.homework_commons.order("created_at desc") + @homework_commons = @course.homework_commons.where("publish_time <= ?",Time.now.strftime("%Y-%m-%d")).order("created_at desc") @is_teacher = User.current.allowed_to?(:as_teacher,@course) || User.current.admin? @is_evaluation = @homework.homework_detail_manual && @homework.homework_detail_manual.comment_status == 2 && !@is_teacher #是不是匿评 @show_all = false @@ -168,9 +168,15 @@ class StudentWorkController < ApplicationController def create # 提交作品前先判断是否已经提交 + @has_commit = false; if hsd_committed_work?(User.current.id, @homework.id) - flash[:notice] = l(:notice_successful_create) - redirect_to edit_student_work_url(params[:student_work]) + @work = StudentWork.where("user_id =? and homework_common_id =?", User.current.id, @homework.id).first + @has_commit = true; + #flash[:notice] = l(:notice_successful_create) + #redirect_to edit_student_work_url(params[:student_work]) + respond_to do |format| + format.js + end return end if params[:student_work] @@ -216,7 +222,7 @@ class StudentWorkController < ApplicationController def edit @user = User.current - if !User.current.admin? && @homework.homework_type == 2 #编程作业不能修改作业 + if (!User.current.admin? && @homework.homework_type == 2) || Time.parse(@homework.end_time.to_s).strftime("%Y-%m-%d") < Time.now.strftime("%Y-%m-%d") #编程作业不能修改作业|| 截止日期已到不能修改作业 render_403 else respond_to do |format| @@ -278,6 +284,23 @@ class StudentWorkController < ApplicationController end end + def delete_work + @work = StudentWork.where("user_id =? and homework_common_id =?", User.current.id, @homework.id).first + if @work + @work.destroy + end + redirect_to user_homeworks_user_path(User.current.id) + end + + def retry_work + if @work.destroy + @student_work = StudentWork.new + respond_to do |format| + format.js + end + end + end + #添加评分,已评分则为修改评分 def add_score @is_last = params[:is_last] == "true" @@ -477,8 +500,9 @@ class StudentWorkController < ApplicationController if params[:student_path] redirect_to student_work_index_url(:homework => @homework.id) else - @user_activity_id = params[:user_activity_id] - @is_in_course = params[:is_in_course] + @user_activity_id = params[:user_activity_id].to_i + @is_in_course = params[:is_in_course].to_i + @course_activity = params[:course_activity].to_i respond_to do |format| format.js end @@ -504,6 +528,18 @@ class StudentWorkController < ApplicationController @course_activity = params[:course_activity].to_i end + def revise_attachment + Attachment.attach_filesex(@work, params[:attachments], params[:attachment_type]) + revise_attachments = @work.attachments.where("attachtype = 7").reorder("created_on desc") + if revise_attachments.count == 2 + revise_attachments.last.destroy + end + #@attachment = @work.attachments.where("attachtype = 7").order("created_on desc").first + respond_to do |format| + format.js + end + end + private def hsd_committed_work?(user, homework) sw = StudentWork.where("user_id =? and homework_common_id =?", user, homework).first diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 776e6b7d5..834009d71 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -92,7 +92,7 @@ class UsersController < ApplicationController end # 用户消息 - # 说明: homework 发布作业;message:讨论区; news:新闻; poll:问卷;works_reviewers:作品评阅;works_reply:作品回复 + # 说明: homework 发布作业;message:讨论区; news:新闻; poll:问卷;works_reviewers:作品评阅;works_reply:作品回复,exercise:课程测验 # issue:问题;journal:缺陷状态更新; forum:公共贴吧: user_feedback: 用户留言; new_reply:新闻回复(comment) def user_messages if !User.current.logged? @@ -128,7 +128,7 @@ class UsersController < ApplicationController #课程相关消息 when 'homework' - @message_alls = CourseMessage.where("course_message_type in ('HomeworkCommon','StudentWorksScore','JournalsForMessage','StudentWork') and user_id =?", @user).order("created_at desc") + @message_alls = CourseMessage.where("course_message_type in ('HomeworkCommon','StudentWorksScore','JournalsForMessage','StudentWork','Exercise') and user_id =?", @user).order("created_at desc") when 'course_message' @message_alls = CourseMessage.where("course_message_type =? and user_id =?", "Message", @user).order("created_at desc") when 'course_news' @@ -1367,7 +1367,7 @@ class UsersController < ApplicationController end end - if(params[:type].blank? || params[:type] == "1") #全部 + if(params[:type].nil? || params[:type].blank? || params[:type] == "1" || params[:type] == 'all') #全部 if User.current.id.to_i == params[:id].to_i user_course_ids = User.current.courses.map { |c| c.id} #我的资源库的话,那么应该是我上传的所有资源 加上 我加入的课程的所有资源 @attachments = Attachment.where("(author_id = #{params[:id]} and container_type in('Project','Principal','Course','Issue','Document','Message','News','StudentWorkScore','HomewCommon')) "+ @@ -1429,6 +1429,7 @@ class UsersController < ApplicationController @course = @user.courses .select { |course| @user.allowed_to?(:as_teacher,course)} end + @search = params[:search] #这里仅仅是传递需要发送的资源id @send_id = params[:send_id] @send_ids = params[:checkbox1] || params[:send_ids] @@ -1445,6 +1446,7 @@ class UsersController < ApplicationController else @projects = @user.projects end + @search = params[:search] #这里仅仅是传递需要发送的资源id @send_id = params[:send_id] @send_ids = params[:checkbox1] || params[:send_ids] #搜索的时候 和 直接 用表格提交的时候的send_ids @@ -1856,7 +1858,7 @@ class UsersController < ApplicationController # 根据资源关键字进行搜索 def resource_search search = params[:search].to_s.strip.downcase - if(params[:type].nil? || params[:type] == "1") #全部 + if(params[:type].nil? || params[:type].blank? || params[:type] == "1" || params[:type] == 'all') #全部 if User.current.id.to_i == params[:id].to_i user_course_ids = User.current.courses.map { |c| c.id} #我的资源库的话,那么应该是我上传的所有资源 加上 我加入的课程的所有资源 取交集并查询 @attachments = Attachment.where("((author_id = #{params[:id]} and container_type in('Project','Principal','Course','Issue','Document','Message','News','StudentWorkScore','HomewCommon')) "+ diff --git a/app/controllers/welcome_controller.rb b/app/controllers/welcome_controller.rb index 784066378..815a44839 100644 --- a/app/controllers/welcome_controller.rb +++ b/app/controllers/welcome_controller.rb @@ -151,36 +151,104 @@ class WelcomeController < ApplicationController end def search - search_condition = params[:q] - search_type = params[:search_type].to_sym unless search_condition.blank? - search_by = params[:search_by] + @name = params[:q] + @search_type = params[:search_type] + case params[:search_type] + when 'all' + @alls = Elasticsearch::Model.search({ + query: { + multi_match: { + query: @name, + type:"most_fields", + operator: "or", + fields: ['login', 'firstname','lastname','name','description^0.5','filename'] + } + }, + highlight: { + pre_tags: [''], + post_tags: [''], + fields: { + login: {}, + firstname: {}, + lastname: {}, + name:{}, + description:{}, + filename:{} + } + } + },[User,Course,Attachment,Project] ).page(params[:page] || 1).per(20).results + when 'user' + @users = User.search(@name).page(params[:page] || 1).per(20) + when 'project' + @projects = Project.search(@name).page(params[:page] || 1).per(20).results + when 'course' + @courses = Course.search(@name).page(params[:page] || 1).per(20).results + when 'attachment' + @attachments = Attachment.search(@name).page(params[:page] || 1).per(20).results + else + @alls = Elasticsearch::Model.search({ + query: { + multi_match: { + query: @name, + type:"most_fields", + operator: "or", + fields: ['login', 'firstname','lastname','name','description^0.5','filename'] + } + }, + highlight: { + pre_tags: [''], + post_tags: [''], + fields: { + login: {}, + firstname: {}, + lastname: {}, + name:{}, + description:{}, + filename:{} + } + } + },[User,Course,Attachment,Project] ).page(params[:page] || 1).per(20).results - if search_type.nil? && params[:contests_search] && params[:name] != "" - search_type = :contests - search_condition = params[:name] end + @users_count = User.search(@name).results.total + + @course_count = Course.search(@name).results.total + @attach_count = Attachment.search(@name).results.total + @project_count = Project.search(@name).results.total + @total_count = Elasticsearch::Model.search({ + query: { + multi_match: { + query: @name, + type:"most_fields", + operator: "or", + fields: ['login', 'firstname','lastname','name','description^0.5','filename'] + } + }, + highlight: { + pre_tags: [''], + post_tags: [''], + fields: { + login: {}, + firstname: {}, + lastname: {}, + name:{}, + description:{}, + filename:{} + } + } + },[User,Course,Attachment,Project] ).results.total + # search_type = params[:search_type].to_sym unless search_condition.blank? + # search_by = params[:search_by] + # + # if search_type.nil? && params[:contests_search] && params[:name] != "" + # search_type = :contests + # search_condition = params[:name] + # end + respond_to do |format| - format.html{ - case search_type - when :projects - redirect_to projects_search_url(:name => search_condition, - :project_type => Project::ProjectType_project) - when :courses - redirect_to courses_search_url(:name => search_condition) - when :contests - redirect_to contests_url(:name => search_condition) - when :users - redirect_to users_search_url(:name => search_condition,:search_by => search_by) - when :users_teacher - redirect_to users_search_url(:name => search_condition, :search_by => search_by, :role => :teacher) - when :users_student - redirect_to users_search_url(:name => search_condition, :search_by => search_by, :role => :student) - else - #redirect_to home_path, :alert => l(:label_sumbit_empty) - (redirect_to signin_path, :notice => l(:label_sumbit_empty);return) #if params[:name].blank? - end - } + format.js + format.html{ render :layout=>'users_base'} end end diff --git a/app/controllers/words_controller.rb b/app/controllers/words_controller.rb index 6cc622c49..df9fd30f2 100644 --- a/app/controllers/words_controller.rb +++ b/app/controllers/words_controller.rb @@ -3,6 +3,8 @@ class WordsController < ApplicationController include ApplicationHelper before_filter :find_user, :only => [:new, :create, :destroy, :more, :back] + before_filter :require_login, :only => [:create_reply] + def create if params[:new_form][:user_message].size>0 && User.current.logged? unless params[:user_id].nil? @@ -102,6 +104,15 @@ class WordsController < ApplicationController @user = User.find(@journal_destroyed.jour_id) @jours_count = @user.journals_for_messages.where('m_parent_id IS NULL').count @is_user = true + elsif @journal_destroyed.jour_type == 'HomeworkCommon' + @homework = HomeworkCommon.find @journal_destroyed.jour_id + if params[:user_activity_id] + @user_activity_id = params[:user_activity_id] + else + @user_activity_id = -1 + end + @is_in_course = params[:is_in_course].to_i + @course_activity = params[:course_activity].to_i end respond_to do |format| format.js diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index f4e0f88ff..46a20dd4c 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -75,6 +75,50 @@ module ApplicationHelper end end + # 更新课程英雄榜得分 + # user传过来必须是学生 + def course_member_score(course_id,user_id,type) + course_contributor_score = CourseContributorScore.where("course_id =? and user_id =?", course_id, user_id).first + case type + when "JournalForMessage" + if course_contributor_score.nil? + CourseContributorScore.create(:course_id => course_id, :user_id => user_id, :message_num => 0, :message_reply_num => 0, + :news_reply_num => 0, :resource_num => 0, :journal_num => 1, :journal_reply_num => 0, :total_score => 1) + else + score = course_contributor_score.journal_num + 1 + total_score = course_contributor_score.total_score + 1 + course_contributor_score.update_attributes(:journal_num => score, :total_score => total_score) + end + when "Message" + if course_contributor_score.nil? + CourseContributorScore.create(:course_id => course_id, :user_id => user_id, :message_num => 2, :message_reply_num => 0, + :news_reply_num => 0, :resource_num => 0, :journal_num => 0, :journal_reply_num => 0, :total_score => 2) + else + score = course_contributor_score.message_num + 2 + total_score = course_contributor_score.total_score + 2 + course_contributor_score.update_attributes(:message_num => score, :total_score => total_score) + end + when "MessageReply" + if course_contributor_score.nil? + CourseContributorScore.create(:course_id => course_id, :user_id => user_id, :message_num => 0, :message_reply_num => 1, + :news_reply_num => 0, :resource_num => 0, :journal_num => 0, :journal_reply_num => 0, :total_score => 1) + else + score = course_contributor_score.message_reply_num + 1 + total_score = course_contributor_score.total_score + 1 + course_contributor_score.update_attributes(:message_reply_num => score, :total_score => total_score) + end + when "NewReply" + if course_contributor_score.nil? + CourseContributorScore.create(:course_id => course_id, :user_id => user_id, :message_num => 0, :message_reply_num => 0, + :news_reply_num => 1, :resource_num => 0, :journal_num => 0, :journal_reply_num => 0, :total_score => 1) + else + score = course_contributor_score.news_reply_num + 1 + total_score = course_contributor_score.total_score + 1 + course_contributor_score.update_attributes(:news_reply_num => score, :total_score => total_score) + end + end + end + # Added by young # Define the course menu's link class # 不是数组的转化成数组,然后判断当前menu_item是否在给定的列表 @@ -1825,6 +1869,23 @@ module ApplicationHelper s end + def get_user_identity identity + s = "" + case identity + when 0 + s = '教师' + when 1 + s = '学生' + when 2 + s = '组织' + when 3 + s= '开发者' + else + s = '学生' + end + s + end + def get_memo @new_memo = Memo.new @public_forum = Forum.find(1) rescue ActiveRecord::RecordNotFound @@ -2382,7 +2443,7 @@ module ApplicationHelper if homework.homework_detail_manual && homework.homework_detail_manual.comment_status == 2 #匿评作业,且作业状态不是在开启匿评之前 link_to "作品匿评", student_work_index_path(:homework => homework.id), :class => 'c_blue', :title => "开启匿评后不可修改作品" elsif homework.homework_detail_manual && homework.homework_detail_manual.comment_status == 3 - link_to "匿评结束", student_work_index_path(:homework => homework.id), :class => 'c_blue', :title => "匿评已结束" + link_to "查看作品(#{homework.student_works.count})", student_work_index_path(:homework => homework.id), :class => 'c_blue', :title => "匿评已结束" elsif homework.homework_type == 2 && Time.parse(homework.end_time.to_s).strftime("%Y-%m-%d") >= Time.now.strftime("%Y-%m-%d")#编程作业不能修改作品 link_to "修改作品(#{homework.student_works.count})", new_student_work_path(:homework => homework.id),:class => 'c_blue' elsif Time.parse(homework.end_time.to_s).strftime("%Y-%m-%d") >= Time.now.strftime("%Y-%m-%d") diff --git a/app/helpers/courses_helper.rb b/app/helpers/courses_helper.rb index caca6fb1e..a1b119cb5 100644 --- a/app/helpers/courses_helper.rb +++ b/app/helpers/courses_helper.rb @@ -25,6 +25,10 @@ module CoursesHelper # searchTeacherAndAssistant(project).count end + def show_nav?(count) + count == 0 ? true : false + end + #课程模块需要展示的模块 def course_model @nav_dispaly_course_all_label = 1 @@ -733,4 +737,26 @@ module CoursesHelper end desc.html_safe end + + # 学生按作业总分排序,取前8个 + def hero_homework_score(course, score_sort_by) + sql_select = "SELECT members.*,( + SELECT SUM(student_works.final_score) + FROM student_works,homework_commons + WHERE student_works.homework_common_id = homework_commons.id + AND homework_commons.course_id = #{course.id} + AND student_works.user_id = members.user_id + ) AS score + FROM members + JOIN students_for_courses + ON students_for_courses.student_id = members.user_id AND students_for_courses.course_id = members.course_id + WHERE members.course_id = #{course.id} ORDER BY score #{score_sort_by} limit 9" + homework_scores = Member.find_by_sql(sql_select) + end + + def contributor_course_scor(course_id) + ccs = CourseContributorScore.where("course_id =?", course_id).order("total_score desc") .limit(9) + end + end + diff --git a/app/helpers/exercise_helper.rb b/app/helpers/exercise_helper.rb index bb87f3b82..b0d0118e5 100644 --- a/app/helpers/exercise_helper.rb +++ b/app/helpers/exercise_helper.rb @@ -107,6 +107,19 @@ module ExerciseHelper end end + #获取未完成的题目 + def get_uncomplete_question exercise,user + all_questions = exercise.exercise_questions + uncomplete_question = [] + all_questions.each do |question| + answers = get_user_answer(question, user) + if answers.empty? + uncomplete_question << question + end + end + uncomplete_question + end + #获取文本题答案 def get_anwser_vote_text(question_id,user_id) pv = ExerciseAnswer.find_by_exercise_question_id_and_user_id(question_id,user_id) diff --git a/app/helpers/org_subfields_helper.rb b/app/helpers/org_subfields_helper.rb new file mode 100644 index 000000000..a9f8a396f --- /dev/null +++ b/app/helpers/org_subfields_helper.rb @@ -0,0 +1,2 @@ +module OrgSubfieldsHelper +end diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb index f32bef51b..ff4aa61fb 100644 --- a/app/helpers/repositories_helper.rb +++ b/app/helpers/repositories_helper.rb @@ -27,6 +27,20 @@ module RepositoriesHelper REPO_IP_ADDRESS = Setting.host_repository REPO_GITLAB_ADDRESS = "git.trustie.net" + # 某个成员不能拥有同名版本库,不同的成员可以创建同名版本库 + def is_sigle_identifier?(user_id, iden) + projects = Project.where("user_id =?",user_id) + identifiers = [] + projects.each do |project| + # 只针对gitlab类型的,git类型的后期清掉 + repository = Repository.where("project_id =? and type =?", project.id, "Repository::Gitlab").first + if repository + identifiers << repository.identifier + end + end + identifiers.include?(iden) ? false :true + end + def format_revision(revision) if revision.respond_to? :format_identifier revision.format_identifier @@ -47,7 +61,7 @@ module RepositoriesHelper def user_commit_rep(mail) user = User.find_by_mail(mail) - user.nil? ? User.find(2) : User.find_by_mail(mail) + #user.nil? ? User.find(2) : User.find_by_mail(mail) end def render_properties(properties) diff --git a/app/helpers/student_work_helper.rb b/app/helpers/student_work_helper.rb index e1cf3464e..df5c872f8 100644 --- a/app/helpers/student_work_helper.rb +++ b/app/helpers/student_work_helper.rb @@ -126,4 +126,15 @@ module StudentWorkHelper end type end + + def revise_attachment_status homework, attach + date = Time.parse(format_time(attach.created_on.to_s)).strftime("%Y-%m-%d") + status = "" + if homework.homework_detail_manual && ((homework.anonymous_comment == 0 &&homework.homework_detail_manual.evaluation_start.to_s <= date) || (homework.anonymous_comment == 1 && homework.end_time < date)) + status = "此时其他同学作品已公开" + else + status = "此时其他同学作品尚未公开" + end + return status + end end \ No newline at end of file diff --git a/app/models/attachment.rb b/app/models/attachment.rb index f7fb9b1aa..999cefdaa 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -17,7 +17,7 @@ require "digest/md5" require "fileutils" - +require 'elasticsearch/model' class Attachment < ActiveRecord::Base belongs_to :container, :polymorphic => true belongs_to :project, foreign_key: 'container_id', conditions: "attachments.container_type = 'Project'" @@ -38,6 +38,18 @@ class Attachment < ActiveRecord::Base validates :description, length: {maximum: 254} validate :validate_max_file_size + #elasticsearch + include Elasticsearch::Model + #elasticsearch kaminari init + Kaminari::Hooks.init + Elasticsearch::Model::Response::Response.__send__ :include, Elasticsearch::Model::Response::Pagination::Kaminari + settings index: { number_of_shards: 5 } do + mappings dynamic: 'false' do + indexes :filename, analyzer: 'smartcn',index_options: 'offsets' + indexes :downloads, analyzer: 'smartcn',index_options: 'offsets' + end + end + acts_as_taggable acts_as_event :title => :filename, @@ -74,9 +86,9 @@ class Attachment < ActiveRecord::Base @@thumbnails_storage_path = File.join(Rails.root, "tmp", "thumbnails") before_save :files_to_final_location,:act_as_course_activity - after_create :office_conver, :be_user_score,:act_as_forge_activity - after_update :office_conver, :be_user_score - after_destroy :delete_from_disk,:down_user_score + after_create :office_conver, :be_user_score,:act_as_forge_activity,:create_attachment_ealasticsearch_index + after_update :office_conver, :be_user_score,:update_attachment_ealasticsearch_index + after_destroy :delete_from_disk,:down_user_score,:delete_attachment_ealasticsearch_index # add by nwb # 获取所有可公开的资源文件列表 @@ -92,7 +104,35 @@ class Attachment < ActiveRecord::Base " 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) } - + scope :indexable,lambda { where('is_public = 1 and ((container_type in ("Principal")) ' + + 'or (container_type = "Course" and container_id in( SELECT `courses`.id FROM `courses` WHERE (courses.status <> 9 AND courses.is_public = 1)) )'+ + 'or (container_type = "Project" and container_id in(SELECT `projects`.id FROM `projects` WHERE (projects.status <> 9 AND projects.is_public = 1) ))' +')')} #用于elastic建索引的scope + def self.search(query) + __elasticsearch__.search( + { + query: { + multi_match: { + query: query, + type:"most_fields", + operator: "or", + fields: ['filename'] + } + }, + sort:{ + _score:{order:"desc"}, + downloads: {order:"desc"} + + }, + highlight: { + pre_tags: [''], + post_tags: [''], + fields: { + filename: {} + } + } + } + ) + end # add by nwb # 公开的项目id列表 def self.public_project_id @@ -560,4 +600,47 @@ class Attachment < ActiveRecord::Base self.course_acts << CourseActivity.new(:user_id => self.author_id,:course_id => self.container_id) end end + + def create_attachment_ealasticsearch_index + if self.is_public == 1 && ( (self.container_type == 'Project' && Project.find(self.container_id).is_public == 1) || + ( self.container_type == 'Course' && Course.find(self.container_id).is_public == 1) || + self.container_type == 'Principal') + self.__elasticsearch__.index_document + end + end + def update_attachment_ealasticsearch_index + if self.is_public == 1 && ( (self.container_type == 'Project' && Project.find(self.container_id).is_public == 1) || + ( self.container_type == 'Course' && Course.find(self.container_id).is_public == 1) || + self.container_type == 'Principal') + begin + self.__elasticsearch__.update_document + rescue => e + end + else + begin + self.__elasticsearch__.delete_document + rescue => e + end + end + end + def delete_attachment_ealasticsearch_index + begin + self.__elasticsearch__.delete_document + rescue => e + end + end end + +# Delete the previous articles index in Elasticsearch +# Attachment.__elasticsearch__.client.indices.delete index: Attachment.index_name rescue nil +# +# # Create the new index with the new mapping +# Attachment.__elasticsearch__.client.indices.create \ +# index: Attachment.index_name, +# body: { settings: Attachment.settings.to_hash, mappings: Attachment.mappings.to_hash } + +# Index all article records from the DB to Elasticsearch +#暂时只做公开课程/项目里的公开资源 和其他的公开资源 +#Attachment.where('is_public = 1 and ((container_type in ("Principal")) ' + +# 'or (container_type = "Course" and container_id in( SELECT `courses`.id FROM `courses` WHERE (courses.status <> 9 AND courses.is_public = 1)) )'+ +# 'or (container_type = "Project" and container_id in(SELECT `projects`.id FROM `projects` WHERE (projects.status <> 9 AND projects.is_public = 1) ))' +')').import :force=>true diff --git a/app/models/board.rb b/app/models/board.rb index edcbe0c9d..67d59e599 100644 --- a/app/models/board.rb +++ b/app/models/board.rb @@ -17,8 +17,8 @@ class Board < ActiveRecord::Base include Redmine::SafeAttributes - belongs_to :project - belongs_to :course + belongs_to :project,:touch => true + belongs_to :course,:touch=>true 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 diff --git a/app/models/comment.rb b/app/models/comment.rb index bb31eb894..69753d81c 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -31,11 +31,11 @@ class Comment < ActiveRecord::Base :title=>Proc.new {|o| "RE: #{o.commented.title}" }, :url => Proc.new {|o| {:controller => 'news', :action => 'show', :id => o.commented.id} } - belongs_to :commented, :polymorphic => true, :counter_cache => true + belongs_to :commented, :polymorphic => true, :counter_cache => true,:touch => true belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' validates_presence_of :commented, :author, :comments safe_attributes 'comments' - after_create :send_mail, :act_as_system_message + after_create :send_mail, :act_as_system_message, :act_as_student_score def act_as_system_message if self.commented.course @@ -66,13 +66,26 @@ class Comment < ActiveRecord::Base def set_notify_id(notify_id) @notify_id= notify_id end + def get_notify_id() return @notify_id end + def set_notify_is_read(notify_is_read) @notify_is_read = notify_is_read end + def get_notify_is_read() return @notify_is_read end + + # 课程成员得分(英雄榜) + def act_as_student_score + if self.commented.course + unless self.author.allowed_to?(:as_teacher, self.commented.course) + course_member_score(self.commented.course.id, self.author_id, "NewReply") + end + end + end + end diff --git a/app/models/course.rb b/app/models/course.rb index 1350b8cf7..1c1bedb3b 100644 --- a/app/models/course.rb +++ b/app/models/course.rb @@ -1,10 +1,24 @@ - +require 'elasticsearch/model' class Course < ActiveRecord::Base include Redmine::SafeAttributes STATUS_ACTIVE = 1 STATUS_CLOSED = 5 STATUS_ARCHIVED = 9 + + #elasticsearch + include Elasticsearch::Model + + #elasticsearch kaminari init + Kaminari::Hooks.init + Elasticsearch::Model::Response::Response.__send__ :include, Elasticsearch::Model::Response::Pagination::Kaminari + settings index: { number_of_shards: 5 } do + mappings dynamic: 'false' do + indexes :name, analyzer: 'smartcn',index_options: 'offsets' + indexes :description, analyzer: 'smartcn',index_options: 'offsets' + indexes :updated_at, analyzer: 'smartcn',index_options: 'offsets',type:"date" + end + end attr_accessible :code, :extra, :name, :state, :tea_id, :time , :location, :state, :term, :password,:is_public,:description,:class_period, :open_student, :enterprise_name #belongs_to :project, :class_name => 'Course', :foreign_key => :extra, primary_key: :identifier @@ -18,7 +32,7 @@ class Course < ActiveRecord::Base :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 :org_courses + has_many :org_courses, :dependent => :destroy has_many :organizations, :through => :org_courses # has_many :homeworks, :through => :homework_for_courses, :source => :bid, :dependent => :destroy has_many :journals_for_messages, :as => :jour, :dependent => :destroy @@ -40,8 +54,10 @@ class Course < ActiveRecord::Base has_many :course_activities # 课程消息 - has_many :course_messages, :class_name =>'CourseMessage', :as => :course_message, :dependent => :destroy + has_many :course_messages, :class_name =>'CourseMessage', :as => :course_message, :dependent => :destroy has_many :exercises, :dependent => :destroy + # 课程贡献榜 + has_many :course_contributor_scores, :dependent => :destroy acts_as_taggable acts_as_nested_set :order => 'name', :dependent => :destroy @@ -54,9 +70,9 @@ class Course < ActiveRecord::Base validates_length_of :description, :maximum => 10000 before_save :self_validate # 公开课程变成私有课程,所有资源都变成私有 - after_update :update_files_public - after_create :create_board_sync, :act_as_course_activity, :act_as_course_message - before_destroy :delete_all_members + after_update :update_files_public,:update_course_ealasticsearch_index + after_create :create_board_sync, :act_as_course_activity, :act_as_course_message,:create_course_ealasticsearch_index + before_destroy :delete_all_members,:delete_course_ealasticsearch_index safe_attributes 'extra', 'time', @@ -98,6 +114,34 @@ class Course < ActiveRecord::Base where(" LOWER(name) LIKE :p ", :p => pattern) end } + scope :indexable,lambda { where('is_public = 1') } + def self.search(query) + __elasticsearch__.search( + { + query: { + multi_match: { + query: query, + type:"most_fields", + operator: "or", + fields: ['name', 'description^0.5'] + } + }, + sort: { + _score:{order: "desc" }, + updated_at:{order:"desc"} + + }, + highlight: { + pre_tags: [''], + post_tags: [''], + fields: { + name: {}, + description: {} + } + } + } + ) + end def visible?(user=User.current) user.allowed_to?(:view_course, self) @@ -342,6 +386,57 @@ class Course < ActiveRecord::Base #def name # read_attribute('name') || Project.find_by_identifier(self.extra).try(:name) #end + + # after_commit on: [:create] do + # __elasticsearch__.index_document + # end + # + # after_commit on: [:update] do + # __elasticsearch__.update_document + # end + # + # after_commit on: [:destroy] do + # __elasticsearch__.delete_document + # end + def create_course_ealasticsearch_index + if self.is_public == 1 + self.__elasticsearch__.index_document + end + end + def update_course_ealasticsearch_index + if self.is_public == 1 #如果是初次更新成为公开的情况,会报错,那么这条记录尚未被索引过。没有报错就是更新的其他属性 + begin + self.__elasticsearch__.update_document + rescue => e + self.__elasticsearch__.index_document + end + else #如果是更新成为私有的,那么索引就要被删除 + begin + self.__elasticsearch__.delete_document + rescue => e + + end + end + end + + def delete_course_ealasticsearch_index + begin + self.__elasticsearch__.delete_document + rescue => e + + end + end end +# Delete the previous articles index in Elasticsearch +# Course.__elasticsearch__.client.indices.delete index: Course.index_name rescue nil +# +# # Create the new index with the new mapping +# Course.__elasticsearch__.client.indices.create \ +# index: Course.index_name, +# body: { settings: Course.settings.to_hash, mappings: Course.mappings.to_hash } + +# Index all article records from the DB to Elasticsearch +#Course.where('is_public = 1').import :force=>true + diff --git a/app/models/course_contributor_score.rb b/app/models/course_contributor_score.rb new file mode 100644 index 000000000..f2b05458f --- /dev/null +++ b/app/models/course_contributor_score.rb @@ -0,0 +1,5 @@ +class CourseContributorScore < ActiveRecord::Base + attr_accessible :course_id, :journal_num, :journal_reply_num, :message_num, :message_reply_num, :news_reply_num, :resource_num, :user_id, :total_score + belongs_to :course + belongs_to :user +end diff --git a/app/models/document.rb b/app/models/document.rb index 37983d6d4..b45a74775 100644 --- a/app/models/document.rb +++ b/app/models/document.rb @@ -17,7 +17,7 @@ class Document < ActiveRecord::Base include Redmine::SafeAttributes - belongs_to :project + belongs_to :project,:touch=>true belongs_to :user belongs_to :category, :class_name => "DocumentCategory", :foreign_key => "category_id" include UserScoreHelper diff --git a/app/models/editor_of_document.rb b/app/models/editor_of_document.rb new file mode 100644 index 000000000..15d9e7e37 --- /dev/null +++ b/app/models/editor_of_document.rb @@ -0,0 +1,4 @@ +class EditorOfDocument < ActiveRecord::Base + belongs_to :user, :class_name => 'User', :foreign_key => 'editor_id' + belongs_to :org_document_comment +end \ No newline at end of file diff --git a/app/models/exercise.rb b/app/models/exercise.rb index e4295971e..c91e59fd9 100644 --- a/app/models/exercise.rb +++ b/app/models/exercise.rb @@ -2,7 +2,22 @@ class Exercise < ActiveRecord::Base #exercise_status: 1,新建;2,发布;3,关闭 include Redmine::SafeAttributes belongs_to :user + belongs_to :course ,:touch => true has_many :exercise_questions, :dependent => :destroy,:order => "#{ExerciseQuestion.table_name}.question_number" has_many :exercise_users, :dependent => :destroy has_many :users, :through => :exercise_users #该测试被哪些用户提交答案过 + # 课程消息 + has_many :course_messages, :class_name =>'CourseMessage', :as => :course_message, :dependent => :destroy + after_create :acts_as_course_message + def acts_as_course_message + if self.course + if self.exercise_status == 2 #未发布 + #self.course.members.each do |m| + self.course_messages << CourseMessage.create(:user_id => User.current.id, :course_id => self.course_id, :viewed => false,:status=>2) + #end + # else + # self.course_messages.destroy_all 这里的destory_all值得商榷。因为我这里是通过status来控制不同的status的 + end + end + end end diff --git a/app/models/forge_activity.rb b/app/models/forge_activity.rb index bb5f30442..c98c5475b 100644 --- a/app/models/forge_activity.rb +++ b/app/models/forge_activity.rb @@ -46,18 +46,24 @@ class ForgeActivity < ActiveRecord::Base end def add_org_activity - if self.forge_act_type == 'Message' && !self.forge_act.parent_id.nil? - org_activity = OrgActivity.where("org_act_type = 'Message' and org_act_id = #{self.forge_act.parent.id}").first + org_activity = OrgActivity.where("org_act_type = '#{self.forge_act_type.to_s}' and org_act_id = #{self.forge_act_id}").first + if org_activity org_activity.created_at = self.created_at org_activity.save else - OrgActivity.create(:user_id => self.user_id, - :org_act_id => self.forge_act_id, - :org_act_type => self.forge_act_type, - :container_id => self.project_id, - :container_type => 'Project', - :created_at => self.created_at, - :updated_at => self.updated_at) + if self.forge_act_type == 'Message' && !self.forge_act.parent_id.nil? + org_activity = OrgActivity.where("org_act_type = 'Message' and org_act_id = #{self.forge_act.parent.id}").first + org_activity.created_at = self.created_at + org_activity.save + else + OrgActivity.create(:user_id => self.user_id, + :org_act_id => self.forge_act_id, + :org_act_type => self.forge_act_type, + :container_id => self.project_id, + :container_type => 'Project', + :created_at => self.created_at, + :updated_at => self.updated_at) + end end end diff --git a/app/models/issue.rb b/app/models/issue.rb index 2a6da44c5..edce3310a 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -19,7 +19,7 @@ class Issue < ActiveRecord::Base include Redmine::SafeAttributes include Redmine::Utils::DateCalculation include UserScoreHelper - belongs_to :project + belongs_to :project,:touch=> true belongs_to :tracker belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id' belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' diff --git a/app/models/journals_for_message.rb b/app/models/journals_for_message.rb index 5e40267cb..ec6390408 100644 --- a/app/models/journals_for_message.rb +++ b/app/models/journals_for_message.rb @@ -21,9 +21,10 @@ class JournalsForMessage < ActiveRecord::Base after_destroy :delete_kindeditor_assets belongs_to :project, :foreign_key => 'jour_id', - :conditions => "#{self.table_name}.jour_type = 'Project' " + :conditions => "#{self.table_name}.jour_type = 'Project' ",:touch => true + belongs_to :course, - :foreign_key => 'jour_id' + :foreign_key => 'jour_id',:touch=>true belongs_to :jour, :polymorphic => true @@ -64,7 +65,7 @@ class JournalsForMessage < ActiveRecord::Base has_many :user_feedback_messages, :class_name => 'UserFeedbackMessage', :as =>:journals_for_message, :dependent => :destroy validates :notes, presence: true, if: :is_homework_jour? - after_create :act_as_activity, :act_as_course_activity, :act_as_course_message, :act_as_user_feedback_message, :act_as_principal_activity + after_create :act_as_activity, :act_as_course_activity, :act_as_course_message, :act_as_user_feedback_message, :act_as_principal_activity, :act_as_student_score after_create :reset_counters! after_destroy :reset_counters! after_save :be_user_score @@ -263,4 +264,12 @@ class JournalsForMessage < ActiveRecord::Base end end + + # 课程成员得分(英雄榜) + def act_as_student_score + unless self.user.allowed_to?(:as_teacher, self.jour) + course_member_score(self.jour_id, self.user_id, "JournalForMessage") + end + end + end diff --git a/app/models/message.rb b/app/models/message.rb index 7af59815b..d8f62171a 100644 --- a/app/models/message.rb +++ b/app/models/message.rb @@ -20,7 +20,7 @@ class Message < ActiveRecord::Base include UserScoreHelper include ApplicationHelper has_many_kindeditor_assets :assets, :dependent => :destroy - belongs_to :board + belongs_to :board,:touch => true belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' has_many :praise_tread, as: :praise_tread_object, dependent: :destroy @@ -74,7 +74,7 @@ class Message < ActiveRecord::Base after_update :update_messages_board after_destroy :reset_counters!,:down_user_score,:delete_kindeditor_assets - after_create :act_as_activity,:act_as_course_activity,:be_user_score,:act_as_forge_activity, :act_as_system_message, :send_mail + after_create :act_as_activity,:act_as_course_activity,:be_user_score,:act_as_forge_activity, :act_as_system_message, :send_mail, :act_as_student_score #before_save :be_user_score scope :visible, lambda {|*args| @@ -186,7 +186,7 @@ class Message < ActiveRecord::Base # Description def act_as_forge_activity # 如果project为空,那么就是课程相关的消息 - if !self.board.project.nil? + if !self.board.project.nil? && self.parent_id.nil? self.forge_acts << ForgeActivity.new(:user_id => self.author_id, :project_id => self.board.project.id) end @@ -285,4 +285,18 @@ class Message < ActiveRecord::Base delete_kindeditor_assets_from_disk self.id,OwnerTypeHelper::MESSAGE end + # 课程成员得分(英雄榜) + def act_as_student_score + if self.course + unless self.author.allowed_to?(:as_teacher, self.course) + if self.parent_id.nil? + # 发帖 + course_member_score(self.course.id, self.author_id, "Message") + else + # 回帖 + course_member_score(self.course.id, self.author_id, "MessageReply") + end + end + end + end end diff --git a/app/models/news.rb b/app/models/news.rb index e9b8b5314..53581a536 100644 --- a/app/models/news.rb +++ b/app/models/news.rb @@ -17,11 +17,11 @@ class News < ActiveRecord::Base include Redmine::SafeAttributes - belongs_to :project + belongs_to :project,:touch => true include ApplicationHelper has_many_kindeditor_assets :assets, :dependent => :destroy #added by nwb - belongs_to :course + belongs_to :course,:touch => true belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' has_many :comments, :as => :commented, :dependent => :destroy, :order => "created_on" # fq diff --git a/app/models/org_document_comment.rb b/app/models/org_document_comment.rb index 7b9f9cd75..e2ce350ce 100644 --- a/app/models/org_document_comment.rb +++ b/app/models/org_document_comment.rb @@ -3,7 +3,7 @@ class OrgDocumentComment < ActiveRecord::Base include Redmine::SafeAttributes belongs_to :organization belongs_to :creator, :class_name => 'User', :foreign_key => 'creator_id' - + has_many :editor_of_documents, :dependent => :destroy acts_as_tree :order => "#{OrgDocumentComment.table_name}.sticky asc, #{OrgDocumentComment.table_name}.created_at desc" has_many :org_acts, :class_name => 'OrgActivity',:as =>:org_act ,:dependent => :destroy after_create :document_save_as_org_activity diff --git a/app/models/org_subfield.rb b/app/models/org_subfield.rb new file mode 100644 index 000000000..1660310f8 --- /dev/null +++ b/app/models/org_subfield.rb @@ -0,0 +1,3 @@ +class OrgSubfield < ActiveRecord::Base + belongs_to :organization, :foreign_key => :organization_id +end \ No newline at end of file diff --git a/app/models/organization.rb b/app/models/organization.rb index d3755b5ee..350dc3080 100644 --- a/app/models/organization.rb +++ b/app/models/organization.rb @@ -5,7 +5,8 @@ class Organization < ActiveRecord::Base has_many :projects,:through => :org_projects has_many :courses, :through => :org_courses has_many :org_document_comments, :dependent => :destroy - has_many :org_courses + has_many :org_courses, :dependent => :destroy + has_many :org_subfields, :dependent => :destroy has_many :users, :through => :org_members validates_uniqueness_of :name after_create :save_as_org_activity diff --git a/app/models/project.rb b/app/models/project.rb index 0b0420920..ff546e098 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -14,7 +14,7 @@ # 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 'elasticsearch/model' class Project < ActiveRecord::Base include Redmine::SafeAttributes ProjectType_project = 0 @@ -30,6 +30,19 @@ class Project < ActiveRecord::Base # Specific overidden Activities + #elasticsearch + include Elasticsearch::Model + #elasticsearch kaminari init + Kaminari::Hooks.init + Elasticsearch::Model::Response::Response.__send__ :include, Elasticsearch::Model::Response::Pagination::Kaminari + settings index: { number_of_shards: 5 } do + mappings dynamic: 'false' do + indexes :name, analyzer: 'smartcn',index_options: 'offsets' + indexes :description, analyzer: 'smartcn',index_options: 'offsets' + indexes :updated_on, analyzer: 'smartcn',index_options: 'offsets', type:'date' + end + end + has_many :student_works has_many :time_entry_activities has_many :members, :include => [:principal, :roles], :conditions => "#{Principal.table_name}.type='User' AND #{Principal.table_name}.status=#{Principal::STATUS_ACTIVE}" @@ -138,8 +151,9 @@ class Project < ActiveRecord::Base #ActiveModel::Dirty 这里有一个changed方法。对任何对象都可以用 after_save :update_inherited_members, :if => Proc.new {|project| project.inherit_members_changed?} # 创建project之后默认创建一个board,之后的board去掉了board的概念 - after_create :create_board_sync,:acts_as_forge_activities - before_destroy :delete_all_members + after_create :create_board_sync,:acts_as_forge_activities,:create_project_ealasticsearch_index + before_destroy :delete_all_members,:delete_project_ealasticsearch_index + after_update :update_project_ealasticsearch_index def remove_references_before_destroy return if self.id.nil? Watcher.delete_all ['watchable_id = ?', id] @@ -172,7 +186,33 @@ class Project < ActiveRecord::Base } scope :project_entities, -> { where(project_type: ProjectType_project) } scope :course_entities, -> { where(project_type: ProjectType_course) } - + scope :indexable,lambda { where('is_public = 1')} #用于elastic建索引的scope + def self.search(query) + __elasticsearch__.search( + { + query: { + multi_match: { + query: query, + type:"most_fields", + operator: "or", + fields: ['name','description^0.5'] + } + }, + sort: { + _score:{order: "desc" }, + updated_on:{order: "desc" } + }, + highlight: { + pre_tags: [''], + post_tags: [''], + fields: { + name: {}, + description: {} + } + } + } + ) + end def new_course self.where('project_type = ?', 1) end @@ -1176,5 +1216,36 @@ class Project < ActiveRecord::Base end + def create_project_ealasticsearch_index + if self.is_public + self.__elasticsearch__.index_document + end + end + def update_project_ealasticsearch_index + if self.is_public #如果是初次更新成为公开的情况,会报错,那么这条记录尚未被索引过。没有报错就是更新的其他属性 + begin + self.__elasticsearch__.update_document + rescue => e + self.__elasticsearch__.index_document + end + else #如果是更新成为私有的,那么索引就要被删除 + begin + self.__elasticsearch__.delete_document + rescue => e + + end + end + end + def delete_project_ealasticsearch_index + begin + self.__elasticsearch__.delete_document + rescue => e + + end + end + + end +#Project.where('is_public = 1').import :force=>true + diff --git a/app/models/project_tags.rb b/app/models/project_tags.rb index 16de1ea45..bcf666fb5 100644 --- a/app/models/project_tags.rb +++ b/app/models/project_tags.rb @@ -2,7 +2,7 @@ class ProjectTags < ActiveRecord::Base attr_accessible :description, :project_id, :tag_id, :user_id ####################################################################################################添加代码 - belongs_to :project + belongs_to :project,:touch => true belongs_to :tag belongs_to :user diff --git a/app/models/repository.rb b/app/models/repository.rb index 94b7905c6..f50f37f31 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -40,7 +40,8 @@ class Repository < ActiveRecord::Base validates_length_of :identifier, :maximum => IDENTIFIER_MAX_LENGTH, :allow_blank => true validates_presence_of :identifier#, :unless => Proc.new { |r| r.is_default? || r.set_as_default? } #validates_uniqueness_of :identifier, :scope => :project_id, :allow_blank => true - validates_uniqueness_of :identifier, :allow_blank => true + # 改成同一用户不能有两个相同名字的版本库 + # validates_uniqueness_of :identifier, :allow_blank => true validates_exclusion_of :identifier, :in => %w(show entry raw changes annotate diff show stats graph) # donwcase letters, digits, dashes, underscores but not digits only validates_format_of :identifier, :with => /^[a-z0-9_\-]+$/, :allow_blank => true @@ -52,7 +53,8 @@ class Repository < ActiveRecord::Base 'password', 'path_encoding', 'log_encoding', - 'is_default' + 'is_default', + 'type' safe_attributes 'url', :if => lambda {|repository, user| repository.new_record?} @@ -63,6 +65,10 @@ class Repository < ActiveRecord::Base end def repo_create_validation + # 之所以可以这样改,是因为Fork的时候不需要从Trustie创建版本库,只需从Gitlab关联即可 + if self.class.name.demodulize == "Repository" + return + end unless Setting.enabled_scm.include?(self.class.name.demodulize) errors.add(:type, :invalid) end diff --git a/app/models/student_work.rb b/app/models/student_work.rb index 010ede635..884f4a089 100644 --- a/app/models/student_work.rb +++ b/app/models/student_work.rb @@ -10,6 +10,7 @@ class StudentWork < ActiveRecord::Base has_many :student_work_tests, order: 'id desc' # course's message has_many :course_messages, :class_name =>'CourseMessage', :as => :course_message, :dependent => :destroy + has_many :attachments, :dependent => :destroy before_destroy :delete_praise before_save :set_program_score, :set_src diff --git a/app/models/user.rb b/app/models/user.rb index 3e7bc2ddb..9c437a186 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -16,7 +16,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. require "digest/sha1" - +require 'elasticsearch/model' class User < Principal TEACHER = 0 STUDENT = 1 @@ -25,6 +25,20 @@ class User < Principal include Redmine::SafeAttributes seems_rateable_rater + #elasticsearch + include Elasticsearch::Model + #elasticsearch kaminari init + Kaminari::Hooks.init + Elasticsearch::Model::Response::Response.__send__ :include, Elasticsearch::Model::Response::Pagination::Kaminari + settings index: { number_of_shards: 5 } do + mappings dynamic: 'false' do + indexes :login, analyzer: 'smartcn',index_options: 'offsets' + indexes :firstname, analyzer: 'smartcn',index_options: 'offsets' + indexes :lastname, analyzer: 'smartcn',index_options: 'offsets' + indexes :last_login_on, analyzer: 'smartcn',index_options: 'offsets',type: 'date' + end + end + # Different ways of displaying/sorting users USER_FORMATS = { :firstname_lastname => { @@ -64,6 +78,7 @@ class User < Principal }, } + #每日一报、一事一报、不报 MAIL_NOTIFICATION_OPTIONS = [ #['week', :label_user_mail_option_week], @@ -153,6 +168,8 @@ class User < Principal # 邮件邀请状态 has_many :invite_lists, :dependent => :destroy # end + # 课程贡献榜 + has_many :course_contributor_scores, :dependent => :destroy ######added by nie has_many :project_infos, :dependent => :destroy @@ -160,6 +177,7 @@ class User < Principal ##### has_many :shares ,:dependent => :destroy + # add by zjc has_one :level, :class_name => 'UserLevels', :dependent => :destroy has_many :memos , :foreign_key => 'author_id' @@ -220,12 +238,12 @@ class User < Principal # validates_email_realness_of :mail before_create :set_mail_notification before_save :update_hashed_password - before_destroy :remove_references_before_destroy + before_destroy :remove_references_before_destroy,:delete_user_ealasticsearch_index # added by fq - after_create :act_as_activity, :add_onclick_time, :act_as_principal_activity + after_create :act_as_activity, :add_onclick_time, :act_as_principal_activity,:create_user_ealasticsearch_index # end # 更新邮箱用户或用户名的同事,同步更新邀请信息 - after_update :update_invite_list + after_update :update_invite_list,:update_user_ealasticsearch_index include Trustie::Gitlab::ManageUser @@ -238,7 +256,7 @@ class User < Principal where("#{User.table_name}.id NOT IN (SELECT gu.user_id FROM #{table_name_prefix}groups_users#{table_name_suffix} gu WHERE gu.group_id = ?)", group_id) } scope :sorted, lambda { order(*User.fields_for_order_statement)} - + scope :indexable,lambda { where('id not in (2,4)')} #用于elastic建索引的scope,id为2是匿名用户,4是管理员,不能被索引 scope :like, lambda {|arg, type| if arg.blank? where(nil) @@ -256,7 +274,33 @@ class User < Principal end end } - + def self.search(query) + __elasticsearch__.search( + { + query: { + multi_match: { + query: query, + type:"most_fields", + operator: "or", + fields: ['login', 'firstname','lastname'] + } + }, + sort:{ + _score:{order:"desc"}, + last_login_on: {order:"desc"} + }, + highlight: { + pre_tags: [''], + post_tags: [''], + fields: { + login: {}, + firstname: {}, + lastname: {} + } + } + } + ) + end # ====================================================================== @@ -433,7 +477,7 @@ class User < Principal end if user # user is already in local database - #return nil unless user.active? + return nil if user.locked? return nil unless user.check_password?(password) else # user is not yet registered, try to authenticate with available sources @@ -1117,6 +1161,23 @@ class User < Principal end end + + def create_user_ealasticsearch_index + if self.id != 2 && self.id != 4 + self.__elasticsearch__.index_document + end + end + def update_user_ealasticsearch_index + if self.id != 2 && self.id != 4 + self.__elasticsearch__.update_document + end + end + def delete_user_ealasticsearch_index + if self.id != 2 && self.id != 4 + self.__elasticsearch__.delete_document + end + end + end class AnonymousUser < User @@ -1151,4 +1212,17 @@ class AnonymousUser < User def destroy false end + end + +# Delete the previous articles index in Elasticsearch +# User.__elasticsearch__.client.indices.delete index: User.index_name rescue nil +# +# # Create the new index with the new mapping +# User.__elasticsearch__.client.indices.create \ +# index: User.index_name, +# body: { settings: User.settings.to_hash, mappings: User.mappings.to_hash } + +# Index all article records from the DB to Elasticsearch +# 匿名用户 角色 和 管理员角色不能被索引 +#User.where('id not in (2,4)').import :force=>true diff --git a/app/views/attachments/destroy.js.erb b/app/views/attachments/destroy.js.erb index d23422e24..cfbe68085 100644 --- a/app/views/attachments/destroy.js.erb +++ b/app/views/attachments/destroy.js.erb @@ -1,5 +1,9 @@ <% if @is_destroy%> $("#attachment_<%= @attachment.id%>").remove(); + if(document.getElementById("uploadReviseBox")) { + $("#uploadReviseBox").removeClass('disable_link'); + $("#choose_revise_attach").attr("onclick","_file.click();"); + } <%else%> var attachment_html_obj = $('#attachments_<%= j params[:attachment_id] %>'); //modify by yutao 2015-5-14 当1个页面存在多个上传控件时此块代码存在bug 故改之 start @@ -26,5 +30,10 @@ $('#upload_file_count'+containerid).html(""+count+""+"个文件"+"已上传"); } } + + if(document.getElementById("uploadReviseBox")) { + $("#uploadReviseBox").removeClass('disable_link'); + $("#choose_revise_attach").attr("onclick","_file.click();"); + } //modify by yutao 2015-5-14 当1个页面存在多个上传控件时此块代码存在bug 故改之 end <% end%> \ No newline at end of file diff --git a/app/views/comments/create.js.erb b/app/views/comments/create.js.erb index ea904a63f..b0354b53f 100644 --- a/app/views/comments/create.js.erb +++ b/app/views/comments/create.js.erb @@ -1,3 +1,6 @@ +<% if @course %> $("#user_activity_<%= @user_activity_id%>").replaceWith("<%= escape_javascript(render :partial => 'users/course_news', :locals => {:activity => @news,:user_activity_id =>@user_activity_id}) %>"); - +<% else %> +$("#user_activity_<%= @user_activity_id%>").replaceWith("<%= escape_javascript(render :partial => 'projects/project_news', :locals => {:activity => @news,:user_activity_id =>@user_activity_id}) %>"); +<% end %> init_activity_KindEditor_data('<%= @user_activity_id%>',"","87%"); diff --git a/app/views/courses/_tool_expand.html.erb b/app/views/courses/_tool_expand.html.erb new file mode 100644 index 000000000..e032496ea --- /dev/null +++ b/app/views/courses/_tool_expand.html.erb @@ -0,0 +1,47 @@ +<% course_file_num = visable_attachemnts_incourse(@course).count%> +<% is_teacher = User.current.logged? && (User.current.admin? || User.current.allowed_to?(:as_teacher,@course)) %> +<% if show_nav?(@course.homework_commons.count) %> +
当前测验 - <% if question_count > 0 %>共有<%= question_count %>道题,其中<% end %> - <% if mc_count > 0 %><%= mc_count %>道单选、<% end %> - <% if mcq_count > 0 %><%= mcq_count %>道多选、<% end %> - <% if single_count > 0%><%= single_count %>道填空,<% end %> - 总分为<%=current_score %>分。 +
当前测验<%if question_count >0%>共有<%= question_count %>道题,其中<%end%><%if mc_count > 0%><%=mc_count %>道单选、<%end%><%if mcq_count > 0%><%=mcq_count %>道多选、<%end%><%if single_count > 0%><%=single_count %>道填空,<%end%>总分为<%=current_score %>分。
- 是否确定提交该测验?
+ <% if exercise.publish_time.nil? %>点击提交后测验将立即发布,<% end %>是否确定提交该测验?
- - | -
- - | -
<%= exercise.exercise_description.nil? ? "" :exercise.exercise_description.html_safe%>