Merge branch 'develop' into gitlab_guange

This commit is contained in:
huang 2015-12-01 09:50:05 +08:00
commit 0fe68563dd
47 changed files with 966 additions and 219 deletions

10
Gemfile
View File

@ -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

View File

@ -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')) "+
@ -1856,7 +1856,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')) "+

View File

@ -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: ['<span class="c_red">'],
post_tags: ['</span>'],
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: ['<span class="c_red">'],
post_tags: ['</span>'],
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: ['<span class="c_red">'],
post_tags: ['</span>'],
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

View File

@ -1869,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

View File

@ -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: 1 } 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: ['<span class="c_red">'],
post_tags: ['</span>'],
fields: {
filename: {}
}
}
}
)
end
# add by nwb
# 公开的项目id列表
def self.public_project_id
@ -561,4 +601,46 @@ class Attachment < ActiveRecord::Base
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

View File

@ -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

View File

@ -31,7 +31,7 @@ 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'
@ -81,8 +81,10 @@ class Comment < ActiveRecord::Base
# 课程成员得分(英雄榜)
def act_as_student_score
unless self.author.allowed_to?(:as_teacher, self.commented.course)
course_member_score(self.commented.course.id, self.author_id, "NewReply")
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

View File

@ -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: 1 } 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
@ -56,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',
@ -100,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: ['<span class="c_red">'],
post_tags: ['</span>'],
fields: {
name: {},
description: {}
}
}
}
)
end
def visible?(user=User.current)
user.allowed_to?(:view_course, self)
@ -344,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

View File

@ -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

View File

@ -2,6 +2,7 @@ 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 #该测试被哪些用户提交答案过

View File

@ -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'

View File

@ -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

View File

@ -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
@ -287,13 +287,15 @@ class Message < ActiveRecord::Base
# 课程成员得分(英雄榜)
def act_as_student_score
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")
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

View File

@ -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

View File

@ -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: 1 } 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: ['<span class="c_red">'],
post_tags: ['</span>'],
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

View File

@ -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

View File

@ -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: 1 } 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],
@ -162,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'
@ -222,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
@ -240,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)
@ -258,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: ['<span class="c_red">'],
post_tags: ['</span>'],
fields: {
login: {},
firstname: {},
lastname: {}
}
}
}
)
end
# ======================================================================
@ -1119,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
@ -1153,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

View File

@ -20,7 +20,7 @@
<a class="btn_submit c_white" data-button="ok" onclick="pollsSubmit($(this));">
保存
</a>
<a class="btn_cancel" data-button="cancel" onclick="resetHead();pollsCancel();">
<a class="btn_cancel" data-button="cancel" onclick="pollsCancel();">
<%= l(:button_cancel)%>
</a>
</div>
@ -35,6 +35,6 @@
$("#exercise_time").val("<%=exercise.time if exercise.time!= -1 %>");
$("#exercise_publish_time").val("<%= Time.parse(format_time(exercise.publish_time)).strftime("%Y-%m-%d") if !exercise.publish_time.nil?%>");
/*$("#exercise_description").text("<%#=exercise.exercise_description.html_safe %>");*/
document.getElementById("exercise_description").innerText = <%=exercise.exercise_description.html_safe %>;
document.getElementById("exercise_description").innerHTML = <%=exercise.exercise_description.html_safe %>;
}
</script>

View File

@ -7,5 +7,5 @@
remote: data-remote
-%>
<%= link_to_unless current_page.last?, t('views.pagination.last').html_safe, url, :remote => remote %>
<%= link_to_unless false, t('views.pagination.last').html_safe, url, :remote => remote %>

View File

@ -8,8 +8,7 @@
-%>
<%= paginator.render do -%>
<ul id="paginator" class="wlist">
<%#= first_page_tag unless current_page.first? %>
<%= prev_page_tag unless current_page.first? %>
<%= prev_page_tag %>
<% each_page do |page| -%>
<% if page.left_outer? || page.right_outer? || page.inside_window? -%>
<%= page_tag page %>
@ -17,7 +16,7 @@
<%= gap_tag %>
<% end -%>
<% end -%>
<%= next_page_tag unless current_page.last? %>
<%= next_page_tag %>
<!--<%#= last_page_tag unless current_page.last? %>-->
</ul>
<% end -%>

View File

@ -7,6 +7,6 @@
remote: data-remote
-%>
<li >
<%= link_to_unless current_page.first?, t('views.pagination.previous').html_safe, url, :rel => 'prev', :remote => remote ,:class=>"previous c_blue"%>
<%= link_to_unless false, t('views.pagination.previous').html_safe, url, :rel => 'prev', :remote => remote ,:class=>"previous c_blue"%>
</li>

View File

@ -18,24 +18,24 @@
</ul>
</div>
<script>
<% type = type%>
$(function (){
if('<%= type %>' != null && '<%= type %>' == 'courses' ){
$('input:radio[value="courses"]').attr('checked','checked');
}
if('<%= type %>' != null && '<%= type %>' == 'projects' ){
$('input:radio[value="projects"]').attr('checked','checked');
}
if('<%= type %>' != null && '<%= type %>' == 'users' ){
$('input:radio[value="users"]').attr('checked','checked');
}
});
<%# type = type%>
// $(function (){
// if('<%#= type %>' != null && '<%#= type %>' == 'courses' ){
// $('input:radio[value="courses"]').attr('checked','checked');
// }
// if('<%#= type %>' != null && '<%#= type %>' == 'projects' ){
// $('input:radio[value="projects"]').attr('checked','checked');
// }
// if('<%#= type %>' != null && '<%#= type %>' == 'users' ){
// $('input:radio[value="users"]').attr('checked','checked');
// }
// });
$(function(){
$("#navHomepageSearchInput").keypress(function(e){
var name = $.trim($('#navHomepageSearchInput').val());
if (e.keyCode == '13' && name != "" && name.length != 0) {
$('#type').val($('input[type=radio]:checked').val());
//$('#type').val($('input[type=radio]:checked').val());
$(this).parent().submit();
}
})
@ -44,7 +44,7 @@
function search_in_header(obj){
var name = $.trim($('#navHomepageSearchInput').val());
if (name != "" && name.length != 0) {
$('#type').val($('input[type=radio]:checked').val());
//$('#type').val($('input[type=radio]:checked').val());
obj.parent().submit();
}
}
@ -54,28 +54,28 @@
<% name = name%>
<%= form_tag({controller: :welcome, action: :search },:class=>'navHomepageSearchBox', method: :get) do %>
<input type="text" name="q" value="<%= name.nil? ? "" : name%>" id="navHomepageSearchInput" class="navHomepageSearchInput" placeholder="请输入关键词进行搜索"/>
<input type="hidden" name="search_type" id="type" value=""/>
<input type="text" name="q" value="<%= name.nil? ? "" : name%>" id="navHomepageSearchInput" class="navHomepageSearchInput" placeholder="请输入关键词搜索公开的课程、项目、用户以及资源"/>
<input type="hidden" name="search_type" id="type" value="all"/>
<input type="text" style="display: none;"/>
<a href="javascript:void(0);" class="homepageSearchIcon" onclick="search_in_header($(this));"></a>
<% end %>
<div class="navSearchTypeBox" id="navHomepageSearchType">
<div class="fl mr15 mt8">
<input type="radio" value="courses" name="search_type" checked/>
课程
</div>
<div class="fl mr15 mt8">
<input type="radio" value="projects" name="search_type" />
项目
</div>
<div class="fl mr15 mt8">
<input type="radio" value="users" name="search_type" />
用户
</div>
<div id="navSearchAlert" class="fr mr10">
<span class="c_red">请选择搜索类型</span>
</div>
</div>
<!--<div class="navSearchTypeBox" id="navHomepageSearchType">-->
<!--<div class="fl mr15 mt8">-->
<!--<input type="radio" value="courses" name="search_type" checked/>-->
<!--课程-->
<!--</div>-->
<!--<div class="fl mr15 mt8">-->
<!--<input type="radio" value="projects" name="search_type" />-->
<!--项目-->
<!--</div>-->
<!--<div class="fl mr15 mt8">-->
<!--<input type="radio" value="users" name="search_type" />-->
<!--用户-->
<!--</div>-->
<!--<div id="navSearchAlert" class="fr mr10">-->
<!--<span class="c_red">请选择搜索类型</span>-->
<!--</div>-->
<!--</div>-->
</div>
<div class="navHomepageProfile" id="navHomepageProfile">

View File

@ -18,23 +18,23 @@
// alert(3)
$(doc).parent().submit();
}
<% type = type%>
$(function (){
if('<%= type %>' != null && '<%= type %>' == 'courses' ){
$('input:radio[value="courses"]').attr('checked','checked');
}
if('<%= type %>' != null && '<%= type %>' == 'projects' ){
$('input:radio[value="projects"]').attr('checked','checked');
}
if('<%= type %>' != null && '<%= type %>' == 'users' ){
$('input:radio[value="users"]').attr('checked','checked');
}
});
<!--<%# type = type%>-->
// $(function (){
// if('<%#= type %>' != null && '<%#= type %>' == 'courses' ){
// $('input:radio[value="courses"]').attr('checked','checked');
// }
// if('<%#= type %>' != null && '<%#= type %>' == 'projects' ){
// $('input:radio[value="projects"]').attr('checked','checked');
// }
// if('<%#= type %>' != null && '<%#= type %>' == 'users' ){
// $('input:radio[value="users"]').attr('checked','checked');
// }
// });
function search_in_header(obj){
var name = $.trim($('#navHomepageSearchInput').val());
if (name != "" && name.length != 0) {
$('#type').val($('input[type=radio]:checked').val());
//$('#type').val($('input[type=radio]:checked').val());
obj.parent().submit();
}
}
@ -42,7 +42,7 @@
function search_in_header_I(e,obj){
var name = $.trim($('#navHomepageSearchInput').val());
if (e.keyCode == '13' && name != "" && name.length != 0) {
$('#type').val($('input[type=radio]:checked').val());
//$('#type').val($('input[type=radio]:checked').val());
obj.parent().submit();
}
}
@ -52,28 +52,28 @@
<% name = name%>
<%= form_tag({controller: :welcome, action: :search },:class=>'navHomepageSearchBox', method: :get) do %>
<input type="text" name="q" value="<%= name.nil? ? "" : name%>" id="navHomepageSearchInput" class="navHomepageSearchInput" placeholder="请输入关键词进行搜索" onkeypress="search_in_header_I(event,$(this));"/>
<input type="hidden" name="search_type" id="type" value=""/>
<input type="text" name="q" value="<%= name.nil? ? "" : name%>" id="navHomepageSearchInput" class="navHomepageSearchInput" placeholder="请输入关键词搜索公开的课程、项目、用户以及资源" onkeypress="search_in_header_I(event,$(this));"/>
<input type="hidden" name="search_type" id="type" value="all"/>
<input type="text" style="display: none;"/>
<a href="javascript:void(0);" class="homepageSearchIcon" onclick="search_in_header($(this));"></a>
<% end %>
<div class="navSearchTypeBox" id="navHomepageSearchType">
<div class="fl mr15 mt8">
<input type="radio" value="courses" name="search_type" checked/>
课程
</div>
<div class="fl mr15 mt8">
<input type="radio" value="projects" name="search_type" />
项目
</div>
<div class="fl mr15 mt8">
<input type="radio" value="users" name="search_type" />
用户
</div>
<div id="navSearchAlert" class="fr mr10">
<span class="c_red">请选择搜索类型</span>
</div>
</div>
<!--<div class="navSearchTypeBox" id="navHomepageSearchType">-->
<!--<div class="fl mr15 mt8">-->
<!--<input type="radio" value="courses" name="search_type" checked/>-->
<!--课程-->
<!--</div>-->
<!--<div class="fl mr15 mt8">-->
<!--<input type="radio" value="projects" name="search_type" />-->
<!--项目-->
<!--</div>-->
<!--<div class="fl mr15 mt8">-->
<!--<input type="radio" value="users" name="search_type" />-->
<!--用户-->
<!--</div>-->
<!--<div id="navSearchAlert" class="fr mr10">-->
<!--<span class="c_red">请选择搜索类型</span>-->
<!--</div>-->
<!--</div>-->
</div>
<div id="loginInButton" class="fr ml20">

View File

@ -212,7 +212,7 @@
<% contributor_course_scor(@course.id).each do |contributor_score| %>
<% unless contributor_score.total_score ==0 %>
<li> <a href="javascript:void:(0);"><%=link_to image_tag(url_to_avatar(contributor_score.user), :width => "35", :height => "35", :class=> "rankPortrait"),user_path(contributor_score.user) %></a>
<p><a href="javascript:void:(0);"><%=link_to contributor_score.user, user_path(contributor_score.user), :title => contributor_score.user %></a></p>
<p><a href="javascript:void:(0);"><%=link_to contributor_score.user.show_name, user_path(contributor_score.user), :title => contributor_score.user.show_name %></a></p>
<p><span class="c_green" style="cursor:pointer">
<a onmouseover ="message_titile_show($(this),event)" onmouseout ="message_titile_hide($(this))" class="c_green"><%= contributor_score.total_score.to_i %></a></span></p>
<div style="display: none" class="numIntro">
@ -246,7 +246,7 @@
<% hero_homework_scores.each do |student_score| %>
<% if student_score.score.to_i != 0 %>
<li> <a href="javascript:void:(0);"><%=link_to image_tag(url_to_avatar(student_score.user), :width => "35", :height => "35", :class=> "rankPortrait"),user_path(student_score.user) %></a>
<p><a href="javascript:void:(0);"><%=link_to student_score.user, user_path(student_score.user), :title => student_score.user %></a></p>
<p><a href="javascript:void:(0);"><%=link_to student_score.user.show_name, user_path(student_score.user), :title => student_score.user.show_name %></a></p>
<p><span class="c_red" style="cursor:pointer" title="作业总分:<%= student_score.score %>"><%= student_score.score.to_i %></span></p>
</li>
<% end %>

View File

@ -1,7 +1,7 @@
<%= form_tag( url_for(:controller => 'users',:action => 'resource_search',:id=>user.id),
:remote=>true ,:method => 'get',:class=>'resourcesSearchloadBox',:id=>'resource_search_form') do %>
<input type="text" name="search" placeholder="输入资源关键词进行搜索" class="searchResource" />
<%= hidden_field_tag(:type,type) %>
<%= hidden_field_tag(:type,type.nil? ? 1 : type) %>
<%= submit_tag '',:class=>'homepageSearchIcon',:onfocus=>'this.blur();',:style=>'border-style:none' %>
<!--<a href="javascript:void(0);" onclick='this.parent.submit();return false;' class="searchIcon"></a>-->
<% end %>

View File

@ -5,7 +5,7 @@
<!--</p>-->
<% else %>
<% attachments.each do |attach| %>
<ul class="resourcesList" onmouseover="$(this).children().css('background-color', '#e1e1e1')" onmouseout="$(this).children().css('background-color', 'white')">
<ul class="resourcesList" onmouseover="if($('#contextMenu').css('display') != 'block')$(this).children().css('background-color', '#e1e1e1')" onmouseout=" if($('#contextMenu').css('display') == 'none')$(this).children().css('background-color', 'white')">
<li class="resourcesListCheckbox fl">
<input name="checkbox1[]" type="checkbox" data-deleteble="<%= User.current.id ==attach.author_id ? 'Y' : 'N' %>" onclick="checkAllBox($(this));" value="<%= attach.id%>" class="resourcesCheckbox" />
</li>

View File

@ -480,54 +480,5 @@
lastSendType = sendType;
}
// var iWidth = document.documentElement.clientWidth;
// var iHeight = document.documentElement.clientHeight;
// var moveX = 0;
// var moveY = 0;
// var moveTop = 0;
// var moveLeft = 0;
// var moveable = false;
// var docMouseMoveEvent = document.onmousemove;
// var docMouseUpEvent = document.onmouseup;
// $("#upload_box").mousedown(function() {
// var evt = getEvent();
// moveable = true;
// moveX = evt.clientX;
// moveY = evt.clientY;
//
// moveTop = parseInt($("#upload_box").css('top'));
// moveLeft = parseInt($("#upload_box").css('left'));
//
// $(document).mousemove( function() {
// if (moveable) {
// var evt = getEvent();
// var x = moveLeft + evt.clientX - moveX;
// var y = moveTop + evt.clientY - moveY;
// if ( x > 0 &&( x + 322 < iWidth) && y > 0 && (y + 257 < iHeight) ) {
// $("#upload_box").css('left', x + "px");
// $("#upload_box").css('top', y + "px");
// console.log( moveX)
// console.log( moveY)
// }
// }
// });
// $(document).mouseup (function () {
// if (moveable) {
// document.onmousemove = docMouseMoveEvent;
// document.onmouseup = docMouseUpEvent;
// moveable = false;
// moveX = 0;
// moveY = 0;
// moveTop = 0;
// moveLeft = 0;
// }
// });
// });
//
// // 获得事件Event对象用于兼容IE和FireFox
// function getEvent() {
// return window.event || arguments.callee.caller.arguments[0];
// }
</script>

View File

@ -0,0 +1,80 @@
<% unless all_results.nil? || all_results.empty?%>
<% all_results.each do |item|%>
<% case item.type %>
<% when 'user'%>
<ul class="searchContent">
<li class="fl"></li>
<li class="fl searchContentDes">
<ul class="fl">
<li class="f16 mb5"><a href="<%= user_path(item.id)%>" class="fontGrey3 fl">
<%= item.try(:highlight).try(:login) ? item.highlight.login[0].html_safe : item.login %>
<%if item.firstname.present? || item.lastname.present?%>
(<%= item.try(:highlight).try(:lastname) ? item.highlight.lastname[0].html_safe : item.lastname%>
<%= item.try(:highlight).try(:firstname) ? item.highlight.firstname[0].html_safe : item.firstname %>)
<%end %>
</a>
<div class="mt5 fl"><%= image_tag("search_icon_03.png", :width=>"8", :height=>"16" ,:class=>"fl") %><span class="searchTag"><%= get_user_identity(User.find(item.id).user_extensions.identity) %></span></div>
<div class="cl"></div>
</li>
<li class="fontGrey3 mb5"><%= User.find(item.id).user_extensions && User.find(item.id).user_extensions.brief_introduction.present? ? User.find(item.id).user_extensions.brief_introduction : '这位童鞋很懒,什么也没有留下~'%></li>
<li class="f12 fontGrey2"><span class="mr30">加入时间:<%= format_date( User.find(item.id).created_on)%></span><span class="mr30"><%= User.find(item.id).user_extensions.occupation.present? ? '单位:'+User.find(item.id).user_extensions.occupation : ''%></span></li>
</ul>
</li>
<div class="cl"></div>
</ul>
<% when 'course'%>
<ul class="searchContent">
<li class="fl">
</li>
<li class="fl searchContentDes">
<ul class="fl">
<li class="f16 mb5">
<a href="<%= course_path(item.id)%>" class="fontGrey3 fl"><%= item.try(:highlight).try(:name) ? item.highlight.name[0].html_safe : item.name %></a>
<div class="mt5 fl"><%= image_tag("search_icon_03.png", :width=>"8", :height=>"16" ,:class=>"fl") %><span class="searchTag">课程</span></div>
<div class="cl"></div>
</li>
<li class="fontGrey3 mb5"><%= item.try(:highlight).try(:description) ? item.highlight.description[0].html_safe : item.description %></li>
<li class="f12 fontGrey2"><span class="mr30">教师:<%= User.find(item.tea_id).realname %></span><span class="mr30">授课时间:<%= item.time.to_s + item.term%></span><span class="mr30"><%= User.find(item.tea_id).user_extensions.occupation.present? ? '单位:'+User.find(item.tea_id).user_extensions.occupation : ''%></span></li>
</ul>
</li>
<div class="cl"></div>
</ul>
<% when 'attachment'%>
<ul class="searchContent">
<li class="fl">
</li>
<li class="fl searchContentDes">
<ul class="fl">
<li class="f16 mb5 fontGrey3"><a href="<%= download_named_attachment_path(item.id,item.filename)%>" class="fontGrey3 mr10 fl"><%= item.try(:highlight).try(:filename) ? item.highlight.filename[0].html_safe : item.filename %></a><span class="f12 fl" style="padding-top: 5px">(<%= number_to_human_size(item.filesize)%>)</span>
<div class="mt5 fl"><%= image_tag("search_icon_03.png", :width=>"8", :height=>"16" ,:class=>"fl") %><span class="searchTag">资源</span></div>
<div class="cl"></div>
</li>
<li class="f12 fontGrey2"><span class="mr30">发布者:<%= User.find(item.author_id).login%><%= User.find(item.author_id).realname%></span>
<!--<span class="mr30">职称:<%#= get_technical_title User.find(item.author_id) %></span>-->
<span class="mr30">发布时间:<%= format_date(item.created_on)%></span></li>
</ul>
</li>
<div class="cl"></div>
</ul>
<% when 'project'%>
<ul class="searchContent">
<li class="fl">
</li>
<li class="fl searchContentDes">
<ul class="fl">
<li class="f16 mb5"><a href="<%= project_path(item.id)%>" class="fontGrey3 fl"><%= item.try(:highlight).try(:name) ? item.highlight.name[0].html_safe : item.name %></a>
<div class="mt5 fl"><%= image_tag("search_icon_03.png", :width=>"8", :height=>"16" ,:class=>"fl") %><span class="searchTag">项目</span></div>
<div class="cl"></div>
</li>
<li class="fontGrey3 mb5"><%= item.try(:highlight).try(:description) ? item.highlight.description[0].html_safe : item.description%></li>
<li class="f12 fontGrey2"><span class="mr30">管理人员:<%= item.user_id ? User.find(item.user_id).login : '无' %></span><span class="mr30">创建时间:<%= date_format_local( Project.find(item.id).created_on) %></span></li>
</ul>
</li>
<div class="cl"></div>
</ul>
<%end %>
<% end %>
<div class="pageRoll">
<%= paginate all_results,:params => {:controller => 'welcome', :action => 'search',:search_type=>'all'}%>
</div>
<% end %>

View File

@ -0,0 +1,24 @@
<% unless attachments.nil? || attachments.empty?%>
<% attachments.each do |attachment|%>
<ul class="searchContent">
<li class="fl">
</li>
<li class="fl searchContentDes">
<ul class="fl">
<li class="f16 mb5 fontGrey3">
<a href="<%= download_named_attachment_path(attachment.id,attachment.filename)%>" class="fontGrey3 mr10 fl"><%= attachment.try(:highlight).try(:filename) ? attachment.highlight.filename[0].html_safe : attachment.filename %></a><span class="f12 fl" style="padding-top: 5px">(<%= number_to_human_size(attachment.filesize)%>)</span>
<div class="mt5 fl"><%= image_tag("search_icon_03.png", :width=>"8", :height=>"16" ,:class=>"fl") %><span class="searchTag">资源</span></div>
<div class="cl"></div>
</li>
<li class="f12 fontGrey2"><span class="mr30">发布者:<%= User.find(attachment.author_id).login%><%= User.find(attachment.author_id).realname%></span>
<!--<span class="mr30">职称:<%#= get_technical_title User.find(attachment.author_id) %></span>-->
<span class="mr30">发布时间:<%= format_date(attachment.created_on)%></span></li>
</ul>
</li>
<div class="cl"></div>
</ul>
<% end %>
<div class="pageRoll">
<%= paginate attachments,:params => {:controller => 'welcome', :action => 'search',:search_type=>'attachment'}%>
</div>
<% end %>

View File

@ -0,0 +1,24 @@
<% unless courses.nil? || courses.empty?%>
<% courses.each do |course|%>
<ul class="searchContent">
<li class="fl">
<%= link_to image_tag(url_to_avatar(Course.find(course.id)), :width => "75", :height => "75",:class=>'searchCourseImage'), course_path(course.id), :alt => "课程图片" %>
</li>
<li class="fl searchContentDes">
<ul class="fl">
<li class="f16 mb5">
<a href="<%= course_path(course.id)%>" class="fontGrey3 fl"><%= course.try(:highlight).try(:name) ? course.highlight.name[0].html_safe : course.name %></a>
<div class="mt5 fl"><%= image_tag("search_icon_03.png", :width=>"8", :height=>"16" ,:class=>"fl") %><span class="searchTag">课程</span></div>
<div class="cl"></div>
</li>
<li class="fontGrey3 mb5"><%= course.try(:highlight).try(:description) ? course.highlight.description[0].html_safe : (course.description.present? ? course.description : '暂时没有该课程描述') %></li>
<li class="f12 fontGrey2"><span class="mr30">教师:<%= User.find(course.tea_id).realname %></span><span class="mr30">授课时间:<%= course.time.to_s + course.term%></span><span class="mr30"><%= User.find(course.tea_id).user_extensions.occupation.present? ? '单位:'+User.find(course.tea_id).user_extensions.occupation : ''%></span></li>
</ul>
</li>
<div class="cl"></div>
</ul>
<% end %>
<div class="pageRoll">
<%= paginate courses,:params => {:controller => 'welcome', :action => 'search',:search_type=>'course'}%>
</div>
<% end %>

View File

@ -0,0 +1,24 @@
<% unless projects.nil? || projects.empty?%>
<% projects.each do |project|%>
<ul class="searchContent">
<li class="fl">
<!--<img src="images/homepageImage.jpg" alt="个人图片" width="75" height="75" class="searchCourseImage" />-->
<%= link_to image_tag(url_to_avatar(Project.find(project.id)), :width => "75", :height => "75",:class=>'searchCourseImage'), project_path(project.id), :alt => "项目图片" %>
</li>
<li class="fl searchContentDes">
<ul class="fl">
<li class="f16 mb5"><a href="<%= project_path(project.id)%>" class="fontGrey3 fl"><%= project.try(:highlight).try(:name) ? project.highlight.name[0].html_safe : project.name %></a>
<div class="mt5 fl"><%= image_tag("search_icon_03.png", :width=>"8", :height=>"16" ,:class=>"fl") %><span class="searchTag">项目</span></div>
<div class="cl"></div>
</li>
<li class="fontGrey3 mb5"><%= project.try(:highlight).try(:description) ? project.highlight.description[0].html_safe : project.description%></li>
<li class="f12 fontGrey2"><span class="mr30">管理人员:<%= project.user_id ? User.find(project.user_id).login : '无' %></span><span class="mr30">创建时间:<%= date_format_local( Project.find(project.id).created_on) %></span></li>
</ul>
</li>
<div class="cl"></div>
</ul>
<% end %>
<div class="pageRoll">
<%= paginate projects,:params => {:controller => 'welcome', :action => 'search',:search_type=>'project'}%>
</div>
<% end %>

View File

@ -0,0 +1,24 @@
<% unless users.nil? || users.empty?%>
<% users.each do |user|%>
<ul class="searchContent">
<li class="fl">
<!--<img src="images/homepageImage.jpg" alt="个人图片" width="75" height="75" class="searchCourseImage" />-->
<%= link_to image_tag(url_to_avatar(User.find(user.id)), :width => "75", :height => "75",:class=>'searchCourseImage'), user_path(user.id), :alt => "用户头像" %>
</li>
<li class="fl searchContentDes">
<ul class="fl">
<li class="f16 mb5"><a href="<%= user_path(user.id)%>" class="fontGrey3 fl"><%= user.try(:highlight).try(:login) ? user.highlight.login[0].html_safe : user.login %>(<%= user.try(:highlight).try(:lastname) ? user.highlight.lastname[0].html_safe : user.lastname%><%= user.try(:highlight).try(:firstname) ? user.highlight.firstname[0].html_safe : user.firstname %>)</a>
<div class="mt5 fl"><%= image_tag("search_icon_03.png", :width=>"8", :height=>"16" ,:class=>"fl") %><span class="searchTag"><%= get_user_identity(User.find(user.id).user_extensions.identity) %></span></div>
<div class="cl"></div>
</li>
<li class="fontGrey3 mb5"><%= User.find(user.id).user_extensions && User.find(user.id).user_extensions.brief_introduction.present? ? User.find(user.id).user_extensions.brief_introduction : '这位童鞋很懒,什么也没有留下~'%></li>
<li class="f12 fontGrey2"><span class="mr30">加入时间:<%= format_date( User.find(user.id).created_on)%></span><span class="mr30"><%= User.find(user.id).user_extensions.occupation.present? ? '单位:'+User.find(user.id).user_extensions.occupation : ''%></span></li>
</ul>
</li>
<div class="cl"></div>
</ul>
<% end %>
<div class="pageRoll">
<%= paginate users,:params => {:controller => 'welcome', :action => 'search',:search_type=>'user'}%>
</div>
<% end %>

View File

@ -0,0 +1,100 @@
<script type="text/javascript" language="javascript">
//搜索列表
function g(o){return document.getElementById(o);}
function HoverLi(n){
//如果有N个标签,就将i<=N;
for(var i=1;i<=5;i++){
g('searchBaner_'+i).className='searchBannerNormal';
g('searchContent_'+i).className='undis';g('searchNum_'+i).className="numRed";
g('searchType_'+i).className="fontGrey2 f14";
}
g('searchContent_'+n).className='dis';
g('searchBaner_'+n).className='searchBannerActive';
g('searchNum_'+n).className="c_red";
g('searchType_'+n).className="fontGrey3 f14";
}
function on_click_search(n){
if(n == 1){
search('all')
//$("#searchContent_1").html('<%#= escape_javascript(render :partial => 'search_all_results',:locals => {:alls=> @results})%>');
}else if( n == 2){
//$("#searchContent_2").html('<%#= escape_javascript(render :partial => 'search_user_results',:locals => {:users=>@users})%>');
search('user')
}else if(n == 3){
search('course')
}else if(n == 4){
search('attachment')
}else if(n == 5){
search('project')
}
}
function search(type){
$.ajax({
url:'<%= url_for(:controller => 'welcome',:action=>'search')%>' +'?q=<%= @name %>&search_type='+type,
type:'get',
success:function(data){
}
})
}
$(function(){
if('<%= @search_type%>' == 'all'){
HoverLi(1)
$("#searchContent_1").html('<%= escape_javascript(render :partial => 'search_all_results',:locals => {:all_results=> @alls})%>');
}else if('<%= @search_type%>' == 'user'){
HoverLi(2)
$("#searchContent_2").html('<%= escape_javascript(render :partial => 'search_user_results',:locals => {:users=>@users})%>');
}else if('<%= @search_type%>' == 'course'){
HoverLi(3)
$("#searchContent_3").html('<%= escape_javascript(render :partial => 'search_course_results',:locals => {:courses=>@courses})%>');
}else if('<%= @search_type%>' == 'attachment'){
HoverLi(4)
$("#searchContent_4").html('<%= escape_javascript(render :partial => 'search_attachment_results',:locals => {:attachments=>@attachments})%>');
}else if('<%= @search_type%>' == 'project'){
HoverLi(5)
$("#searchContent_5").html('<%= escape_javascript(render :partial => 'search_project_results',:locals => {:projects=>@projects})%>');
}
})
//如果要做成点击后再转到请将<li>中的onmouseover 改成 onclick;
//]]>
</script>
<script>
//搜索内容自动撑高到整屏
var h1 = $(window).height();
var h2 = $(".homepageContentContainer").height();
</script>
<div class="homepageContentContainer">
<div class="homepageContent">
<div class="blocks mt10 mb10">
<ul id="searchBanner">
<li id="searchBaner_1" class="searchBannerActive" onclick="HoverLi(1);on_click_search(1);"><a href="javascript:void(0);" id="searchType_1" class="fontGrey3 f14">全部<span style="font-weight:normal;"><font id="searchNum_1" class="c_red">(<%= @total_count%>)</font></span></a></li>
<li id="searchBaner_2" onclick="HoverLi(2);on_click_search(2);"><a href="javascript:void(0);" id="searchType_2" class="fontGrey2 f14">用户<span class="numRed" style="font-weight:normal;"><font id="searchNum_2" class="numRed">(<%= @users_count%>)</font></span></a></li>
<li id="searchBaner_3" onclick="HoverLi(3);on_click_search(3);"><a href="javascript:void(0);" id="searchType_3" class="fontGrey2 f14">课程<span style="font-weight:normal;"><font id="searchNum_3" class="numRed">(<%=@course_count%>)</font></span></a></li>
<li id="searchBaner_4" onclick="HoverLi(4);on_click_search(4);"><a href="javascript:void(0);" id="searchType_4" class="fontGrey2 f14">资源<span class="numRed" style="font-weight:normal;"><font id="searchNum_4" class="numRed">(<%= @attach_count%>)</font></span></a></li>
<li id="searchBaner_5" onclick="HoverLi(5);on_click_search(5);"><a href="javascript:void(0);" id="searchType_5" class="fontGrey2 f14">项目<span class="numRed" style="font-weight:normal;"><font id="searchNum_5" class="numRed">(<%= @project_count%>)</font></span></a></li>
<div class="cl"></div>
</ul>
<ul id="searchTips" style="display:none;">
<span class="fontGrey3">没有搜索到相关的内容!</span>
</ul>
<div id="searchContent_1">
</div>
<div id="searchContent_2" class="undis">
<%#= render :partial => 'search_user_results',:locals => {:users=>@users}%>
</div>
<div id="searchContent_3" class="undis">
</div>
<div id="searchContent_4" class="undis">
</div>
<div id="searchContent_5" class="undis">
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,13 @@
<% case @search_type%>
<% when 'all'%>
$("#searchContent_1").html('<%= escape_javascript(render :partial => 'search_all_results',:locals => {:all_results=> @alls})%>');
<% when 'user'%>
$("#searchContent_2").html('<%= escape_javascript(render :partial => 'search_user_results',:locals => {:users=>@users})%>');
<% when 'course'%>
$("#searchContent_3").html('<%= escape_javascript(render :partial => 'search_course_results',:locals => {:courses=>@courses})%>');
<% when 'project'%>
$("#searchContent_5").html('<%= escape_javascript(render :partial => 'search_project_results',:locals => {:projects=>@projects})%>');
<% when 'attachment'%>
$("#searchContent_4").html('<%= escape_javascript(render :partial => 'search_attachment_results',:locals => {:attachments=>@attachments})%>');
<%else%>
<%end %>

View File

@ -2,7 +2,7 @@ require File.expand_path('../boot', __FILE__)
require 'rails/all'
require 'sprockets/railtie'
require 'elasticsearch/model'
if defined?(Bundler)
# If you precompile assets before deploying to production, use this line
Bundler.require(*Rails.groups(:assets => %w(development test)))
@ -73,6 +73,17 @@ module RedmineApp
end
config.after_initialize do
if RbConfig::CONFIG['target_os'] == 'mingw32'
Elasticsearch::Client.new hosts: ['localhost:9200'], retry_on_failure: true,log:true
elsif RbConfig::CONFIG['target_os'] == 'linux' && ["fast76"].include?(`hostname`.gsub("\n",""))
Elasticsearch::Client.new hosts: ['localhost:9200'], retry_on_failure: true,log:true
elsif RbConfig::CONFIG['target_os'] == 'linux' && ["testtrustie11","agent12"].include?(`hostname`.gsub("\n",""))
Elasticsearch::Client.new hosts: ['localhost:9200','192.168.80.11:9200','192.168.80.12:9200'], retry_on_failure: true
elsif RbConfig::CONFIG['target_os'] == 'linux' && ["trustie168","trustieserver14","trustieserver16","Trustie18"].include?(`hostname`.gsub("\n",""))
Elasticsearch::Client.new hosts: ['localhost:9200','192.168.80.168:9200','192.168.80.14:9200','192.168.80.16:9200','192.168.80.18:9200'], retry_on_failure: true
else
Elasticsearch::Client.new hosts: ['localhost:9200'], retry_on_failure: true
end
end
if File.exists?(File.join(File.dirname(__FILE__), 'additional_environment.rb'))

View File

@ -23,10 +23,10 @@
Kaminari.configure do |config|
# config.default_per_page = 25
# config.max_per_page = nil
config.window = 0
config.window = 1
# config.outer_window = 3
# config.left = 2
# config.right = 2
config.left = 2
config.right = 2
# config.page_method_name = :page
# config.param_name = :page
end

View File

@ -104,7 +104,7 @@ RedmineApp::Application.routes.draw do
resources :homework_users
resources :no_uses
delete 'no_uses', :to => 'no_uses#delete'
match 'site_search', :to => 'users#site_search', :as => 'site_search', :via => [:get, :post, :put]
resources :apply_project_masters
delete 'apply_project_masters', :to => 'apply_project_masters#delete'
@ -497,6 +497,11 @@ RedmineApp::Application.routes.draw do
end
end
end
resources :blog_comments do
collection do
get :search
end
end
match 'users/:id/user_newfeedback', :to => 'users#user_newfeedback', :via => :get, :as => "feedback"
match 'users/:id/user_projects', :to => 'users#user_projects', :via => :get
#消息

View File

@ -0,0 +1,5 @@
class AddIndexToHomeworkCommons < ActiveRecord::Migration
def change
add_index :homework_commons, [:course_id, :id]
end
end

View File

@ -0,0 +1,5 @@
class AddIndexToStudentWorks < ActiveRecord::Migration
def change
add_index :student_works, [:homework_common_id, :user_id]
end
end

View File

@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20151127011351) do
ActiveRecord::Schema.define(:version => 20151130033906) do
create_table "activities", :force => true do |t|
t.integer "act_id", :null => false
@ -543,26 +543,23 @@ ActiveRecord::Schema.define(:version => 20151127011351) do
add_index "documents", ["created_on"], :name => "index_documents_on_created_on"
add_index "documents", ["project_id"], :name => "documents_project_id"
create_table "dts", :primary_key => "Num", :force => true do |t|
t.string "Defect", :limit => 50
t.string "Category", :limit => 50
t.string "File"
t.string "Method"
t.string "Module", :limit => 20
t.string "Variable", :limit => 50
t.integer "StartLine"
t.integer "IPLine"
t.string "IPLineCode", :limit => 200
t.string "Judge", :limit => 15
t.integer "Review", :limit => 1
create_table "dts", :force => true do |t|
t.string "IPLineCode"
t.string "Description"
t.text "PreConditions", :limit => 2147483647
t.text "TraceInfo", :limit => 2147483647
t.text "Code", :limit => 2147483647
t.string "Num"
t.string "Variable"
t.string "TraceInfo"
t.string "Method"
t.string "File"
t.string "IPLine"
t.string "Review"
t.string "Category"
t.string "Defect"
t.string "PreConditions"
t.string "StartLine"
t.integer "project_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "id", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "enabled_modules", :force => true do |t|
@ -736,6 +733,8 @@ ActiveRecord::Schema.define(:version => 20151127011351) do
t.integer "anonymous_comment", :default => 0
end
add_index "homework_commons", ["course_id", "id"], :name => "index_homework_commons_on_course_id_and_id"
create_table "homework_detail_manuals", :force => true do |t|
t.float "ta_proportion"
t.integer "comment_status"
@ -892,6 +891,16 @@ ActiveRecord::Schema.define(:version => 20151127011351) do
add_index "journal_details", ["journal_id"], :name => "journal_details_journal_id"
create_table "journal_details_copy", :force => true do |t|
t.integer "journal_id", :default => 0, :null => false
t.string "property", :limit => 30, :default => "", :null => false
t.string "prop_key", :limit => 30, :default => "", :null => false
t.text "old_value"
t.text "value"
end
add_index "journal_details_copy", ["journal_id"], :name => "journal_details_journal_id"
create_table "journal_replies", :id => false, :force => true do |t|
t.integer "journal_id"
t.integer "user_id"
@ -1506,6 +1515,8 @@ ActiveRecord::Schema.define(:version => 20151127011351) do
t.boolean "is_test", :default => false
end
add_index "student_works", ["homework_common_id", "user_id"], :name => "index_student_works_on_homework_common_id_and_user_id"
create_table "student_works_evaluation_distributions", :force => true do |t|
t.integer "student_work_id"
t.integer "user_id"

View File

@ -0,0 +1 @@
require 'elasticsearch/rails/tasks/import'

View File

@ -0,0 +1,31 @@
namespace :importer do
task :importuser do
ENV['CLASS']='User'
ENV['SCOPE']='indexable'
ENV['FORCE']='y'
ENV['BATCH']='1000'
Rake::Task["elasticsearch:import:model"].invoke
end
task :importproject do
ENV['CLASS']='Project'
ENV['SCOPE']='indexable'
ENV['FORCE']='y'
ENV['BATCH']='1000'
Rake::Task["elasticsearch:import:model"].invoke
end
task :importcourse do
ENV['CLASS']='Course'
ENV['SCOPE']='indexable'
ENV['FORCE']='y'
ENV['BATCH']='1000'
Rake::Task["elasticsearch:import:model"].invoke
end
task :importattachment do
ENV['CLASS']='Attachment'
ENV['SCOPE']='indexable'
ENV['FORCE']='y'
ENV['BATCH']='1000'
Rake::Task["elasticsearch:import:model"].invoke
end
end

View File

@ -60,7 +60,7 @@ namespace :homework_evaluation do
work_ids = "(" + homework_common.student_works.map(&:id).join(",") + ")"
homework_common.student_works.each do |student_work|
absence_penalty_count = student_work.user.student_works_evaluation_distributions.where("student_work_id IN #{work_ids}").count - student_work.user.student_works_scores.where("student_work_id IN #{work_ids}").count
student_work.absence_penalty = absence_penalty_count > 0 ? absence_penalty_count * homework_detail_manuals.absence_penalty : 0
student_work.absence_penalty = absence_penalty_count > 0 ? absence_penalty_count * homework_detail_manual.absence_penalty : 0
student_work.save
end
homework_detail_manual.update_column('comment_status', 3)

View File

@ -22,7 +22,7 @@ namespace :homework_publishtime do
end
task :end => :environment do
homework_commons = HomeworkCommon.where("end_time < '#{Date.today}'")
homework_commons = HomeworkCommon.where("end_time = '#{Date.today}'")
homework_commons.each do |homework|
if homework.anonymous_comment == 1
homework_detail_manual = homework.homework_detail_manual

View File

@ -9,7 +9,7 @@ namespace :sync_rep do
if project.repositories && project.repositories.count == 1 && project.repositories.first.type == "Repository::Git"
rep = project.repositories.first
count = Repository.find_by_sql("SELECT * FROM `repositories` where identifier = '#{rep.identifier}'").count
puts count
puts project.id
unless count > 1
rep.identifier
s = Trustie::Gitlab::Sync.new

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1329,3 +1329,23 @@ a:hover.link_file_a{ background:url(../images/pic_file.png) 0 -25px no-repeat; c
span.author { font-size: 0.9em; color: #888; }
.ReplyToMessageInputContainer {width: 582px;float: left;}
/*全站搜索*/
.blocks {padding:15px; background-color:#ffffff; border:1px solid #dddddd;}
#searchBanner {border-bottom:1px solid #d0d0d0;}
#searchBanner li {float:left; width:88px; margin-right:3px; text-align:center; padding-bottom:10px; font-weight:bold;}
#searchTips {padding:10px 5px; background-color:#f5f6f7;}
.searchBannerActive {border-bottom:3px solid #3498db !important;}
.searchBannerNormal {border-bottom:none !important;}
.searchContent {min-height:74px; border-bottom:1px solid #ededed; padding:13px 0px;}
.searchCourseware {min-height:44px; border-bottom:1px solid #ededed; padding:13px 0px; width:968px;}
.searchCourseImage {width:75px; margin-right:10px;}
.searchContentDes {width:883px;}
.searchTag {font-size:12px; color:#ffffff; background-color:#7ec8e4; height:16px; min-height:16px; max-height:16px; float:left; line-height:16px; padding:0px 3px;}
.undis {display:none;}
.dis {display:inline-block;}
.numRed {color:#FF6600;}
.pageRoll {float:right; border-left:1px solid #dddddd; margin-top:15px;}
.pageCell {border:1px solid #dddddd; padding:5px 12px; float:left; margin-left:-1px; position:relative;}
.pageCell:hover {border:1px solid #3498db; z-index:10;}
.pageCellActive {background-color:#3498db; border:1px solid #3498db !important; position:relative; color:#ffffff;}