<%= link_to '['+topic.forum.name + ']',forum_path(topic.forum),:class => 'memo_Bar_title' %><%= link_to topic.subject.truncate(30, omission: '...'), topic.event_url, :class => "gray" , :style => "font-size: 10pt !important;" %>
diff --git a/app/views/welcome/course.html.erb b/app/views/welcome/course.html.erb
index 464d3af4d..f1b09cf54 100644
--- a/app/views/welcome/course.html.erb
+++ b/app/views/welcome/course.html.erb
@@ -135,7 +135,7 @@
<% find_new_forum_topics(10).each do |topic| %>
- -
+
-
From 61815af8bdbbc2658ba51026ce758954a4a48d09 Mon Sep 17 00:00:00 2001
From: alan <547533434@qq.com>
Date: Thu, 30 Oct 2014 11:24:46 +0800
Subject: [PATCH 03/18] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B8=AF=E6=BE=B3?=
=?UTF-8?q?=E5=8F=B0=E9=AB=98=E6=A0=A1=E4=BF=A1=E6=81=AF=20Signed-off-by:?=
=?UTF-8?q?=20alan=20<547533434@qq.com>?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../20141030030211_add_data_for_school.rb | 25 +++++++++++++++++++
1 file changed, 25 insertions(+)
create mode 100644 db/migrate/20141030030211_add_data_for_school.rb
diff --git a/db/migrate/20141030030211_add_data_for_school.rb b/db/migrate/20141030030211_add_data_for_school.rb
new file mode 100644
index 000000000..8ce3d88f1
--- /dev/null
+++ b/db/migrate/20141030030211_add_data_for_school.rb
@@ -0,0 +1,25 @@
+class AddDataForSchool < ActiveRecord::Migration
+ def up
+ sql = " Insert into schools (name, province, logo_link) values
+ ('香港大学','香港','/images/transparent.png'),
+ ('香港大学','香港','/images/transparent.png'),
+ ('香港中文大学','香港','/images/transparent.png'),
+ ('香港科技大学','香港','/images/transparent.png'),('香港理工大学','香港','/images/transparent.png'),
+ ('香港城市大学','香港','/images/transparent.png'),('香港浸会大学','香港','/images/transparent.png'),
+ ('香港教育学院','香港','/images/transparent.png'),('香港歌德学院','香港','/images/transparent.png'),
+ ('香港岭南大学','香港','/images/transparent.png'),('澳门大学','澳门','/images/transparent.png'),
+ ('澳门理工学院','澳门','/images/transparent.png'),('澳门科技大学','澳门','/images/transparent.png'),
+ ('澳门保安部队高等学校','澳门','/images/transparent.png'),('亚洲国际公开大学','澳门','/images/transparent.png'),
+ ('澳门旅游学院','澳门','/images/transparent.png'),('清华大学(新竹)','台湾','/images/transparent.png'),
+ ('台湾大学','台湾','/images/transparent.png'),('交通大学','台湾','/images/transparent.png'),
+ ('中央大学','台湾','/images/transparent.png'),('成功大学','台湾','/images/transparent.png'),
+ ('中山大学','台湾','/images/transparent.png'),('中原大学','台湾','/images/transparent.png'),
+ ('政治大学','台湾','/images/transparent.png'),('元智大学','台湾','/images/transparent.png'),
+ ('天主教辅仁大学','台湾','/images/transparent.png'),('台湾科技大学','台湾','/images/transparent.png'),
+ ('台湾师范大学','台湾','/images/transparent.png'),('台湾艺术大学','台湾','/images/transparent.png')"
+ execute(sql)
+ end
+
+ def down
+ end
+end
From 94a4c0037ac4df3902508f62c6c004d6e9c95c5b Mon Sep 17 00:00:00 2001
From: alan <547533434@qq.com>
Date: Thu, 30 Oct 2014 16:49:19 +0800
Subject: [PATCH 04/18] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dbug=E3=80=8A=E4=B8=AD?=
=?UTF-8?q?=E5=9B=BD=E9=AB=98=E6=A0=A1--=E5=9C=B0=E5=8C=BA=E5=88=97?=
=?UTF-8?q?=E8=A1=A8=E6=97=A0=E2=80=9C=E6=B8=AF=E2=80=9D=E3=80=81=E2=80=9C?=
=?UTF-8?q?=E6=BE=B3=E2=80=9D=E3=80=81=E2=80=9C=E5=8F=B0=E2=80=9D=20?=
=?UTF-8?q?=E5=BB=BA=E8=AE=AE=E5=A2=9E=E5=8A=A0=E3=80=8B=20Signed-off-by:?=
=?UTF-8?q?=20alan=20<547533434@qq.com>?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
...1029065917_change_bids_description_type.rb | 11 +-
... => 20141030071656_add_data_for_school.rb} | 1 +
db/schema.rb | 2612 ++++++++---------
3 files changed, 1313 insertions(+), 1311 deletions(-)
rename db/migrate/{20141030030211_add_data_for_school.rb => 20141030071656_add_data_for_school.rb} (99%)
diff --git a/db/migrate/20141029065917_change_bids_description_type.rb b/db/migrate/20141029065917_change_bids_description_type.rb
index 2705f661e..f578e9180 100644
--- a/db/migrate/20141029065917_change_bids_description_type.rb
+++ b/db/migrate/20141029065917_change_bids_description_type.rb
@@ -1,5 +1,6 @@
-class ChangeBidsDescriptionType < ActiveRecord::Migration
- def change
- change_column :bids, :description, :text, default: nil
- end
-end
+#encoding=UTF-8
+class ChangeBidsDescriptionType < ActiveRecord::Migration
+ def change
+ change_column :bids, :description, :text, default: nil
+ end
+end
diff --git a/db/migrate/20141030030211_add_data_for_school.rb b/db/migrate/20141030071656_add_data_for_school.rb
similarity index 99%
rename from db/migrate/20141030030211_add_data_for_school.rb
rename to db/migrate/20141030071656_add_data_for_school.rb
index 8ce3d88f1..71b600b16 100644
--- a/db/migrate/20141030030211_add_data_for_school.rb
+++ b/db/migrate/20141030071656_add_data_for_school.rb
@@ -1,3 +1,4 @@
+#encoding=UTF-8
class AddDataForSchool < ActiveRecord::Migration
def up
sql = " Insert into schools (name, province, logo_link) values
diff --git a/db/schema.rb b/db/schema.rb
index c837552de..ddeef8e19 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -1,1306 +1,1306 @@
-# encoding: UTF-8
-# This file is auto-generated from the current state of the database. Instead
-# of editing this file, please use the migrations feature of Active Record to
-# incrementally modify your database, and then regenerate this schema definition.
-#
-# Note that this schema.rb definition is the authoritative source for your
-# database schema. If you need to create the application database on another
-# system, you should be using db:schema:load, not running all the migrations
-# from scratch. The latter is a flawed and unsustainable approach (the more migrations
-# you'll amass, the slower it'll run and the greater likelihood for issues).
-#
-# It's strongly recommended to check this file into your version control system.
-
-ActiveRecord::Schema.define(:version => 20141029065917) do
-
- create_table "activities", :force => true do |t|
- t.integer "act_id", :null => false
- t.string "act_type", :null => false
- t.integer "user_id", :null => false
- end
-
- add_index "activities", ["act_id", "act_type"], :name => "index_activities_on_act_id_and_act_type"
- add_index "activities", ["user_id", "act_type"], :name => "index_activities_on_user_id_and_act_type"
- add_index "activities", ["user_id"], :name => "index_activities_on_user_id"
-
- create_table "applied_projects", :force => true do |t|
- t.integer "project_id", :null => false
- t.integer "user_id", :null => false
- end
-
- create_table "apply_project_masters", :force => true do |t|
- t.integer "user_id"
- t.string "apply_type"
- t.integer "apply_id"
- t.integer "status"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
- create_table "attachments", :force => true do |t|
- t.integer "container_id"
- t.string "container_type", :limit => 30
- t.string "filename", :default => "", :null => false
- t.string "disk_filename", :default => "", :null => false
- t.integer "filesize", :default => 0, :null => false
- t.string "content_type", :default => ""
- t.string "digest", :limit => 40, :default => "", :null => false
- t.integer "downloads", :default => 0, :null => false
- t.integer "author_id", :default => 0, :null => false
- t.datetime "created_on"
- t.string "description"
- t.string "disk_directory"
- t.integer "attachtype", :default => 1
- t.integer "is_public", :default => 1
- end
-
- add_index "attachments", ["author_id"], :name => "index_attachments_on_author_id"
- add_index "attachments", ["container_id", "container_type"], :name => "index_attachments_on_container_id_and_container_type"
- add_index "attachments", ["created_on"], :name => "index_attachments_on_created_on"
-
- create_table "attachmentstypes", :force => true do |t|
- t.integer "typeId", :null => false
- t.string "typeName", :limit => 50
- end
-
- create_table "auth_sources", :force => true do |t|
- t.string "type", :limit => 30, :default => "", :null => false
- t.string "name", :limit => 60, :default => "", :null => false
- t.string "host", :limit => 60
- t.integer "port"
- t.string "account"
- t.string "account_password", :default => ""
- t.string "base_dn"
- t.string "attr_login", :limit => 30
- t.string "attr_firstname", :limit => 30
- t.string "attr_lastname", :limit => 30
- t.string "attr_mail", :limit => 30
- t.boolean "onthefly_register", :default => false, :null => false
- t.boolean "tls", :default => false, :null => false
- t.string "filter"
- t.integer "timeout"
- end
-
- add_index "auth_sources", ["id", "type"], :name => "index_auth_sources_on_id_and_type"
-
- create_table "biding_projects", :force => true do |t|
- t.integer "project_id"
- t.integer "bid_id"
- t.integer "user_id"
- t.string "description"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- t.string "reward"
- end
-
- create_table "bids", :force => true do |t|
- t.string "name"
- t.string "budget", :null => false
- t.integer "author_id"
- t.date "deadline"
- t.text "description"
- t.datetime "created_on", :null => false
- t.datetime "updated_on", :null => false
- t.integer "commit"
- t.integer "reward_type"
- t.integer "homework_type"
- t.integer "parent_id"
- t.string "password"
- t.integer "is_evaluation"
- t.integer "proportion", :default => 60
- end
-
- create_table "boards", :force => true do |t|
- t.integer "project_id", :null => false
- t.string "name", :default => "", :null => false
- t.string "description"
- t.integer "position", :default => 1
- t.integer "topics_count", :default => 0, :null => false
- t.integer "messages_count", :default => 0, :null => false
- t.integer "last_message_id"
- t.integer "parent_id"
- t.integer "course_id"
- end
-
- add_index "boards", ["last_message_id"], :name => "index_boards_on_last_message_id"
- add_index "boards", ["project_id"], :name => "boards_project_id"
-
- create_table "bug_to_osps", :force => true do |t|
- t.integer "osp_id"
- t.integer "relative_memo_id"
- t.string "description"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
- create_table "changes", :force => true do |t|
- t.integer "changeset_id", :null => false
- t.string "action", :limit => 1, :default => "", :null => false
- t.text "path", :null => false
- t.text "from_path"
- t.string "from_revision"
- t.string "revision"
- t.string "branch"
- end
-
- add_index "changes", ["changeset_id"], :name => "changesets_changeset_id"
-
- create_table "changeset_parents", :id => false, :force => true do |t|
- t.integer "changeset_id", :null => false
- t.integer "parent_id", :null => false
- end
-
- add_index "changeset_parents", ["changeset_id"], :name => "changeset_parents_changeset_ids"
- add_index "changeset_parents", ["parent_id"], :name => "changeset_parents_parent_ids"
-
- create_table "changesets", :force => true do |t|
- t.integer "repository_id", :null => false
- t.string "revision", :null => false
- t.string "committer"
- t.datetime "committed_on", :null => false
- t.text "comments"
- t.date "commit_date"
- t.string "scmid"
- t.integer "user_id"
- end
-
- add_index "changesets", ["committed_on"], :name => "index_changesets_on_committed_on"
- add_index "changesets", ["repository_id", "revision"], :name => "changesets_repos_rev", :unique => true
- add_index "changesets", ["repository_id", "scmid"], :name => "changesets_repos_scmid"
- add_index "changesets", ["repository_id"], :name => "index_changesets_on_repository_id"
- add_index "changesets", ["user_id"], :name => "index_changesets_on_user_id"
-
- create_table "changesets_issues", :id => false, :force => true do |t|
- t.integer "changeset_id", :null => false
- t.integer "issue_id", :null => false
- end
-
- add_index "changesets_issues", ["changeset_id", "issue_id"], :name => "changesets_issues_ids", :unique => true
-
- create_table "code_review_assignments", :force => true do |t|
- t.integer "issue_id"
- t.integer "change_id"
- t.integer "attachment_id"
- t.string "file_path"
- t.string "rev"
- t.string "rev_to"
- t.string "action_type"
- t.integer "changeset_id"
- end
-
- create_table "code_review_project_settings", :force => true do |t|
- t.integer "project_id"
- t.integer "tracker_id"
- t.datetime "created_at"
- t.datetime "updated_at"
- t.integer "updated_by"
- t.boolean "hide_code_review_tab", :default => false
- t.integer "auto_relation", :default => 1
- t.integer "assignment_tracker_id"
- t.text "auto_assign"
- t.integer "lock_version", :default => 0, :null => false
- t.boolean "tracker_in_review_dialog", :default => false
- end
-
- create_table "code_review_user_settings", :force => true do |t|
- t.integer "user_id", :default => 0, :null => false
- t.integer "mail_notification", :default => 0, :null => false
- t.datetime "created_at"
- t.datetime "updated_at"
- end
-
- create_table "code_reviews", :force => true do |t|
- t.integer "project_id"
- t.integer "change_id"
- t.datetime "created_at"
- t.datetime "updated_at"
- t.integer "line"
- t.integer "updated_by_id"
- t.integer "lock_version", :default => 0, :null => false
- t.integer "status_changed_from"
- t.integer "status_changed_to"
- t.integer "issue_id"
- t.string "action_type"
- t.string "file_path"
- t.string "rev"
- t.string "rev_to"
- t.integer "attachment_id"
- t.integer "file_count", :default => 0, :null => false
- t.boolean "diff_all"
- end
-
- create_table "comments", :force => true do |t|
- t.string "commented_type", :limit => 30, :default => "", :null => false
- t.integer "commented_id", :default => 0, :null => false
- t.integer "author_id", :default => 0, :null => false
- t.text "comments"
- t.datetime "created_on", :null => false
- t.datetime "updated_on", :null => false
- end
-
- add_index "comments", ["author_id"], :name => "index_comments_on_author_id"
- add_index "comments", ["commented_id", "commented_type"], :name => "index_comments_on_commented_id_and_commented_type"
-
- create_table "contest_notifications", :force => true do |t|
- t.text "title"
- t.text "content"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
- create_table "contesting_projects", :force => true do |t|
- t.integer "project_id"
- t.string "contest_id"
- t.integer "user_id"
- t.string "description"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- t.string "reward"
- end
-
- create_table "contesting_softapplications", :force => true do |t|
- t.integer "softapplication_id"
- t.integer "contest_id"
- t.integer "user_id"
- t.string "description"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- t.string "reward"
- end
-
- create_table "contestnotifications", :force => true do |t|
- t.integer "contest_id"
- t.string "title"
- t.string "summary"
- t.text "description"
- t.integer "author_id"
- t.integer "notificationcomments_count"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
- create_table "contests", :force => true do |t|
- t.string "name"
- t.string "budget", :default => ""
- t.integer "author_id"
- t.date "deadline"
- t.string "description"
- t.integer "commit"
- t.string "password"
- t.datetime "created_on", :null => false
- t.datetime "updated_on", :null => false
- end
-
- create_table "course_attachments", :force => true do |t|
- t.string "filename"
- t.string "disk_filename"
- t.integer "filesize"
- t.string "content_type"
- t.string "digest"
- t.integer "downloads"
- t.string "author_id"
- t.string "integer"
- t.string "description"
- t.string "disk_directory"
- t.integer "attachtype"
- t.integer "is_public"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- t.integer "container_id", :default => 0
- end
-
- create_table "course_infos", :force => true do |t|
- t.integer "course_id"
- t.integer "user_id"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
- create_table "course_statuses", :force => true do |t|
- t.integer "changesets_count"
- t.integer "watchers_count"
- t.integer "course_id"
- t.float "grade", :default => 0.0
- t.integer "course_ac_para", :default => 0
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
- create_table "courses", :force => true do |t|
- t.integer "tea_id"
- t.string "name"
- t.integer "state"
- t.string "code"
- t.integer "time"
- t.string "extra"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- t.string "location"
- t.string "term"
- t.string "string"
- t.string "password"
- t.string "setup_time"
- t.string "endup_time"
- t.string "class_period"
- t.integer "school_id"
- t.text "description"
- t.integer "status", :default => 1
- t.integer "attachmenttype", :default => 2
- t.integer "lft"
- t.integer "rgt"
- t.integer "is_public", :limit => 1, :default => 1
- t.integer "inherit_members", :limit => 1, :default => 1
- t.integer "open_student", :default => 0
- end
-
- create_table "custom_fields", :force => true do |t|
- t.string "type", :limit => 30, :default => "", :null => false
- t.string "name", :limit => 30, :default => "", :null => false
- t.string "field_format", :limit => 30, :default => "", :null => false
- t.text "possible_values"
- t.string "regexp", :default => ""
- t.integer "min_length", :default => 0, :null => false
- t.integer "max_length", :default => 0, :null => false
- t.boolean "is_required", :default => false, :null => false
- t.boolean "is_for_all", :default => false, :null => false
- t.boolean "is_filter", :default => false, :null => false
- t.integer "position", :default => 1
- t.boolean "searchable", :default => false
- t.text "default_value"
- t.boolean "editable", :default => true
- t.boolean "visible", :default => true, :null => false
- t.boolean "multiple", :default => false
- end
-
- add_index "custom_fields", ["id", "type"], :name => "index_custom_fields_on_id_and_type"
-
- create_table "custom_fields_projects", :id => false, :force => true do |t|
- t.integer "custom_field_id", :default => 0, :null => false
- t.integer "project_id", :default => 0, :null => false
- end
-
- add_index "custom_fields_projects", ["custom_field_id", "project_id"], :name => "index_custom_fields_projects_on_custom_field_id_and_project_id", :unique => true
-
- create_table "custom_fields_trackers", :id => false, :force => true do |t|
- t.integer "custom_field_id", :default => 0, :null => false
- t.integer "tracker_id", :default => 0, :null => false
- end
-
- add_index "custom_fields_trackers", ["custom_field_id", "tracker_id"], :name => "index_custom_fields_trackers_on_custom_field_id_and_tracker_id", :unique => true
-
- create_table "custom_values", :force => true do |t|
- t.string "customized_type", :limit => 30, :default => "", :null => false
- t.integer "customized_id", :default => 0, :null => false
- t.integer "custom_field_id", :default => 0, :null => false
- t.text "value"
- end
-
- add_index "custom_values", ["custom_field_id"], :name => "index_custom_values_on_custom_field_id"
- add_index "custom_values", ["customized_type", "customized_id"], :name => "custom_values_customized"
-
- create_table "documents", :force => true do |t|
- t.integer "project_id", :default => 0, :null => false
- t.integer "category_id", :default => 0, :null => false
- t.string "title", :limit => 60, :default => "", :null => false
- t.text "description"
- t.datetime "created_on"
- t.integer "user_id", :default => 0
- t.integer "is_public", :default => 1
- end
-
- add_index "documents", ["category_id"], :name => "index_documents_on_category_id"
- add_index "documents", ["created_on"], :name => "index_documents_on_created_on"
- add_index "documents", ["project_id"], :name => "documents_project_id"
-
- create_table "enabled_modules", :force => true do |t|
- t.integer "project_id"
- t.string "name", :null => false
- t.integer "course_id"
- end
-
- add_index "enabled_modules", ["project_id"], :name => "enabled_modules_project_id"
-
- create_table "enumerations", :force => true do |t|
- t.string "name", :limit => 30, :default => "", :null => false
- t.integer "position", :default => 1
- t.boolean "is_default", :default => false, :null => false
- t.string "type"
- t.boolean "active", :default => true, :null => false
- t.integer "project_id"
- t.integer "parent_id"
- t.string "position_name", :limit => 30
- end
-
- add_index "enumerations", ["id", "type"], :name => "index_enumerations_on_id_and_type"
- add_index "enumerations", ["project_id"], :name => "index_enumerations_on_project_id"
-
- create_table "first_pages", :force => true do |t|
- t.string "web_title"
- t.string "title"
- t.text "description"
- t.string "page_type"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- t.integer "sort_type"
- t.integer "image_width", :default => 107
- t.integer "image_height", :default => 63
- t.integer "show_course", :default => 1
- t.integer "show_contest", :default => 1
- end
-
- create_table "forums", :force => true do |t|
- t.string "name", :null => false
- t.text "description"
- t.integer "topic_count", :default => 0
- t.integer "memo_count", :default => 0
- t.integer "last_memo_id", :default => 0
- t.integer "creator_id", :null => false
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
- create_table "groups_users", :id => false, :force => true do |t|
- t.integer "group_id", :null => false
- t.integer "user_id", :null => false
- end
-
- add_index "groups_users", ["group_id", "user_id"], :name => "groups_users_ids", :unique => true
-
- create_table "homework_attaches", :force => true do |t|
- t.integer "bid_id"
- t.integer "user_id"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- t.string "reward"
- t.string "name"
- t.text "description"
- t.integer "state"
- t.integer "project_id", :default => 0
- end
-
- create_table "homework_for_courses", :force => true do |t|
- t.integer "course_id"
- t.integer "bid_id"
- end
-
- create_table "homework_users", :force => true do |t|
- t.string "homework_attach_id"
- t.string "user_id"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
- create_table "issue_categories", :force => true do |t|
- t.integer "project_id", :default => 0, :null => false
- t.string "name", :limit => 30, :default => "", :null => false
- t.integer "assigned_to_id"
- end
-
- add_index "issue_categories", ["assigned_to_id"], :name => "index_issue_categories_on_assigned_to_id"
- add_index "issue_categories", ["project_id"], :name => "issue_categories_project_id"
-
- create_table "issue_relations", :force => true do |t|
- t.integer "issue_from_id", :null => false
- t.integer "issue_to_id", :null => false
- t.string "relation_type", :default => "", :null => false
- t.integer "delay"
- end
-
- add_index "issue_relations", ["issue_from_id", "issue_to_id"], :name => "index_issue_relations_on_issue_from_id_and_issue_to_id", :unique => true
- add_index "issue_relations", ["issue_from_id"], :name => "index_issue_relations_on_issue_from_id"
- add_index "issue_relations", ["issue_to_id"], :name => "index_issue_relations_on_issue_to_id"
-
- create_table "issue_statuses", :force => true do |t|
- t.string "name", :limit => 30, :default => "", :null => false
- t.boolean "is_closed", :default => false, :null => false
- t.boolean "is_default", :default => false, :null => false
- t.integer "position", :default => 1
- t.integer "default_done_ratio"
- end
-
- add_index "issue_statuses", ["is_closed"], :name => "index_issue_statuses_on_is_closed"
- add_index "issue_statuses", ["is_default"], :name => "index_issue_statuses_on_is_default"
- add_index "issue_statuses", ["position"], :name => "index_issue_statuses_on_position"
-
- create_table "issues", :force => true do |t|
- t.integer "tracker_id", :null => false
- t.integer "project_id", :null => false
- t.string "subject", :default => "", :null => false
- t.text "description"
- t.date "due_date"
- t.integer "category_id"
- t.integer "status_id", :null => false
- t.integer "assigned_to_id"
- t.integer "priority_id", :null => false
- t.integer "fixed_version_id"
- t.integer "author_id", :null => false
- t.integer "lock_version", :default => 0, :null => false
- t.datetime "created_on"
- t.datetime "updated_on"
- t.date "start_date"
- t.integer "done_ratio", :default => 0, :null => false
- t.float "estimated_hours"
- t.integer "parent_id"
- t.integer "root_id"
- t.integer "lft"
- t.integer "rgt"
- t.boolean "is_private", :default => false, :null => false
- t.datetime "closed_on"
- end
-
- add_index "issues", ["assigned_to_id"], :name => "index_issues_on_assigned_to_id"
- add_index "issues", ["author_id"], :name => "index_issues_on_author_id"
- add_index "issues", ["category_id"], :name => "index_issues_on_category_id"
- add_index "issues", ["created_on"], :name => "index_issues_on_created_on"
- add_index "issues", ["fixed_version_id"], :name => "index_issues_on_fixed_version_id"
- add_index "issues", ["priority_id"], :name => "index_issues_on_priority_id"
- add_index "issues", ["project_id"], :name => "issues_project_id"
- add_index "issues", ["root_id", "lft", "rgt"], :name => "index_issues_on_root_id_and_lft_and_rgt"
- add_index "issues", ["status_id"], :name => "index_issues_on_status_id"
- add_index "issues", ["tracker_id"], :name => "index_issues_on_tracker_id"
-
- create_table "join_in_competitions", :force => true do |t|
- t.integer "user_id"
- t.integer "competition_id"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
- create_table "join_in_contests", :force => true do |t|
- t.integer "user_id"
- t.integer "bid_id"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
- create_table "journal_details", :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", ["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"
- t.integer "reply_id"
- end
-
- add_index "journal_replies", ["journal_id"], :name => "index_journal_replies_on_journal_id"
- add_index "journal_replies", ["reply_id"], :name => "index_journal_replies_on_reply_id"
- add_index "journal_replies", ["user_id"], :name => "index_journal_replies_on_user_id"
-
- create_table "journals", :force => true do |t|
- t.integer "journalized_id", :default => 0, :null => false
- t.string "journalized_type", :limit => 30, :default => "", :null => false
- t.integer "user_id", :default => 0, :null => false
- t.text "notes"
- t.datetime "created_on", :null => false
- t.boolean "private_notes", :default => false, :null => false
- end
-
- add_index "journals", ["created_on"], :name => "index_journals_on_created_on"
- add_index "journals", ["journalized_id", "journalized_type"], :name => "journals_journalized_id"
- add_index "journals", ["journalized_id"], :name => "index_journals_on_journalized_id"
- add_index "journals", ["user_id"], :name => "index_journals_on_user_id"
-
- create_table "journals_for_messages", :force => true do |t|
- t.integer "jour_id"
- t.string "jour_type"
- t.integer "user_id"
- t.text "notes"
- t.integer "status"
- t.integer "reply_id"
- t.datetime "created_on", :null => false
- t.datetime "updated_on", :null => false
- t.string "m_parent_id"
- t.boolean "is_readed"
- t.integer "m_reply_count"
- t.integer "m_reply_id"
- t.integer "is_comprehensive_evaluation"
- end
-
- create_table "member_roles", :force => true do |t|
- t.integer "member_id", :null => false
- t.integer "role_id", :null => false
- t.integer "inherited_from"
- end
-
- add_index "member_roles", ["member_id"], :name => "index_member_roles_on_member_id"
- add_index "member_roles", ["role_id"], :name => "index_member_roles_on_role_id"
-
- create_table "members", :force => true do |t|
- t.integer "user_id", :default => 0, :null => false
- t.integer "project_id", :default => 0
- t.datetime "created_on"
- t.boolean "mail_notification", :default => false, :null => false
- t.integer "course_id", :default => -1
- end
-
- add_index "members", ["project_id"], :name => "index_members_on_project_id"
- add_index "members", ["user_id", "project_id", "course_id"], :name => "index_members_on_user_id_and_project_id", :unique => true
- add_index "members", ["user_id"], :name => "index_members_on_user_id"
-
- create_table "memos", :force => true do |t|
- t.integer "forum_id", :null => false
- t.integer "parent_id"
- t.string "subject", :null => false
- t.text "content", :null => false
- t.integer "author_id", :null => false
- t.integer "replies_count", :default => 0
- t.integer "last_reply_id"
- t.boolean "lock", :default => false
- t.boolean "sticky", :default => false
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- t.integer "viewed_count", :default => 0
- end
-
- create_table "messages", :force => true do |t|
- t.integer "board_id", :null => false
- t.integer "parent_id"
- t.string "subject", :default => "", :null => false
- t.text "content"
- t.integer "author_id"
- t.integer "replies_count", :default => 0, :null => false
- t.integer "last_reply_id"
- t.datetime "created_on", :null => false
- t.datetime "updated_on", :null => false
- t.boolean "locked", :default => false
- t.integer "sticky", :default => 0
- end
-
- add_index "messages", ["author_id"], :name => "index_messages_on_author_id"
- add_index "messages", ["board_id"], :name => "messages_board_id"
- add_index "messages", ["created_on"], :name => "index_messages_on_created_on"
- add_index "messages", ["last_reply_id"], :name => "index_messages_on_last_reply_id"
- add_index "messages", ["parent_id"], :name => "messages_parent_id"
-
- create_table "news", :force => true do |t|
- t.integer "project_id"
- t.string "title", :limit => 60, :default => "", :null => false
- t.string "summary", :default => ""
- t.text "description"
- t.integer "author_id", :default => 0, :null => false
- t.datetime "created_on"
- t.integer "comments_count", :default => 0, :null => false
- t.integer "course_id"
- end
-
- add_index "news", ["author_id"], :name => "index_news_on_author_id"
- add_index "news", ["created_on"], :name => "index_news_on_created_on"
- add_index "news", ["project_id"], :name => "news_project_id"
-
- create_table "no_uses", :force => true do |t|
- t.integer "user_id", :null => false
- t.string "no_use_type"
- t.integer "no_use_id"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
- create_table "notificationcomments", :force => true do |t|
- t.string "notificationcommented_type"
- t.integer "notificationcommented_id"
- t.integer "author_id"
- t.text "notificationcomments"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
- create_table "open_id_authentication_associations", :force => true do |t|
- t.integer "issued"
- t.integer "lifetime"
- t.string "handle"
- t.string "assoc_type"
- t.binary "server_url"
- t.binary "secret"
- end
-
- create_table "open_id_authentication_nonces", :force => true do |t|
- t.integer "timestamp", :null => false
- t.string "server_url"
- t.string "salt", :null => false
- end
-
- create_table "open_source_projects", :force => true do |t|
- t.string "name"
- t.text "description"
- t.integer "commit_count", :default => 0
- t.integer "code_line", :default => 0
- t.integer "users_count", :default => 0
- t.date "last_commit_time"
- t.string "url"
- t.date "date_collected"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
- create_table "option_numbers", :force => true do |t|
- t.integer "user_id"
- t.integer "memo"
- t.integer "messages_for_issues"
- t.integer "issues_status"
- t.integer "replay_for_message"
- t.integer "replay_for_memo"
- t.integer "follow"
- t.integer "tread"
- t.integer "praise_by_one"
- t.integer "praise_by_two"
- t.integer "praise_by_three"
- t.integer "tread_by_one"
- t.integer "tread_by_two"
- t.integer "tread_by_three"
- t.integer "changeset"
- t.integer "document"
- t.integer "attachment"
- t.integer "issue_done_ratio"
- t.integer "post_issue"
- t.integer "score_type"
- t.integer "total_score"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- t.integer "project_id"
- end
-
- create_table "praise_tread_caches", :force => true do |t|
- t.integer "object_id", :null => false
- t.string "object_type"
- t.integer "praise_num"
- t.integer "tread_num"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
- create_table "praise_treads", :force => true do |t|
- t.integer "user_id", :null => false
- t.integer "praise_tread_object_id"
- t.string "praise_tread_object_type"
- t.integer "praise_or_tread"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
- create_table "project_infos", :force => true do |t|
- t.integer "project_id"
- t.integer "user_id"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
- create_table "project_scores", :force => true do |t|
- t.string "project_id"
- t.integer "score"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- t.integer "issue_num", :default => 0
- t.integer "issue_journal_num", :default => 0
- t.integer "news_num", :default => 0
- t.integer "documents_num", :default => 0
- t.integer "changeset_num", :default => 0
- t.integer "board_message_num", :default => 0
- end
-
- create_table "project_statuses", :force => true do |t|
- t.integer "changesets_count"
- t.integer "watchers_count"
- t.integer "project_id"
- t.integer "project_type"
- t.float "grade", :default => 0.0
- t.integer "course_ac_para", :default => 0
- end
-
- add_index "project_statuses", ["grade"], :name => "index_project_statuses_on_grade"
-
- create_table "projecting_softapplictions", :force => true do |t|
- t.integer "user_id"
- t.integer "softapplication_id"
- t.integer "project_id"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
- create_table "projects", :force => true do |t|
- t.string "name", :default => "", :null => false
- t.text "description"
- t.string "homepage", :default => ""
- t.boolean "is_public", :default => true, :null => false
- t.integer "parent_id"
- t.datetime "created_on"
- t.datetime "updated_on"
- t.string "identifier"
- t.integer "status", :default => 1, :null => false
- t.integer "lft"
- t.integer "rgt"
- t.boolean "inherit_members", :default => false, :null => false
- t.integer "project_type"
- t.boolean "hidden_repo", :default => false, :null => false
- t.integer "attachmenttype", :default => 1
- t.integer "user_id"
- t.integer "dts_test", :default => 0
- end
-
- add_index "projects", ["lft"], :name => "index_projects_on_lft"
- add_index "projects", ["rgt"], :name => "index_projects_on_rgt"
-
- create_table "projects_trackers", :id => false, :force => true do |t|
- t.integer "project_id", :default => 0, :null => false
- t.integer "tracker_id", :default => 0, :null => false
- end
-
- add_index "projects_trackers", ["project_id", "tracker_id"], :name => "projects_trackers_unique", :unique => true
- add_index "projects_trackers", ["project_id"], :name => "projects_trackers_project_id"
-
- create_table "queries", :force => true do |t|
- t.integer "project_id"
- t.string "name", :default => "", :null => false
- t.text "filters"
- t.integer "user_id", :default => 0, :null => false
- t.boolean "is_public", :default => false, :null => false
- t.text "column_names"
- t.text "sort_criteria"
- t.string "group_by"
- t.string "type"
- end
-
- add_index "queries", ["project_id"], :name => "index_queries_on_project_id"
- add_index "queries", ["user_id"], :name => "index_queries_on_user_id"
-
- create_table "relative_memo_to_open_source_projects", :force => true do |t|
- t.integer "osp_id"
- t.integer "relative_memo_id"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
- create_table "relative_memos", :force => true do |t|
- t.integer "osp_id"
- t.integer "parent_id"
- t.string "subject", :null => false
- t.text "content", :limit => 16777215, :null => false
- t.integer "author_id"
- t.integer "replies_count", :default => 0
- t.integer "last_reply_id"
- t.boolean "lock", :default => false
- t.boolean "sticky", :default => false
- t.boolean "is_quote", :default => false
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- t.integer "viewed_count_crawl", :default => 0
- t.integer "viewed_count_local", :default => 0
- t.string "url"
- t.string "username"
- t.string "userhomeurl"
- t.date "date_collected"
- t.string "topic_resource"
- end
-
- create_table "repositories", :force => true do |t|
- t.integer "project_id", :default => 0, :null => false
- t.string "url", :default => "", :null => false
- t.string "login", :limit => 60, :default => ""
- t.string "password", :default => ""
- t.string "root_url", :default => ""
- t.string "type"
- t.string "path_encoding", :limit => 64
- t.string "log_encoding", :limit => 64
- t.text "extra_info"
- t.string "identifier"
- t.boolean "is_default", :default => false
- end
-
- add_index "repositories", ["project_id"], :name => "index_repositories_on_project_id"
-
- create_table "rich_rich_files", :force => true do |t|
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- t.string "rich_file_file_name"
- t.string "rich_file_content_type"
- t.integer "rich_file_file_size"
- t.datetime "rich_file_updated_at"
- t.string "owner_type"
- t.integer "owner_id"
- t.text "uri_cache"
- t.string "simplified_type", :default => "file"
- end
-
- create_table "roles", :force => true do |t|
- t.string "name", :limit => 30, :default => "", :null => false
- t.integer "position", :default => 1
- t.boolean "assignable", :default => true
- t.integer "builtin", :default => 0, :null => false
- t.text "permissions"
- t.string "issues_visibility", :limit => 30, :default => "default", :null => false
- end
-
- create_table "schools", :force => true do |t|
- t.string "name"
- t.string "province"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- t.string "logo_link"
- end
-
- create_table "seems_rateable_cached_ratings", :force => true do |t|
- t.integer "cacheable_id", :limit => 8
- t.string "cacheable_type"
- t.float "avg", :null => false
- t.integer "cnt", :null => false
- t.string "dimension"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
- create_table "seems_rateable_rates", :force => true do |t|
- t.integer "rater_id", :limit => 8
- t.integer "rateable_id"
- t.string "rateable_type"
- t.float "stars", :null => false
- t.string "dimension"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
- create_table "settings", :force => true do |t|
- t.string "name", :default => "", :null => false
- t.text "value"
- t.datetime "updated_on"
- end
-
- add_index "settings", ["name"], :name => "index_settings_on_name"
-
- create_table "shares", :force => true do |t|
- t.date "created_on"
- t.string "url"
- t.string "title"
- t.integer "share_type"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- t.integer "project_id"
- t.integer "user_id"
- t.string "description"
- end
-
- create_table "softapplications", :force => true do |t|
- t.string "name"
- t.text "description"
- t.integer "app_type_id"
- t.string "app_type_name"
- t.string "android_min_version_available"
- t.integer "user_id"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- t.integer "contest_id"
- t.integer "softapplication_id"
- t.integer "is_public"
- t.string "application_developers"
- t.string "deposit_project_url"
- t.string "deposit_project"
- t.integer "project_id"
- end
-
- create_table "students_for_courses", :force => true do |t|
- t.integer "student_id"
- t.integer "course_id"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
- create_table "taggings", :force => true do |t|
- t.integer "tag_id"
- t.integer "taggable_id"
- t.string "taggable_type"
- t.integer "tagger_id"
- t.string "tagger_type"
- t.string "context", :limit => 128
- t.datetime "created_at"
- end
-
- add_index "taggings", ["tag_id"], :name => "index_taggings_on_tag_id"
- add_index "taggings", ["taggable_id", "taggable_type", "context"], :name => "index_taggings_on_taggable_id_and_taggable_type_and_context"
- add_index "taggings", ["taggable_type"], :name => "index_taggings_on_taggable_type"
-
- create_table "tags", :force => true do |t|
- t.string "name"
- end
-
- create_table "teachers", :force => true do |t|
- t.string "tea_name"
- t.string "location"
- t.integer "couurse_time"
- t.integer "course_code"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- t.string "extra"
- end
-
- create_table "time_entries", :force => true do |t|
- t.integer "project_id", :null => false
- t.integer "user_id", :null => false
- t.integer "issue_id"
- t.float "hours", :null => false
- t.string "comments"
- t.integer "activity_id", :null => false
- t.date "spent_on", :null => false
- t.integer "tyear", :null => false
- t.integer "tmonth", :null => false
- t.integer "tweek", :null => false
- t.datetime "created_on", :null => false
- t.datetime "updated_on", :null => false
- end
-
- add_index "time_entries", ["activity_id"], :name => "index_time_entries_on_activity_id"
- add_index "time_entries", ["created_on"], :name => "index_time_entries_on_created_on"
- add_index "time_entries", ["issue_id"], :name => "time_entries_issue_id"
- add_index "time_entries", ["project_id"], :name => "time_entries_project_id"
- add_index "time_entries", ["user_id"], :name => "index_time_entries_on_user_id"
-
- create_table "tokens", :force => true do |t|
- t.integer "user_id", :default => 0, :null => false
- t.string "action", :limit => 30, :default => "", :null => false
- t.string "value", :limit => 40, :default => "", :null => false
- t.datetime "created_on", :null => false
- end
-
- add_index "tokens", ["user_id"], :name => "index_tokens_on_user_id"
- add_index "tokens", ["value"], :name => "tokens_value", :unique => true
-
- create_table "trackers", :force => true do |t|
- t.string "name", :limit => 30, :default => "", :null => false
- t.boolean "is_in_chlog", :default => false, :null => false
- t.integer "position", :default => 1
- t.boolean "is_in_roadmap", :default => true, :null => false
- t.integer "fields_bits", :default => 0
- end
-
- create_table "user_extensions", :force => true do |t|
- t.integer "user_id", :null => false
- t.date "birthday"
- t.string "brief_introduction"
- t.integer "gender"
- t.string "location"
- t.string "occupation"
- t.integer "work_experience"
- t.integer "zip_code"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- t.string "technical_title"
- t.integer "identity"
- t.string "student_id"
- t.string "teacher_realname"
- t.string "student_realname"
- t.string "location_city"
- t.integer "school_id"
- end
-
- create_table "user_grades", :force => true do |t|
- t.integer "user_id", :null => false
- t.integer "project_id", :null => false
- t.float "grade", :default => 0.0
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
- add_index "user_grades", ["grade"], :name => "index_user_grades_on_grade"
- add_index "user_grades", ["project_id"], :name => "index_user_grades_on_project_id"
- add_index "user_grades", ["user_id"], :name => "index_user_grades_on_user_id"
-
- create_table "user_levels", :force => true do |t|
- t.integer "user_id"
- t.integer "level"
- end
-
- create_table "user_preferences", :force => true do |t|
- t.integer "user_id", :default => 0, :null => false
- t.text "others"
- t.boolean "hide_mail", :default => false
- t.string "time_zone"
- end
-
- add_index "user_preferences", ["user_id"], :name => "index_user_preferences_on_user_id"
-
- create_table "user_score_details", :force => true do |t|
- t.integer "current_user_id"
- t.integer "target_user_id"
- t.string "score_type"
- t.string "score_action"
- t.integer "user_id"
- t.integer "old_score"
- t.integer "new_score"
- t.integer "current_user_level"
- t.integer "target_user_level"
- t.integer "score_changeable_obj_id"
- t.string "score_changeable_obj_type"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
- create_table "user_scores", :force => true do |t|
- t.integer "user_id", :null => false
- t.integer "collaboration"
- t.integer "influence"
- t.integer "skill"
- t.integer "active"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
- create_table "user_statuses", :force => true do |t|
- t.integer "changesets_count"
- t.integer "watchers_count"
- t.integer "user_id"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- t.float "grade", :default => 0.0
- end
-
- add_index "user_statuses", ["changesets_count"], :name => "index_user_statuses_on_changesets_count"
- add_index "user_statuses", ["grade"], :name => "index_user_statuses_on_grade"
- add_index "user_statuses", ["watchers_count"], :name => "index_user_statuses_on_watchers_count"
-
- create_table "users", :force => true do |t|
- t.string "login", :default => "", :null => false
- t.string "hashed_password", :limit => 40, :default => "", :null => false
- t.string "firstname", :limit => 30, :default => "", :null => false
- t.string "lastname", :default => "", :null => false
- t.string "mail", :limit => 60, :default => "", :null => false
- t.boolean "admin", :default => false, :null => false
- t.integer "status", :default => 1, :null => false
- t.datetime "last_login_on"
- t.string "language", :limit => 5, :default => ""
- t.integer "auth_source_id"
- t.datetime "created_on"
- t.datetime "updated_on"
- t.string "type"
- t.string "identity_url"
- t.string "mail_notification", :default => "", :null => false
- t.string "salt", :limit => 64
- end
-
- add_index "users", ["auth_source_id"], :name => "index_users_on_auth_source_id"
- add_index "users", ["id", "type"], :name => "index_users_on_id_and_type"
- add_index "users", ["type"], :name => "index_users_on_type"
-
- create_table "versions", :force => true do |t|
- t.integer "project_id", :default => 0, :null => false
- t.string "name", :default => "", :null => false
- t.string "description", :default => ""
- t.date "effective_date"
- t.datetime "created_on"
- t.datetime "updated_on"
- t.string "wiki_page_title"
- t.string "status", :default => "open"
- t.string "sharing", :default => "none", :null => false
- end
-
- add_index "versions", ["project_id"], :name => "versions_project_id"
- add_index "versions", ["sharing"], :name => "index_versions_on_sharing"
-
- create_table "watchers", :force => true do |t|
- t.string "watchable_type", :default => "", :null => false
- t.integer "watchable_id", :default => 0, :null => false
- t.integer "user_id"
- end
-
- add_index "watchers", ["user_id", "watchable_type"], :name => "watchers_user_id_type"
- add_index "watchers", ["user_id"], :name => "index_watchers_on_user_id"
- add_index "watchers", ["watchable_id", "watchable_type"], :name => "index_watchers_on_watchable_id_and_watchable_type"
-
- create_table "web_footer_companies", :force => true do |t|
- t.string "name"
- t.string "logo_size"
- t.string "url"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
- create_table "web_footer_oranizers", :force => true do |t|
- t.string "name"
- t.text "description"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
- create_table "wiki_content_versions", :force => true do |t|
- t.integer "wiki_content_id", :null => false
- t.integer "page_id", :null => false
- t.integer "author_id"
- t.binary "data", :limit => 2147483647
- t.string "compression", :limit => 6, :default => ""
- t.string "comments", :default => ""
- t.datetime "updated_on", :null => false
- t.integer "version", :null => false
- end
-
- add_index "wiki_content_versions", ["updated_on"], :name => "index_wiki_content_versions_on_updated_on"
- add_index "wiki_content_versions", ["wiki_content_id"], :name => "wiki_content_versions_wcid"
-
- create_table "wiki_contents", :force => true do |t|
- t.integer "page_id", :null => false
- t.integer "author_id"
- t.text "text", :limit => 2147483647
- t.string "comments", :default => ""
- t.datetime "updated_on", :null => false
- t.integer "version", :null => false
- end
-
- add_index "wiki_contents", ["author_id"], :name => "index_wiki_contents_on_author_id"
- add_index "wiki_contents", ["page_id"], :name => "wiki_contents_page_id"
-
- create_table "wiki_pages", :force => true do |t|
- t.integer "wiki_id", :null => false
- t.string "title", :null => false
- t.datetime "created_on", :null => false
- t.boolean "protected", :default => false, :null => false
- t.integer "parent_id"
- end
-
- add_index "wiki_pages", ["parent_id"], :name => "index_wiki_pages_on_parent_id"
- add_index "wiki_pages", ["wiki_id", "title"], :name => "wiki_pages_wiki_id_title"
- add_index "wiki_pages", ["wiki_id"], :name => "index_wiki_pages_on_wiki_id"
-
- create_table "wiki_redirects", :force => true do |t|
- t.integer "wiki_id", :null => false
- t.string "title"
- t.string "redirects_to"
- t.datetime "created_on", :null => false
- end
-
- add_index "wiki_redirects", ["wiki_id", "title"], :name => "wiki_redirects_wiki_id_title"
- add_index "wiki_redirects", ["wiki_id"], :name => "index_wiki_redirects_on_wiki_id"
-
- create_table "wikis", :force => true do |t|
- t.integer "project_id", :null => false
- t.string "start_page", :null => false
- t.integer "status", :default => 1, :null => false
- end
-
- add_index "wikis", ["project_id"], :name => "wikis_project_id"
-
- create_table "workflows", :force => true do |t|
- t.integer "tracker_id", :default => 0, :null => false
- t.integer "old_status_id", :default => 0, :null => false
- t.integer "new_status_id", :default => 0, :null => false
- t.integer "role_id", :default => 0, :null => false
- t.boolean "assignee", :default => false, :null => false
- t.boolean "author", :default => false, :null => false
- t.string "type", :limit => 30
- t.string "field_name", :limit => 30
- t.string "rule", :limit => 30
- end
-
- add_index "workflows", ["new_status_id"], :name => "index_workflows_on_new_status_id"
- add_index "workflows", ["old_status_id"], :name => "index_workflows_on_old_status_id"
- add_index "workflows", ["role_id", "tracker_id", "old_status_id"], :name => "wkfs_role_tracker_old_status"
- add_index "workflows", ["role_id"], :name => "index_workflows_on_role_id"
-
- create_table "works_categories", :force => true do |t|
- t.string "category"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
- end
-
-end
+# encoding: UTF-8
+# This file is auto-generated from the current state of the database. Instead
+# of editing this file, please use the migrations feature of Active Record to
+# incrementally modify your database, and then regenerate this schema definition.
+#
+# Note that this schema.rb definition is the authoritative source for your
+# database schema. If you need to create the application database on another
+# system, you should be using db:schema:load, not running all the migrations
+# from scratch. The latter is a flawed and unsustainable approach (the more migrations
+# you'll amass, the slower it'll run and the greater likelihood for issues).
+#
+# It's strongly recommended to check this file into your version control system.
+
+ActiveRecord::Schema.define(:version => 20141030071656) do
+
+ create_table "activities", :force => true do |t|
+ t.integer "act_id", :null => false
+ t.string "act_type", :null => false
+ t.integer "user_id", :null => false
+ end
+
+ add_index "activities", ["act_id", "act_type"], :name => "index_activities_on_act_id_and_act_type"
+ add_index "activities", ["user_id", "act_type"], :name => "index_activities_on_user_id_and_act_type"
+ add_index "activities", ["user_id"], :name => "index_activities_on_user_id"
+
+ create_table "applied_projects", :force => true do |t|
+ t.integer "project_id", :null => false
+ t.integer "user_id", :null => false
+ end
+
+ create_table "apply_project_masters", :force => true do |t|
+ t.integer "user_id"
+ t.string "apply_type"
+ t.integer "apply_id"
+ t.integer "status"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+ create_table "attachments", :force => true do |t|
+ t.integer "container_id"
+ t.string "container_type", :limit => 30
+ t.string "filename", :default => "", :null => false
+ t.string "disk_filename", :default => "", :null => false
+ t.integer "filesize", :default => 0, :null => false
+ t.string "content_type", :default => ""
+ t.string "digest", :limit => 40, :default => "", :null => false
+ t.integer "downloads", :default => 0, :null => false
+ t.integer "author_id", :default => 0, :null => false
+ t.datetime "created_on"
+ t.string "description"
+ t.string "disk_directory"
+ t.integer "attachtype", :default => 1
+ t.integer "is_public", :default => 1
+ end
+
+ add_index "attachments", ["author_id"], :name => "index_attachments_on_author_id"
+ add_index "attachments", ["container_id", "container_type"], :name => "index_attachments_on_container_id_and_container_type"
+ add_index "attachments", ["created_on"], :name => "index_attachments_on_created_on"
+
+ create_table "attachmentstypes", :force => true do |t|
+ t.integer "typeId", :null => false
+ t.string "typeName", :limit => 50
+ end
+
+ create_table "auth_sources", :force => true do |t|
+ t.string "type", :limit => 30, :default => "", :null => false
+ t.string "name", :limit => 60, :default => "", :null => false
+ t.string "host", :limit => 60
+ t.integer "port"
+ t.string "account"
+ t.string "account_password", :default => ""
+ t.string "base_dn"
+ t.string "attr_login", :limit => 30
+ t.string "attr_firstname", :limit => 30
+ t.string "attr_lastname", :limit => 30
+ t.string "attr_mail", :limit => 30
+ t.boolean "onthefly_register", :default => false, :null => false
+ t.boolean "tls", :default => false, :null => false
+ t.string "filter"
+ t.integer "timeout"
+ end
+
+ add_index "auth_sources", ["id", "type"], :name => "index_auth_sources_on_id_and_type"
+
+ create_table "biding_projects", :force => true do |t|
+ t.integer "project_id"
+ t.integer "bid_id"
+ t.integer "user_id"
+ t.string "description"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ t.string "reward"
+ end
+
+ create_table "bids", :force => true do |t|
+ t.string "name"
+ t.string "budget", :null => false
+ t.integer "author_id"
+ t.date "deadline"
+ t.text "description"
+ t.datetime "created_on", :null => false
+ t.datetime "updated_on", :null => false
+ t.integer "commit"
+ t.integer "reward_type"
+ t.integer "homework_type"
+ t.integer "parent_id"
+ t.string "password"
+ t.integer "is_evaluation"
+ t.integer "proportion", :default => 60
+ end
+
+ create_table "boards", :force => true do |t|
+ t.integer "project_id", :null => false
+ t.string "name", :default => "", :null => false
+ t.string "description"
+ t.integer "position", :default => 1
+ t.integer "topics_count", :default => 0, :null => false
+ t.integer "messages_count", :default => 0, :null => false
+ t.integer "last_message_id"
+ t.integer "parent_id"
+ t.integer "course_id"
+ end
+
+ add_index "boards", ["last_message_id"], :name => "index_boards_on_last_message_id"
+ add_index "boards", ["project_id"], :name => "boards_project_id"
+
+ create_table "bug_to_osps", :force => true do |t|
+ t.integer "osp_id"
+ t.integer "relative_memo_id"
+ t.string "description"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+ create_table "changes", :force => true do |t|
+ t.integer "changeset_id", :null => false
+ t.string "action", :limit => 1, :default => "", :null => false
+ t.text "path", :null => false
+ t.text "from_path"
+ t.string "from_revision"
+ t.string "revision"
+ t.string "branch"
+ end
+
+ add_index "changes", ["changeset_id"], :name => "changesets_changeset_id"
+
+ create_table "changeset_parents", :id => false, :force => true do |t|
+ t.integer "changeset_id", :null => false
+ t.integer "parent_id", :null => false
+ end
+
+ add_index "changeset_parents", ["changeset_id"], :name => "changeset_parents_changeset_ids"
+ add_index "changeset_parents", ["parent_id"], :name => "changeset_parents_parent_ids"
+
+ create_table "changesets", :force => true do |t|
+ t.integer "repository_id", :null => false
+ t.string "revision", :null => false
+ t.string "committer"
+ t.datetime "committed_on", :null => false
+ t.text "comments"
+ t.date "commit_date"
+ t.string "scmid"
+ t.integer "user_id"
+ end
+
+ add_index "changesets", ["committed_on"], :name => "index_changesets_on_committed_on"
+ add_index "changesets", ["repository_id", "revision"], :name => "changesets_repos_rev", :unique => true
+ add_index "changesets", ["repository_id", "scmid"], :name => "changesets_repos_scmid"
+ add_index "changesets", ["repository_id"], :name => "index_changesets_on_repository_id"
+ add_index "changesets", ["user_id"], :name => "index_changesets_on_user_id"
+
+ create_table "changesets_issues", :id => false, :force => true do |t|
+ t.integer "changeset_id", :null => false
+ t.integer "issue_id", :null => false
+ end
+
+ add_index "changesets_issues", ["changeset_id", "issue_id"], :name => "changesets_issues_ids", :unique => true
+
+ create_table "code_review_assignments", :force => true do |t|
+ t.integer "issue_id"
+ t.integer "change_id"
+ t.integer "attachment_id"
+ t.string "file_path"
+ t.string "rev"
+ t.string "rev_to"
+ t.string "action_type"
+ t.integer "changeset_id"
+ end
+
+ create_table "code_review_project_settings", :force => true do |t|
+ t.integer "project_id"
+ t.integer "tracker_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.integer "updated_by"
+ t.boolean "hide_code_review_tab", :default => false
+ t.integer "auto_relation", :default => 1
+ t.integer "assignment_tracker_id"
+ t.text "auto_assign"
+ t.integer "lock_version", :default => 0, :null => false
+ t.boolean "tracker_in_review_dialog", :default => false
+ end
+
+ create_table "code_review_user_settings", :force => true do |t|
+ t.integer "user_id", :default => 0, :null => false
+ t.integer "mail_notification", :default => 0, :null => false
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ create_table "code_reviews", :force => true do |t|
+ t.integer "project_id"
+ t.integer "change_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.integer "line"
+ t.integer "updated_by_id"
+ t.integer "lock_version", :default => 0, :null => false
+ t.integer "status_changed_from"
+ t.integer "status_changed_to"
+ t.integer "issue_id"
+ t.string "action_type"
+ t.string "file_path"
+ t.string "rev"
+ t.string "rev_to"
+ t.integer "attachment_id"
+ t.integer "file_count", :default => 0, :null => false
+ t.boolean "diff_all"
+ end
+
+ create_table "comments", :force => true do |t|
+ t.string "commented_type", :limit => 30, :default => "", :null => false
+ t.integer "commented_id", :default => 0, :null => false
+ t.integer "author_id", :default => 0, :null => false
+ t.text "comments"
+ t.datetime "created_on", :null => false
+ t.datetime "updated_on", :null => false
+ end
+
+ add_index "comments", ["author_id"], :name => "index_comments_on_author_id"
+ add_index "comments", ["commented_id", "commented_type"], :name => "index_comments_on_commented_id_and_commented_type"
+
+ create_table "contest_notifications", :force => true do |t|
+ t.text "title"
+ t.text "content"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+ create_table "contesting_projects", :force => true do |t|
+ t.integer "project_id"
+ t.string "contest_id"
+ t.integer "user_id"
+ t.string "description"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ t.string "reward"
+ end
+
+ create_table "contesting_softapplications", :force => true do |t|
+ t.integer "softapplication_id"
+ t.integer "contest_id"
+ t.integer "user_id"
+ t.string "description"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ t.string "reward"
+ end
+
+ create_table "contestnotifications", :force => true do |t|
+ t.integer "contest_id"
+ t.string "title"
+ t.string "summary"
+ t.text "description"
+ t.integer "author_id"
+ t.integer "notificationcomments_count"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+ create_table "contests", :force => true do |t|
+ t.string "name"
+ t.string "budget", :default => ""
+ t.integer "author_id"
+ t.date "deadline"
+ t.string "description"
+ t.integer "commit"
+ t.string "password"
+ t.datetime "created_on", :null => false
+ t.datetime "updated_on", :null => false
+ end
+
+ create_table "course_attachments", :force => true do |t|
+ t.string "filename"
+ t.string "disk_filename"
+ t.integer "filesize"
+ t.string "content_type"
+ t.string "digest"
+ t.integer "downloads"
+ t.string "author_id"
+ t.string "integer"
+ t.string "description"
+ t.string "disk_directory"
+ t.integer "attachtype"
+ t.integer "is_public"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ t.integer "container_id", :default => 0
+ end
+
+ create_table "course_infos", :force => true do |t|
+ t.integer "course_id"
+ t.integer "user_id"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+ create_table "course_statuses", :force => true do |t|
+ t.integer "changesets_count"
+ t.integer "watchers_count"
+ t.integer "course_id"
+ t.float "grade", :default => 0.0
+ t.integer "course_ac_para", :default => 0
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+ create_table "courses", :force => true do |t|
+ t.integer "tea_id"
+ t.string "name"
+ t.integer "state"
+ t.string "code"
+ t.integer "time"
+ t.string "extra"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ t.string "location"
+ t.string "term"
+ t.string "string"
+ t.string "password"
+ t.string "setup_time"
+ t.string "endup_time"
+ t.string "class_period"
+ t.integer "school_id"
+ t.text "description"
+ t.integer "status", :default => 1
+ t.integer "attachmenttype", :default => 2
+ t.integer "lft"
+ t.integer "rgt"
+ t.integer "is_public", :limit => 1, :default => 1
+ t.integer "inherit_members", :limit => 1, :default => 1
+ t.integer "open_student", :default => 0
+ end
+
+ create_table "custom_fields", :force => true do |t|
+ t.string "type", :limit => 30, :default => "", :null => false
+ t.string "name", :limit => 30, :default => "", :null => false
+ t.string "field_format", :limit => 30, :default => "", :null => false
+ t.text "possible_values"
+ t.string "regexp", :default => ""
+ t.integer "min_length", :default => 0, :null => false
+ t.integer "max_length", :default => 0, :null => false
+ t.boolean "is_required", :default => false, :null => false
+ t.boolean "is_for_all", :default => false, :null => false
+ t.boolean "is_filter", :default => false, :null => false
+ t.integer "position", :default => 1
+ t.boolean "searchable", :default => false
+ t.text "default_value"
+ t.boolean "editable", :default => true
+ t.boolean "visible", :default => true, :null => false
+ t.boolean "multiple", :default => false
+ end
+
+ add_index "custom_fields", ["id", "type"], :name => "index_custom_fields_on_id_and_type"
+
+ create_table "custom_fields_projects", :id => false, :force => true do |t|
+ t.integer "custom_field_id", :default => 0, :null => false
+ t.integer "project_id", :default => 0, :null => false
+ end
+
+ add_index "custom_fields_projects", ["custom_field_id", "project_id"], :name => "index_custom_fields_projects_on_custom_field_id_and_project_id", :unique => true
+
+ create_table "custom_fields_trackers", :id => false, :force => true do |t|
+ t.integer "custom_field_id", :default => 0, :null => false
+ t.integer "tracker_id", :default => 0, :null => false
+ end
+
+ add_index "custom_fields_trackers", ["custom_field_id", "tracker_id"], :name => "index_custom_fields_trackers_on_custom_field_id_and_tracker_id", :unique => true
+
+ create_table "custom_values", :force => true do |t|
+ t.string "customized_type", :limit => 30, :default => "", :null => false
+ t.integer "customized_id", :default => 0, :null => false
+ t.integer "custom_field_id", :default => 0, :null => false
+ t.text "value"
+ end
+
+ add_index "custom_values", ["custom_field_id"], :name => "index_custom_values_on_custom_field_id"
+ add_index "custom_values", ["customized_type", "customized_id"], :name => "custom_values_customized"
+
+ create_table "documents", :force => true do |t|
+ t.integer "project_id", :default => 0, :null => false
+ t.integer "category_id", :default => 0, :null => false
+ t.string "title", :limit => 60, :default => "", :null => false
+ t.text "description"
+ t.datetime "created_on"
+ t.integer "user_id", :default => 0
+ t.integer "is_public", :default => 1
+ end
+
+ add_index "documents", ["category_id"], :name => "index_documents_on_category_id"
+ add_index "documents", ["created_on"], :name => "index_documents_on_created_on"
+ add_index "documents", ["project_id"], :name => "documents_project_id"
+
+ create_table "enabled_modules", :force => true do |t|
+ t.integer "project_id"
+ t.string "name", :null => false
+ t.integer "course_id"
+ end
+
+ add_index "enabled_modules", ["project_id"], :name => "enabled_modules_project_id"
+
+ create_table "enumerations", :force => true do |t|
+ t.string "name", :limit => 30, :default => "", :null => false
+ t.integer "position", :default => 1
+ t.boolean "is_default", :default => false, :null => false
+ t.string "type"
+ t.boolean "active", :default => true, :null => false
+ t.integer "project_id"
+ t.integer "parent_id"
+ t.string "position_name", :limit => 30
+ end
+
+ add_index "enumerations", ["id", "type"], :name => "index_enumerations_on_id_and_type"
+ add_index "enumerations", ["project_id"], :name => "index_enumerations_on_project_id"
+
+ create_table "first_pages", :force => true do |t|
+ t.string "web_title"
+ t.string "title"
+ t.text "description"
+ t.string "page_type"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ t.integer "sort_type"
+ t.integer "image_width", :default => 107
+ t.integer "image_height", :default => 63
+ t.integer "show_course", :default => 1
+ t.integer "show_contest", :default => 1
+ end
+
+ create_table "forums", :force => true do |t|
+ t.string "name", :null => false
+ t.text "description"
+ t.integer "topic_count", :default => 0
+ t.integer "memo_count", :default => 0
+ t.integer "last_memo_id", :default => 0
+ t.integer "creator_id", :null => false
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+ create_table "groups_users", :id => false, :force => true do |t|
+ t.integer "group_id", :null => false
+ t.integer "user_id", :null => false
+ end
+
+ add_index "groups_users", ["group_id", "user_id"], :name => "groups_users_ids", :unique => true
+
+ create_table "homework_attaches", :force => true do |t|
+ t.integer "bid_id"
+ t.integer "user_id"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ t.string "reward"
+ t.string "name"
+ t.text "description"
+ t.integer "state"
+ t.integer "project_id", :default => 0
+ end
+
+ create_table "homework_for_courses", :force => true do |t|
+ t.integer "course_id"
+ t.integer "bid_id"
+ end
+
+ create_table "homework_users", :force => true do |t|
+ t.string "homework_attach_id"
+ t.string "user_id"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+ create_table "issue_categories", :force => true do |t|
+ t.integer "project_id", :default => 0, :null => false
+ t.string "name", :limit => 30, :default => "", :null => false
+ t.integer "assigned_to_id"
+ end
+
+ add_index "issue_categories", ["assigned_to_id"], :name => "index_issue_categories_on_assigned_to_id"
+ add_index "issue_categories", ["project_id"], :name => "issue_categories_project_id"
+
+ create_table "issue_relations", :force => true do |t|
+ t.integer "issue_from_id", :null => false
+ t.integer "issue_to_id", :null => false
+ t.string "relation_type", :default => "", :null => false
+ t.integer "delay"
+ end
+
+ add_index "issue_relations", ["issue_from_id", "issue_to_id"], :name => "index_issue_relations_on_issue_from_id_and_issue_to_id", :unique => true
+ add_index "issue_relations", ["issue_from_id"], :name => "index_issue_relations_on_issue_from_id"
+ add_index "issue_relations", ["issue_to_id"], :name => "index_issue_relations_on_issue_to_id"
+
+ create_table "issue_statuses", :force => true do |t|
+ t.string "name", :limit => 30, :default => "", :null => false
+ t.boolean "is_closed", :default => false, :null => false
+ t.boolean "is_default", :default => false, :null => false
+ t.integer "position", :default => 1
+ t.integer "default_done_ratio"
+ end
+
+ add_index "issue_statuses", ["is_closed"], :name => "index_issue_statuses_on_is_closed"
+ add_index "issue_statuses", ["is_default"], :name => "index_issue_statuses_on_is_default"
+ add_index "issue_statuses", ["position"], :name => "index_issue_statuses_on_position"
+
+ create_table "issues", :force => true do |t|
+ t.integer "tracker_id", :null => false
+ t.integer "project_id", :null => false
+ t.string "subject", :default => "", :null => false
+ t.text "description"
+ t.date "due_date"
+ t.integer "category_id"
+ t.integer "status_id", :null => false
+ t.integer "assigned_to_id"
+ t.integer "priority_id", :null => false
+ t.integer "fixed_version_id"
+ t.integer "author_id", :null => false
+ t.integer "lock_version", :default => 0, :null => false
+ t.datetime "created_on"
+ t.datetime "updated_on"
+ t.date "start_date"
+ t.integer "done_ratio", :default => 0, :null => false
+ t.float "estimated_hours"
+ t.integer "parent_id"
+ t.integer "root_id"
+ t.integer "lft"
+ t.integer "rgt"
+ t.boolean "is_private", :default => false, :null => false
+ t.datetime "closed_on"
+ end
+
+ add_index "issues", ["assigned_to_id"], :name => "index_issues_on_assigned_to_id"
+ add_index "issues", ["author_id"], :name => "index_issues_on_author_id"
+ add_index "issues", ["category_id"], :name => "index_issues_on_category_id"
+ add_index "issues", ["created_on"], :name => "index_issues_on_created_on"
+ add_index "issues", ["fixed_version_id"], :name => "index_issues_on_fixed_version_id"
+ add_index "issues", ["priority_id"], :name => "index_issues_on_priority_id"
+ add_index "issues", ["project_id"], :name => "issues_project_id"
+ add_index "issues", ["root_id", "lft", "rgt"], :name => "index_issues_on_root_id_and_lft_and_rgt"
+ add_index "issues", ["status_id"], :name => "index_issues_on_status_id"
+ add_index "issues", ["tracker_id"], :name => "index_issues_on_tracker_id"
+
+ create_table "join_in_competitions", :force => true do |t|
+ t.integer "user_id"
+ t.integer "competition_id"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+ create_table "join_in_contests", :force => true do |t|
+ t.integer "user_id"
+ t.integer "bid_id"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+ create_table "journal_details", :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", ["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"
+ t.integer "reply_id"
+ end
+
+ add_index "journal_replies", ["journal_id"], :name => "index_journal_replies_on_journal_id"
+ add_index "journal_replies", ["reply_id"], :name => "index_journal_replies_on_reply_id"
+ add_index "journal_replies", ["user_id"], :name => "index_journal_replies_on_user_id"
+
+ create_table "journals", :force => true do |t|
+ t.integer "journalized_id", :default => 0, :null => false
+ t.string "journalized_type", :limit => 30, :default => "", :null => false
+ t.integer "user_id", :default => 0, :null => false
+ t.text "notes"
+ t.datetime "created_on", :null => false
+ t.boolean "private_notes", :default => false, :null => false
+ end
+
+ add_index "journals", ["created_on"], :name => "index_journals_on_created_on"
+ add_index "journals", ["journalized_id", "journalized_type"], :name => "journals_journalized_id"
+ add_index "journals", ["journalized_id"], :name => "index_journals_on_journalized_id"
+ add_index "journals", ["user_id"], :name => "index_journals_on_user_id"
+
+ create_table "journals_for_messages", :force => true do |t|
+ t.integer "jour_id"
+ t.string "jour_type"
+ t.integer "user_id"
+ t.text "notes"
+ t.integer "status"
+ t.integer "reply_id"
+ t.datetime "created_on", :null => false
+ t.datetime "updated_on", :null => false
+ t.string "m_parent_id"
+ t.boolean "is_readed"
+ t.integer "m_reply_count"
+ t.integer "m_reply_id"
+ t.integer "is_comprehensive_evaluation"
+ end
+
+ create_table "member_roles", :force => true do |t|
+ t.integer "member_id", :null => false
+ t.integer "role_id", :null => false
+ t.integer "inherited_from"
+ end
+
+ add_index "member_roles", ["member_id"], :name => "index_member_roles_on_member_id"
+ add_index "member_roles", ["role_id"], :name => "index_member_roles_on_role_id"
+
+ create_table "members", :force => true do |t|
+ t.integer "user_id", :default => 0, :null => false
+ t.integer "project_id", :default => 0
+ t.datetime "created_on"
+ t.boolean "mail_notification", :default => false, :null => false
+ t.integer "course_id", :default => -1
+ end
+
+ add_index "members", ["project_id"], :name => "index_members_on_project_id"
+ add_index "members", ["user_id", "project_id", "course_id"], :name => "index_members_on_user_id_and_project_id", :unique => true
+ add_index "members", ["user_id"], :name => "index_members_on_user_id"
+
+ create_table "memos", :force => true do |t|
+ t.integer "forum_id", :null => false
+ t.integer "parent_id"
+ t.string "subject", :null => false
+ t.text "content", :null => false
+ t.integer "author_id", :null => false
+ t.integer "replies_count", :default => 0
+ t.integer "last_reply_id"
+ t.boolean "lock", :default => false
+ t.boolean "sticky", :default => false
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ t.integer "viewed_count", :default => 0
+ end
+
+ create_table "messages", :force => true do |t|
+ t.integer "board_id", :null => false
+ t.integer "parent_id"
+ t.string "subject", :default => "", :null => false
+ t.text "content"
+ t.integer "author_id"
+ t.integer "replies_count", :default => 0, :null => false
+ t.integer "last_reply_id"
+ t.datetime "created_on", :null => false
+ t.datetime "updated_on", :null => false
+ t.boolean "locked", :default => false
+ t.integer "sticky", :default => 0
+ end
+
+ add_index "messages", ["author_id"], :name => "index_messages_on_author_id"
+ add_index "messages", ["board_id"], :name => "messages_board_id"
+ add_index "messages", ["created_on"], :name => "index_messages_on_created_on"
+ add_index "messages", ["last_reply_id"], :name => "index_messages_on_last_reply_id"
+ add_index "messages", ["parent_id"], :name => "messages_parent_id"
+
+ create_table "news", :force => true do |t|
+ t.integer "project_id"
+ t.string "title", :limit => 60, :default => "", :null => false
+ t.string "summary", :default => ""
+ t.text "description"
+ t.integer "author_id", :default => 0, :null => false
+ t.datetime "created_on"
+ t.integer "comments_count", :default => 0, :null => false
+ t.integer "course_id"
+ end
+
+ add_index "news", ["author_id"], :name => "index_news_on_author_id"
+ add_index "news", ["created_on"], :name => "index_news_on_created_on"
+ add_index "news", ["project_id"], :name => "news_project_id"
+
+ create_table "no_uses", :force => true do |t|
+ t.integer "user_id", :null => false
+ t.string "no_use_type"
+ t.integer "no_use_id"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+ create_table "notificationcomments", :force => true do |t|
+ t.string "notificationcommented_type"
+ t.integer "notificationcommented_id"
+ t.integer "author_id"
+ t.text "notificationcomments"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+ create_table "open_id_authentication_associations", :force => true do |t|
+ t.integer "issued"
+ t.integer "lifetime"
+ t.string "handle"
+ t.string "assoc_type"
+ t.binary "server_url"
+ t.binary "secret"
+ end
+
+ create_table "open_id_authentication_nonces", :force => true do |t|
+ t.integer "timestamp", :null => false
+ t.string "server_url"
+ t.string "salt", :null => false
+ end
+
+ create_table "open_source_projects", :force => true do |t|
+ t.string "name"
+ t.text "description"
+ t.integer "commit_count", :default => 0
+ t.integer "code_line", :default => 0
+ t.integer "users_count", :default => 0
+ t.date "last_commit_time"
+ t.string "url"
+ t.date "date_collected"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+ create_table "option_numbers", :force => true do |t|
+ t.integer "user_id"
+ t.integer "memo"
+ t.integer "messages_for_issues"
+ t.integer "issues_status"
+ t.integer "replay_for_message"
+ t.integer "replay_for_memo"
+ t.integer "follow"
+ t.integer "tread"
+ t.integer "praise_by_one"
+ t.integer "praise_by_two"
+ t.integer "praise_by_three"
+ t.integer "tread_by_one"
+ t.integer "tread_by_two"
+ t.integer "tread_by_three"
+ t.integer "changeset"
+ t.integer "document"
+ t.integer "attachment"
+ t.integer "issue_done_ratio"
+ t.integer "post_issue"
+ t.integer "score_type"
+ t.integer "total_score"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ t.integer "project_id"
+ end
+
+ create_table "praise_tread_caches", :force => true do |t|
+ t.integer "object_id", :null => false
+ t.string "object_type"
+ t.integer "praise_num"
+ t.integer "tread_num"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+ create_table "praise_treads", :force => true do |t|
+ t.integer "user_id", :null => false
+ t.integer "praise_tread_object_id"
+ t.string "praise_tread_object_type"
+ t.integer "praise_or_tread"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+ create_table "project_infos", :force => true do |t|
+ t.integer "project_id"
+ t.integer "user_id"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+ create_table "project_scores", :force => true do |t|
+ t.string "project_id"
+ t.integer "score"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ t.integer "issue_num", :default => 0
+ t.integer "issue_journal_num", :default => 0
+ t.integer "news_num", :default => 0
+ t.integer "documents_num", :default => 0
+ t.integer "changeset_num", :default => 0
+ t.integer "board_message_num", :default => 0
+ end
+
+ create_table "project_statuses", :force => true do |t|
+ t.integer "changesets_count"
+ t.integer "watchers_count"
+ t.integer "project_id"
+ t.integer "project_type"
+ t.float "grade", :default => 0.0
+ t.integer "course_ac_para", :default => 0
+ end
+
+ add_index "project_statuses", ["grade"], :name => "index_project_statuses_on_grade"
+
+ create_table "projecting_softapplictions", :force => true do |t|
+ t.integer "user_id"
+ t.integer "softapplication_id"
+ t.integer "project_id"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+ create_table "projects", :force => true do |t|
+ t.string "name", :default => "", :null => false
+ t.text "description"
+ t.string "homepage", :default => ""
+ t.boolean "is_public", :default => true, :null => false
+ t.integer "parent_id"
+ t.datetime "created_on"
+ t.datetime "updated_on"
+ t.string "identifier"
+ t.integer "status", :default => 1, :null => false
+ t.integer "lft"
+ t.integer "rgt"
+ t.boolean "inherit_members", :default => false, :null => false
+ t.integer "project_type"
+ t.boolean "hidden_repo", :default => false, :null => false
+ t.integer "attachmenttype", :default => 1
+ t.integer "user_id"
+ t.integer "dts_test", :default => 0
+ end
+
+ add_index "projects", ["lft"], :name => "index_projects_on_lft"
+ add_index "projects", ["rgt"], :name => "index_projects_on_rgt"
+
+ create_table "projects_trackers", :id => false, :force => true do |t|
+ t.integer "project_id", :default => 0, :null => false
+ t.integer "tracker_id", :default => 0, :null => false
+ end
+
+ add_index "projects_trackers", ["project_id", "tracker_id"], :name => "projects_trackers_unique", :unique => true
+ add_index "projects_trackers", ["project_id"], :name => "projects_trackers_project_id"
+
+ create_table "queries", :force => true do |t|
+ t.integer "project_id"
+ t.string "name", :default => "", :null => false
+ t.text "filters"
+ t.integer "user_id", :default => 0, :null => false
+ t.boolean "is_public", :default => false, :null => false
+ t.text "column_names"
+ t.text "sort_criteria"
+ t.string "group_by"
+ t.string "type"
+ end
+
+ add_index "queries", ["project_id"], :name => "index_queries_on_project_id"
+ add_index "queries", ["user_id"], :name => "index_queries_on_user_id"
+
+ create_table "relative_memo_to_open_source_projects", :force => true do |t|
+ t.integer "osp_id"
+ t.integer "relative_memo_id"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+ create_table "relative_memos", :force => true do |t|
+ t.integer "osp_id"
+ t.integer "parent_id"
+ t.string "subject", :null => false
+ t.text "content", :limit => 16777215, :null => false
+ t.integer "author_id"
+ t.integer "replies_count", :default => 0
+ t.integer "last_reply_id"
+ t.boolean "lock", :default => false
+ t.boolean "sticky", :default => false
+ t.boolean "is_quote", :default => false
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ t.integer "viewed_count_crawl", :default => 0
+ t.integer "viewed_count_local", :default => 0
+ t.string "url"
+ t.string "username"
+ t.string "userhomeurl"
+ t.date "date_collected"
+ t.string "topic_resource"
+ end
+
+ create_table "repositories", :force => true do |t|
+ t.integer "project_id", :default => 0, :null => false
+ t.string "url", :default => "", :null => false
+ t.string "login", :limit => 60, :default => ""
+ t.string "password", :default => ""
+ t.string "root_url", :default => ""
+ t.string "type"
+ t.string "path_encoding", :limit => 64
+ t.string "log_encoding", :limit => 64
+ t.text "extra_info"
+ t.string "identifier"
+ t.boolean "is_default", :default => false
+ end
+
+ add_index "repositories", ["project_id"], :name => "index_repositories_on_project_id"
+
+ create_table "rich_rich_files", :force => true do |t|
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ t.string "rich_file_file_name"
+ t.string "rich_file_content_type"
+ t.integer "rich_file_file_size"
+ t.datetime "rich_file_updated_at"
+ t.string "owner_type"
+ t.integer "owner_id"
+ t.text "uri_cache"
+ t.string "simplified_type", :default => "file"
+ end
+
+ create_table "roles", :force => true do |t|
+ t.string "name", :limit => 30, :default => "", :null => false
+ t.integer "position", :default => 1
+ t.boolean "assignable", :default => true
+ t.integer "builtin", :default => 0, :null => false
+ t.text "permissions"
+ t.string "issues_visibility", :limit => 30, :default => "default", :null => false
+ end
+
+ create_table "schools", :force => true do |t|
+ t.string "name"
+ t.string "province"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ t.string "logo_link"
+ end
+
+ create_table "seems_rateable_cached_ratings", :force => true do |t|
+ t.integer "cacheable_id", :limit => 8
+ t.string "cacheable_type"
+ t.float "avg", :null => false
+ t.integer "cnt", :null => false
+ t.string "dimension"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+ create_table "seems_rateable_rates", :force => true do |t|
+ t.integer "rater_id", :limit => 8
+ t.integer "rateable_id"
+ t.string "rateable_type"
+ t.float "stars", :null => false
+ t.string "dimension"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+ create_table "settings", :force => true do |t|
+ t.string "name", :default => "", :null => false
+ t.text "value"
+ t.datetime "updated_on"
+ end
+
+ add_index "settings", ["name"], :name => "index_settings_on_name"
+
+ create_table "shares", :force => true do |t|
+ t.date "created_on"
+ t.string "url"
+ t.string "title"
+ t.integer "share_type"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ t.integer "project_id"
+ t.integer "user_id"
+ t.string "description"
+ end
+
+ create_table "softapplications", :force => true do |t|
+ t.string "name"
+ t.text "description"
+ t.integer "app_type_id"
+ t.string "app_type_name"
+ t.string "android_min_version_available"
+ t.integer "user_id"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ t.integer "contest_id"
+ t.integer "softapplication_id"
+ t.integer "is_public"
+ t.string "application_developers"
+ t.string "deposit_project_url"
+ t.string "deposit_project"
+ t.integer "project_id"
+ end
+
+ create_table "students_for_courses", :force => true do |t|
+ t.integer "student_id"
+ t.integer "course_id"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+ create_table "taggings", :force => true do |t|
+ t.integer "tag_id"
+ t.integer "taggable_id"
+ t.string "taggable_type"
+ t.integer "tagger_id"
+ t.string "tagger_type"
+ t.string "context", :limit => 128
+ t.datetime "created_at"
+ end
+
+ add_index "taggings", ["tag_id"], :name => "index_taggings_on_tag_id"
+ add_index "taggings", ["taggable_id", "taggable_type", "context"], :name => "index_taggings_on_taggable_id_and_taggable_type_and_context"
+ add_index "taggings", ["taggable_type"], :name => "index_taggings_on_taggable_type"
+
+ create_table "tags", :force => true do |t|
+ t.string "name"
+ end
+
+ create_table "teachers", :force => true do |t|
+ t.string "tea_name"
+ t.string "location"
+ t.integer "couurse_time"
+ t.integer "course_code"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ t.string "extra"
+ end
+
+ create_table "time_entries", :force => true do |t|
+ t.integer "project_id", :null => false
+ t.integer "user_id", :null => false
+ t.integer "issue_id"
+ t.float "hours", :null => false
+ t.string "comments"
+ t.integer "activity_id", :null => false
+ t.date "spent_on", :null => false
+ t.integer "tyear", :null => false
+ t.integer "tmonth", :null => false
+ t.integer "tweek", :null => false
+ t.datetime "created_on", :null => false
+ t.datetime "updated_on", :null => false
+ end
+
+ add_index "time_entries", ["activity_id"], :name => "index_time_entries_on_activity_id"
+ add_index "time_entries", ["created_on"], :name => "index_time_entries_on_created_on"
+ add_index "time_entries", ["issue_id"], :name => "time_entries_issue_id"
+ add_index "time_entries", ["project_id"], :name => "time_entries_project_id"
+ add_index "time_entries", ["user_id"], :name => "index_time_entries_on_user_id"
+
+ create_table "tokens", :force => true do |t|
+ t.integer "user_id", :default => 0, :null => false
+ t.string "action", :limit => 30, :default => "", :null => false
+ t.string "value", :limit => 40, :default => "", :null => false
+ t.datetime "created_on", :null => false
+ end
+
+ add_index "tokens", ["user_id"], :name => "index_tokens_on_user_id"
+ add_index "tokens", ["value"], :name => "tokens_value", :unique => true
+
+ create_table "trackers", :force => true do |t|
+ t.string "name", :limit => 30, :default => "", :null => false
+ t.boolean "is_in_chlog", :default => false, :null => false
+ t.integer "position", :default => 1
+ t.boolean "is_in_roadmap", :default => true, :null => false
+ t.integer "fields_bits", :default => 0
+ end
+
+ create_table "user_extensions", :force => true do |t|
+ t.integer "user_id", :null => false
+ t.date "birthday"
+ t.string "brief_introduction"
+ t.integer "gender"
+ t.string "location"
+ t.string "occupation"
+ t.integer "work_experience"
+ t.integer "zip_code"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ t.string "technical_title"
+ t.integer "identity"
+ t.string "student_id"
+ t.string "teacher_realname"
+ t.string "student_realname"
+ t.string "location_city"
+ t.integer "school_id"
+ end
+
+ create_table "user_grades", :force => true do |t|
+ t.integer "user_id", :null => false
+ t.integer "project_id", :null => false
+ t.float "grade", :default => 0.0
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+ add_index "user_grades", ["grade"], :name => "index_user_grades_on_grade"
+ add_index "user_grades", ["project_id"], :name => "index_user_grades_on_project_id"
+ add_index "user_grades", ["user_id"], :name => "index_user_grades_on_user_id"
+
+ create_table "user_levels", :force => true do |t|
+ t.integer "user_id"
+ t.integer "level"
+ end
+
+ create_table "user_preferences", :force => true do |t|
+ t.integer "user_id", :default => 0, :null => false
+ t.text "others"
+ t.boolean "hide_mail", :default => false
+ t.string "time_zone"
+ end
+
+ add_index "user_preferences", ["user_id"], :name => "index_user_preferences_on_user_id"
+
+ create_table "user_score_details", :force => true do |t|
+ t.integer "current_user_id"
+ t.integer "target_user_id"
+ t.string "score_type"
+ t.string "score_action"
+ t.integer "user_id"
+ t.integer "old_score"
+ t.integer "new_score"
+ t.integer "current_user_level"
+ t.integer "target_user_level"
+ t.integer "score_changeable_obj_id"
+ t.string "score_changeable_obj_type"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+ create_table "user_scores", :force => true do |t|
+ t.integer "user_id", :null => false
+ t.integer "collaboration"
+ t.integer "influence"
+ t.integer "skill"
+ t.integer "active"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+ create_table "user_statuses", :force => true do |t|
+ t.integer "changesets_count"
+ t.integer "watchers_count"
+ t.integer "user_id"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ t.float "grade", :default => 0.0
+ end
+
+ add_index "user_statuses", ["changesets_count"], :name => "index_user_statuses_on_changesets_count"
+ add_index "user_statuses", ["grade"], :name => "index_user_statuses_on_grade"
+ add_index "user_statuses", ["watchers_count"], :name => "index_user_statuses_on_watchers_count"
+
+ create_table "users", :force => true do |t|
+ t.string "login", :default => "", :null => false
+ t.string "hashed_password", :limit => 40, :default => "", :null => false
+ t.string "firstname", :limit => 30, :default => "", :null => false
+ t.string "lastname", :default => "", :null => false
+ t.string "mail", :limit => 60, :default => "", :null => false
+ t.boolean "admin", :default => false, :null => false
+ t.integer "status", :default => 1, :null => false
+ t.datetime "last_login_on"
+ t.string "language", :limit => 5, :default => ""
+ t.integer "auth_source_id"
+ t.datetime "created_on"
+ t.datetime "updated_on"
+ t.string "type"
+ t.string "identity_url"
+ t.string "mail_notification", :default => "", :null => false
+ t.string "salt", :limit => 64
+ end
+
+ add_index "users", ["auth_source_id"], :name => "index_users_on_auth_source_id"
+ add_index "users", ["id", "type"], :name => "index_users_on_id_and_type"
+ add_index "users", ["type"], :name => "index_users_on_type"
+
+ create_table "versions", :force => true do |t|
+ t.integer "project_id", :default => 0, :null => false
+ t.string "name", :default => "", :null => false
+ t.string "description", :default => ""
+ t.date "effective_date"
+ t.datetime "created_on"
+ t.datetime "updated_on"
+ t.string "wiki_page_title"
+ t.string "status", :default => "open"
+ t.string "sharing", :default => "none", :null => false
+ end
+
+ add_index "versions", ["project_id"], :name => "versions_project_id"
+ add_index "versions", ["sharing"], :name => "index_versions_on_sharing"
+
+ create_table "watchers", :force => true do |t|
+ t.string "watchable_type", :default => "", :null => false
+ t.integer "watchable_id", :default => 0, :null => false
+ t.integer "user_id"
+ end
+
+ add_index "watchers", ["user_id", "watchable_type"], :name => "watchers_user_id_type"
+ add_index "watchers", ["user_id"], :name => "index_watchers_on_user_id"
+ add_index "watchers", ["watchable_id", "watchable_type"], :name => "index_watchers_on_watchable_id_and_watchable_type"
+
+ create_table "web_footer_companies", :force => true do |t|
+ t.string "name"
+ t.string "logo_size"
+ t.string "url"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+ create_table "web_footer_oranizers", :force => true do |t|
+ t.string "name"
+ t.text "description"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+ create_table "wiki_content_versions", :force => true do |t|
+ t.integer "wiki_content_id", :null => false
+ t.integer "page_id", :null => false
+ t.integer "author_id"
+ t.binary "data", :limit => 2147483647
+ t.string "compression", :limit => 6, :default => ""
+ t.string "comments", :default => ""
+ t.datetime "updated_on", :null => false
+ t.integer "version", :null => false
+ end
+
+ add_index "wiki_content_versions", ["updated_on"], :name => "index_wiki_content_versions_on_updated_on"
+ add_index "wiki_content_versions", ["wiki_content_id"], :name => "wiki_content_versions_wcid"
+
+ create_table "wiki_contents", :force => true do |t|
+ t.integer "page_id", :null => false
+ t.integer "author_id"
+ t.text "text", :limit => 2147483647
+ t.string "comments", :default => ""
+ t.datetime "updated_on", :null => false
+ t.integer "version", :null => false
+ end
+
+ add_index "wiki_contents", ["author_id"], :name => "index_wiki_contents_on_author_id"
+ add_index "wiki_contents", ["page_id"], :name => "wiki_contents_page_id"
+
+ create_table "wiki_pages", :force => true do |t|
+ t.integer "wiki_id", :null => false
+ t.string "title", :null => false
+ t.datetime "created_on", :null => false
+ t.boolean "protected", :default => false, :null => false
+ t.integer "parent_id"
+ end
+
+ add_index "wiki_pages", ["parent_id"], :name => "index_wiki_pages_on_parent_id"
+ add_index "wiki_pages", ["wiki_id", "title"], :name => "wiki_pages_wiki_id_title"
+ add_index "wiki_pages", ["wiki_id"], :name => "index_wiki_pages_on_wiki_id"
+
+ create_table "wiki_redirects", :force => true do |t|
+ t.integer "wiki_id", :null => false
+ t.string "title"
+ t.string "redirects_to"
+ t.datetime "created_on", :null => false
+ end
+
+ add_index "wiki_redirects", ["wiki_id", "title"], :name => "wiki_redirects_wiki_id_title"
+ add_index "wiki_redirects", ["wiki_id"], :name => "index_wiki_redirects_on_wiki_id"
+
+ create_table "wikis", :force => true do |t|
+ t.integer "project_id", :null => false
+ t.string "start_page", :null => false
+ t.integer "status", :default => 1, :null => false
+ end
+
+ add_index "wikis", ["project_id"], :name => "wikis_project_id"
+
+ create_table "workflows", :force => true do |t|
+ t.integer "tracker_id", :default => 0, :null => false
+ t.integer "old_status_id", :default => 0, :null => false
+ t.integer "new_status_id", :default => 0, :null => false
+ t.integer "role_id", :default => 0, :null => false
+ t.boolean "assignee", :default => false, :null => false
+ t.boolean "author", :default => false, :null => false
+ t.string "type", :limit => 30
+ t.string "field_name", :limit => 30
+ t.string "rule", :limit => 30
+ end
+
+ add_index "workflows", ["new_status_id"], :name => "index_workflows_on_new_status_id"
+ add_index "workflows", ["old_status_id"], :name => "index_workflows_on_old_status_id"
+ add_index "workflows", ["role_id", "tracker_id", "old_status_id"], :name => "wkfs_role_tracker_old_status"
+ add_index "workflows", ["role_id"], :name => "index_workflows_on_role_id"
+
+ create_table "works_categories", :force => true do |t|
+ t.string "category"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
+ end
+
+end
From bdc38014acd3accecb54a250660942c9874ac36f Mon Sep 17 00:00:00 2001
From: alan <547533434@qq.com>
Date: Fri, 31 Oct 2014 14:55:52 +0800
Subject: [PATCH 05/18] =?UTF-8?q?=E4=BF=AE=E6=94=B9bug=E3=80=8A=E6=B5=8B?=
=?UTF-8?q?=E8=AF=95=E7=89=88=EF=BC=9A=E8=AF=BE=E7=A8=8B=E5=88=97=E8=A1=A8?=
=?UTF-8?q?--=E7=82=B9=E5=87=BB=E4=B8=AA=E5=88=AB=E8=AF=BE=E7=A8=8B?=
=?UTF-8?q?=E8=BF=94=E5=9B=9E500=E9=94=99=E8=AF=AF=E3=80=8B=20Signed-off-b?=
=?UTF-8?q?y:=20alan=20<547533434@qq.com>?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
db/migrate/20141031065238_change_data_for_courses.rb | 10 ++++++++++
db/schema.rb | 2 +-
2 files changed, 11 insertions(+), 1 deletion(-)
create mode 100644 db/migrate/20141031065238_change_data_for_courses.rb
diff --git a/db/migrate/20141031065238_change_data_for_courses.rb b/db/migrate/20141031065238_change_data_for_courses.rb
new file mode 100644
index 000000000..f3ee0ab54
--- /dev/null
+++ b/db/migrate/20141031065238_change_data_for_courses.rb
@@ -0,0 +1,10 @@
+#encoding=UTF-8
+class ChangeDataForCourses < ActiveRecord::Migration
+ def up
+ sql = "UPDATE courses set school_id = 117 where id =58"
+ execute(sql)
+ end
+
+ def down
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index ddeef8e19..957e603b7 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 20141030071656) do
+ActiveRecord::Schema.define(:version => 20141031065238) do
create_table "activities", :force => true do |t|
t.integer "act_id", :null => false
From 012db21b0dd12e341ff29d7d0242ec78e62effbd Mon Sep 17 00:00:00 2001
From: alan <547533434@qq.com>
Date: Fri, 31 Oct 2014 16:38:04 +0800
Subject: [PATCH 06/18] =?UTF-8?q?=E4=BF=AE=E6=94=B9bug<=E6=B5=8B=E8=AF=95?=
=?UTF-8?q?=E7=89=88--=E9=A1=B9=E7=9B=AE=E7=89=88--=E4=BD=9C=E5=93=81?=
=?UTF-8?q?=E4=B8=8B=E8=BD=BD=EF=BC=9A=E6=88=90=E5=8A=9F=E4=B8=8A=E4=BC=A0?=
=?UTF-8?q?=E6=9F=90=E4=BA=9B=E8=B5=84=E6=BA=90=EF=BC=8C=E6=AD=A3=E7=A1=AE?=
=?UTF-8?q?=E9=80=89=E6=8B=A9=E5=86=85=E5=AE=B9=E7=B1=BB=E5=9E=8B=EF=BC=8C?=
=?UTF-8?q?=E5=8D=B4=E5=B9=B6=E6=9C=AA=E6=AD=A3=E7=A1=AE=E6=98=BE=E7=A4=BA?=
=?UTF-8?q?=E7=9B=B8=E5=85=B3=E5=86=85=E5=AE=B9=E7=B1=BB=E5=9E=8B=E7=9A=84?=
=?UTF-8?q?=E8=B5=84=E6=BA=90>?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: alan <547533434@qq.com>
---
app/controllers/files_controller.rb | 1 +
app/views/files/_course_file.html.erb | 4 +++-
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/app/controllers/files_controller.rb b/app/controllers/files_controller.rb
index 8dd8ba93f..91176efdf 100644
--- a/app/controllers/files_controller.rb
+++ b/app/controllers/files_controller.rb
@@ -265,6 +265,7 @@ class FilesController < ApplicationController
'size' => "#{Attachment.table_name}.filesize",
'downloads' => "#{Attachment.table_name}.downloads"
sort=''
+
if params[:sort]
params[:sort].split(",").each do |sort_type|
order_by = sort_type.split(":")
diff --git a/app/views/files/_course_file.html.erb b/app/views/files/_course_file.html.erb
index a1dae9a33..9f476aba8 100644
--- a/app/views/files/_course_file.html.erb
+++ b/app/views/files/_course_file.html.erb
@@ -2,6 +2,7 @@
<% attachmenttypes = @course.attachmenttypes %>
<% sufixtypes = @course.contenttypes %>
+
<%= t(:label_user_course) %>资源共享区
@@ -49,7 +50,8 @@
<% if attachmenttypes.any? %>
- <%= select_tag "attachment_browse", content_tag(:option, l(:attachment_all), :value => '0') +options_from_collection_for_select(attachmenttypes, "id", "typeName"),
+ <%= select_tag "attachment_browse", content_tag(:option, l(:attachment_all), :value => '0' ) +options_from_collection_for_select(attachmenttypes, "id", "typeName", params[:type]),
+
:onchange => "course_attachmenttypes_searchex(this.value)" %>
<% end %>
<% if sufixtypes.any? %>
From cbc2d2e99d042ab6e18c1328c7feabde91ef586b Mon Sep 17 00:00:00 2001
From: alan <547533434@qq.com>
Date: Fri, 31 Oct 2014 16:50:29 +0800
Subject: [PATCH 07/18] =?UTF-8?q?=E4=BF=AE=E6=94=B9bug
?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: alan <547533434@qq.com>
---
app/views/courses/_join_private_course.html.erb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/views/courses/_join_private_course.html.erb b/app/views/courses/_join_private_course.html.erb
index 65dd04aa6..e3e75b9d7 100644
--- a/app/views/courses/_join_private_course.html.erb
+++ b/app/views/courses/_join_private_course.html.erb
@@ -62,8 +62,8 @@
-
- <%= l(:label_new_join) %>
- <%= l(:button_cancel)%>
+ <%= l(:label_new_join) %>
+ <%= l(:button_cancel)%>
<% end%>
From 9c4c1679afa3acd0f0692e6435411fd0d66e346f Mon Sep 17 00:00:00 2001
From: alan <547533434@qq.com>
Date: Fri, 31 Oct 2014 20:46:23 +0800
Subject: [PATCH 08/18] =?UTF-8?q?=E4=BF=AE=E6=94=B9bug<=E6=9C=89=E4=BA=9B?=
=?UTF-8?q?=E8=AF=BE=E7=A8=8Bschool=5Fid=3D0=20=E6=88=96=E4=B8=BA=E7=A9=BA?=
=?UTF-8?q?=E5=88=99=E8=AF=BE=E7=A8=8B=E8=BF=9B=E4=B8=8D=E5=8E=BB>=20Signe?=
=?UTF-8?q?d-off-by:=20alan=20<547533434@qq.com>?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/views/layouts/base_users.html.erb | 53 +++++++++++++++++--
app/views/my/account.html.erb | 6 +--
...41031122331_change_school_id_for_school.rb | 11 ++++
db/schema.rb | 2 +-
4 files changed, 65 insertions(+), 7 deletions(-)
create mode 100644 db/migrate/20141031122331_change_school_id_for_school.rb
diff --git a/app/views/layouts/base_users.html.erb b/app/views/layouts/base_users.html.erb
index 97d5fc47f..04501532d 100644
--- a/app/views/layouts/base_users.html.erb
+++ b/app/views/layouts/base_users.html.erb
@@ -21,6 +21,9 @@
<%= call_hook :view_layouts_base_html_head %>
<%= yield :header_tags -%>
+ <% title1 = @user.user_extensions.technical_title %>
+ <% language1 = @user.language %>
+
-
+
@@ -193,8 +240,8 @@
<%= l(:label_technical_title) %>:
|
-
<% end %>
diff --git a/app/views/my/account.html.erb b/app/views/my/account.html.erb
index 38f1e3b9f..fc712933c 100644
--- a/app/views/my/account.html.erb
+++ b/app/views/my/account.html.erb
@@ -61,7 +61,7 @@
- <%= f.text_field :login, :required => true, :name => "login"%>
+ <%= f.text_field :login, :required => true, :size => 25, :name => "login"%>
<%= l(:label_max_number) %>
@@ -69,13 +69,13 @@
- <%= f.text_field :lastname, :required => true %>
+ <%= f.text_field :lastname, :size => 25, :required => true %>
<%= l(:field_lastname_eg) %>
- <%= f.text_field :firstname, :required => true %>
+ <%= f.text_field :firstname, :size => 25, :required => true %>
<%= l(:field_firstname_eg) %>
diff --git a/db/migrate/20141031122331_change_school_id_for_school.rb b/db/migrate/20141031122331_change_school_id_for_school.rb
new file mode 100644
index 000000000..e042bd48e
--- /dev/null
+++ b/db/migrate/20141031122331_change_school_id_for_school.rb
@@ -0,0 +1,11 @@
+#encoding=UTF-8
+class ChangeSchoolIdForSchool < ActiveRecord::Migration
+ def up
+ sql = "update courses, user_extensions set courses.school_id = user_extensions.school_id
+ where courses.tea_id = user_extensions.user_id"
+ execute(sql)
+ end
+
+ def down
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 957e603b7..70ed2ce36 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 20141031065238) do
+ActiveRecord::Schema.define(:version => 20141031122331) do
create_table "activities", :force => true do |t|
t.integer "act_id", :null => false
From 12cf56d2010ad3a5b2007ca63434ef710ecff3c4 Mon Sep 17 00:00:00 2001
From: alan <547533434@qq.com>
Date: Fri, 31 Oct 2014 21:21:57 +0800
Subject: [PATCH 09/18] Signed-off-by: alan <547533434@qq.com>
---
.../20141030071656_add_data_for_school.rb | 52 +++++++++----------
.../20141031065238_change_data_for_courses.rb | 20 +++----
...41031122331_change_school_id_for_school.rb | 22 ++++----
3 files changed, 47 insertions(+), 47 deletions(-)
diff --git a/db/migrate/20141030071656_add_data_for_school.rb b/db/migrate/20141030071656_add_data_for_school.rb
index 71b600b16..94db0ea19 100644
--- a/db/migrate/20141030071656_add_data_for_school.rb
+++ b/db/migrate/20141030071656_add_data_for_school.rb
@@ -1,26 +1,26 @@
-#encoding=UTF-8
-class AddDataForSchool < ActiveRecord::Migration
- def up
- sql = " Insert into schools (name, province, logo_link) values
- ('香港大学','香港','/images/transparent.png'),
- ('香港大学','香港','/images/transparent.png'),
- ('香港中文大学','香港','/images/transparent.png'),
- ('香港科技大学','香港','/images/transparent.png'),('香港理工大学','香港','/images/transparent.png'),
- ('香港城市大学','香港','/images/transparent.png'),('香港浸会大学','香港','/images/transparent.png'),
- ('香港教育学院','香港','/images/transparent.png'),('香港歌德学院','香港','/images/transparent.png'),
- ('香港岭南大学','香港','/images/transparent.png'),('澳门大学','澳门','/images/transparent.png'),
- ('澳门理工学院','澳门','/images/transparent.png'),('澳门科技大学','澳门','/images/transparent.png'),
- ('澳门保安部队高等学校','澳门','/images/transparent.png'),('亚洲国际公开大学','澳门','/images/transparent.png'),
- ('澳门旅游学院','澳门','/images/transparent.png'),('清华大学(新竹)','台湾','/images/transparent.png'),
- ('台湾大学','台湾','/images/transparent.png'),('交通大学','台湾','/images/transparent.png'),
- ('中央大学','台湾','/images/transparent.png'),('成功大学','台湾','/images/transparent.png'),
- ('中山大学','台湾','/images/transparent.png'),('中原大学','台湾','/images/transparent.png'),
- ('政治大学','台湾','/images/transparent.png'),('元智大学','台湾','/images/transparent.png'),
- ('天主教辅仁大学','台湾','/images/transparent.png'),('台湾科技大学','台湾','/images/transparent.png'),
- ('台湾师范大学','台湾','/images/transparent.png'),('台湾艺术大学','台湾','/images/transparent.png')"
- execute(sql)
- end
-
- def down
- end
-end
+#encoding=UTF-8
+class AddDataForSchool < ActiveRecord::Migration
+ def up
+ sql = " Insert into schools (name, province, logo_link) values
+ ('香港大学','香港','/images/transparent.png'),
+ ('香港大学','香港','/images/transparent.png'),
+ ('香港中文大学','香港','/images/transparent.png'),
+ ('香港科技大学','香港','/images/transparent.png'),('香港理工大学','香港','/images/transparent.png'),
+ ('香港城市大学','香港','/images/transparent.png'),('香港浸会大学','香港','/images/transparent.png'),
+ ('香港教育学院','香港','/images/transparent.png'),('香港歌德学院','香港','/images/transparent.png'),
+ ('香港岭南大学','香港','/images/transparent.png'),('澳门大学','澳门','/images/transparent.png'),
+ ('澳门理工学院','澳门','/images/transparent.png'),('澳门科技大学','澳门','/images/transparent.png'),
+ ('澳门保安部队高等学校','澳门','/images/transparent.png'),('亚洲国际公开大学','澳门','/images/transparent.png'),
+ ('澳门旅游学院','澳门','/images/transparent.png'),('清华大学(新竹)','台湾','/images/transparent.png'),
+ ('台湾大学','台湾','/images/transparent.png'),('交通大学','台湾','/images/transparent.png'),
+ ('中央大学','台湾','/images/transparent.png'),('成功大学','台湾','/images/transparent.png'),
+ ('中山大学','台湾','/images/transparent.png'),('中原大学','台湾','/images/transparent.png'),
+ ('政治大学','台湾','/images/transparent.png'),('元智大学','台湾','/images/transparent.png'),
+ ('天主教辅仁大学','台湾','/images/transparent.png'),('台湾科技大学','台湾','/images/transparent.png'),
+ ('台湾师范大学','台湾','/images/transparent.png'),('台湾艺术大学','台湾','/images/transparent.png')"
+ execute(sql)
+ end
+
+ def down
+ end
+end
diff --git a/db/migrate/20141031065238_change_data_for_courses.rb b/db/migrate/20141031065238_change_data_for_courses.rb
index f3ee0ab54..d23e0343e 100644
--- a/db/migrate/20141031065238_change_data_for_courses.rb
+++ b/db/migrate/20141031065238_change_data_for_courses.rb
@@ -1,10 +1,10 @@
-#encoding=UTF-8
-class ChangeDataForCourses < ActiveRecord::Migration
- def up
- sql = "UPDATE courses set school_id = 117 where id =58"
- execute(sql)
- end
-
- def down
- end
-end
+#encoding=UTF-8
+class ChangeDataForCourses < ActiveRecord::Migration
+ def up
+ sql = "UPDATE courses set school_id = 117 where id =58"
+ execute(sql)
+ end
+
+ def down
+ end
+end
diff --git a/db/migrate/20141031122331_change_school_id_for_school.rb b/db/migrate/20141031122331_change_school_id_for_school.rb
index e042bd48e..e779b1a5b 100644
--- a/db/migrate/20141031122331_change_school_id_for_school.rb
+++ b/db/migrate/20141031122331_change_school_id_for_school.rb
@@ -1,11 +1,11 @@
-#encoding=UTF-8
-class ChangeSchoolIdForSchool < ActiveRecord::Migration
- def up
- sql = "update courses, user_extensions set courses.school_id = user_extensions.school_id
- where courses.tea_id = user_extensions.user_id"
- execute(sql)
- end
-
- def down
- end
-end
+#encoding=UTF-8
+class ChangeSchoolIdForSchool < ActiveRecord::Migration
+ def up
+ sql = "update courses, user_extensions set courses.school_id = user_extensions.school_id
+ where courses.tea_id = user_extensions.user_id"
+ execute(sql)
+ end
+
+ def down
+ end
+end
From 14ca7bcf9c7dbff2ab793e854015c2613b0647f1 Mon Sep 17 00:00:00 2001
From: alan <547533434@qq.com>
Date: Sat, 1 Nov 2014 16:57:20 +0800
Subject: [PATCH 10/18] =?UTF-8?q?=E4=BF=AE=E6=94=B9bug<=E9=A1=B9=E7=9B=AE-?=
=?UTF-8?q?-=E8=AE=A8=E8=AE=BA=E5=8C=BA=EF=BC=9A=E4=B8=8D=E7=99=BB?=
=?UTF-8?q?=E5=BD=95=E7=8A=B6=E6=80=81=E4=B8=8B=E8=AE=A8=E8=AE=BA=E5=8C=BA?=
=?UTF-8?q?=E7=9A=84=E5=B8=96=E5=AD=90=E6=98=AF=E4=B8=8D=E8=83=BD=E8=BF=9B?=
=?UTF-8?q?=E8=A1=8C=E5=9B=9E=E5=A4=8D=E7=AD=89=E6=93=8D=E4=BD=9C=E7=9A=84?=
=?UTF-8?q?=EF=BC=8C=E5=BB=BA=E8=AE=AE=E7=9B=B4=E6=8E=A5=E8=B7=B3=E8=BD=AC?=
=?UTF-8?q?=E5=88=B0=E7=99=BB=E5=BD=95=E7=AA=97=E5=8F=A3=E6=88=96=E7=BB=99?=
=?UTF-8?q?=E5=87=BA=E7=9B=B8=E5=85=B3=E6=8F=90=E7=A4=BA=E4=BF=A1=E6=81=AF?=
=?UTF-8?q?>=20Signed-off-by:=20alan=20<547533434@qq.com>?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/views/messages/_course_show.html.erb | 6 +++++-
app/views/messages/_project_show.html.erb | 6 +++++-
2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/app/views/messages/_course_show.html.erb b/app/views/messages/_course_show.html.erb
index 40094b162..f5c2a4211 100644
--- a/app/views/messages/_course_show.html.erb
+++ b/app/views/messages/_course_show.html.erb
@@ -106,7 +106,11 @@
<%= authoring @topic.created_on, @topic.author %>
- <%= toggle_link l(:button_reply), "reply", :focus => 'message_content' %>
+ <% if User.current.logged? %>
+ <%= toggle_link l(:button_reply), "reply", :focus => 'message_content' %>
+ <% else %>
+ <%= link_to l(:button_reply), signin_path %>
+ <% end %>
diff --git a/app/views/messages/_project_show.html.erb b/app/views/messages/_project_show.html.erb
index 98a1a5767..b0a593180 100644
--- a/app/views/messages/_project_show.html.erb
+++ b/app/views/messages/_project_show.html.erb
@@ -111,7 +111,11 @@
<%= authoring @topic.created_on, @topic.author %>
- <%= toggle_link l(:button_reply), "reply", :focus => 'message_content' %>
+ <% if User.current.logged? %>
+ <%= toggle_link l(:button_reply), "reply", :focus => 'message_content' %>
+ <% else %>
+ <%= link_to l(:button_reply), signin_path %>
+ <% end %>
From fecf9513b943c3cc8ffeef1d745330b3b366b831 Mon Sep 17 00:00:00 2001
From: alan <547533434@qq.com>
Date: Sat, 1 Nov 2014 23:30:10 +0800
Subject: [PATCH 11/18] =?UTF-8?q?=E4=BF=AE=E6=94=B9bug=E3=80=8A=E8=AF=BE?=
=?UTF-8?q?=E7=A8=8B=E8=AE=A8=E8=AE=BA=E5=8C=BA=E8=80=81=E5=B8=88=E4=B8=8D?=
=?UTF-8?q?=E8=83=BD=E7=BB=99=E5=B8=96=E5=AD=90=E7=BD=AE=E9=A1=B6=E3=80=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: alan <547533434@qq.com>
---
app/models/message.rb | 9 +-
app/models/user.rb | 2000 ++++++++++++++++++++---------------------
2 files changed, 1007 insertions(+), 1002 deletions(-)
diff --git a/app/models/message.rb b/app/models/message.rb
index 0fdfc5b15..8af3265cc 100644
--- a/app/models/message.rb
+++ b/app/models/message.rb
@@ -78,9 +78,13 @@ class Message < ActiveRecord::Base
safe_attributes 'subject', 'content'
- safe_attributes 'locked', 'sticky', 'board_id',
+ safe_attributes 'board_id','locked', 'sticky',
:if => lambda {|message, user|
- user.allowed_to?(:edit_messages, message.project)
+ if message.project
+ user.allowed_to?(:edit_messages, message.project)
+ else
+ user.allowed_to?(:edit_messages, message.course)
+ end
}
def visible?(user=User.current)
@@ -158,6 +162,7 @@ class Message < ActiveRecord::Base
#更新用户分数 -by zjc
def be_user_score
#新建message且无parent的为发帖
+
if self.parent_id.nil? && !self.board.project.nil?
UserScore.joint(:post_message, self.author,nil,self, { message_id: self.id })
update_memo_number(self.author,1)
diff --git a/app/models/user.rb b/app/models/user.rb
index 0bb359812..1e6c21c71 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -1,1000 +1,1000 @@
-# Redmine - project management software
-# Copyright (C) 2006-2013 Jean-Philippe Lang
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-require "digest/sha1"
-
-class User < Principal
- TEACHER = 0
- STUDENT = 1
- ENTERPRISE = 2
- DEVELOPER = 3
-
- include Redmine::SafeAttributes
-
- # Different ways of displaying/sorting users
- USER_FORMATS = {
- :firstname_lastname => {
- :string => '#{firstname} #{lastname}',
- :order => %w(firstname lastname id),
- :setting_order => 1
- },
- :firstname_lastinitial => {
- :string => '#{firstname} #{lastname.to_s.chars.first}.',
- :order => %w(firstname lastname id),
- :setting_order => 2
- },
- :firstname => {
- :string => '#{firstname}',
- :order => %w(firstname id),
- :setting_order => 3
- },
- :lastname_firstname => {
- :string => '#{lastname} #{firstname}',
- :order => %w(lastname firstname id),
- :setting_order => 4
- },
- :lastname_coma_firstname => {
- :string => '#{lastname}, #{firstname}',
- :order => %w(lastname firstname id),
- :setting_order => 5
- },
- :lastname => {
- :string => '#{lastname}',
- :order => %w(lastname id),
- :setting_order => 6
- },
- :username => {
- :string => '#{login}',
- :order => %w(login id),
- :setting_order => 7
- },
- }
-
- MAIL_NOTIFICATION_OPTIONS = [
- ['all', :label_user_mail_option_all],
- ['selected', :label_user_mail_option_selected],
- ['only_my_events', :label_user_mail_option_only_my_events],
- ['only_assigned', :label_user_mail_option_only_assigned],
- ['only_owner', :label_user_mail_option_only_owner],
- ['none', :label_user_mail_option_none]
- ]
-
- has_many :homework_users
- has_many :homework_attaches, :through => :homework_users
-
- has_and_belongs_to_many :groups, :after_add => Proc.new {|user, group| group.user_added(user)},
- :after_remove => Proc.new {|user, group| group.user_removed(user)}
- has_many :changesets, :dependent => :nullify
- has_one :preference, :dependent => :destroy, :class_name => 'UserPreference'
- has_one :rss_token, :class_name => 'Token', :conditions => "action='feeds'"
- has_one :api_token, :class_name => 'Token', :conditions => "action='api'"
- belongs_to :auth_source
- belongs_to :ucourse, :class_name => 'Course', :foreign_key => :id #huang
-## added by xianbo for delete
- has_many :biding_projects, :dependent => :destroy
- has_many :contesting_projects, :dependent => :destroy
- belongs_to :softapplication, :foreign_key => 'id', :dependent => :destroy
-##ended by xianbo
-
-#####fq
- has_many :jours, :class_name => 'JournalsForMessage', :dependent => :destroy
- has_many :journals_messages, :class_name => 'JournalsForMessage', :foreign_key => "user_id", :dependent => :destroy
- has_many :bids, :foreign_key => 'author_id', :dependent => :destroy
- has_many :contests, :foreign_key => 'author_id', :dependent => :destroy
- has_many :softapplications, :foreign_key => 'user_id', :dependent => :destroy
- has_many :journals_for_messages, :as => :jour, :dependent => :destroy
- has_many :new_jours, :as => :jour, :class_name => 'JournalsForMessage', :conditions => "status=1"
- has_many :journal_replies, :dependent => :destroy
- has_many :activities, :dependent => :destroy
- has_many :students_for_courses
- #has_many :courses, :through => :students_for_courses, :source => :project
- has_many :acts, :class_name => 'Activity', :as => :act, :dependent => :destroy
- has_many :file_commit, :class_name => 'Attachment', :foreign_key => 'author_id', :conditions => "container_type = 'Project' or container_type = 'Version'"
-####
-# added by bai
- has_many :join_in_contests, :dependent => :destroy
- has_many :news, :foreign_key => 'author_id'
- has_many :contestnotification, :foreign_key => 'author_id'
- has_many :comments, :foreign_key => 'author_id'
- has_many :notificationcomments, :foreign_key => 'author_id'
- has_many :wiki_contents, :foreign_key => 'author_id'
- has_many :journals
- has_many :messages, :foreign_key => 'author_id'
- has_one :user_score, :dependent => :destroy
- has_many :documents # 项目中关联的文档再次与人关联
-# end
-
-######added by nie
- has_many :project_infos, :dependent => :destroy
- has_one :user_status, :dependent => :destroy
- #####
- has_many :shares ,:dependent => :destroy
-
- # add by zjc
- has_one :level, :class_name => 'UserLevels', :dependent => :destroy
- has_many :memos , :foreign_key => 'author_id'
- #####
- scope :logged, lambda { where("#{User.table_name}.status <> #{STATUS_ANONYMOUS}") }
- scope :status, lambda {|arg| where(arg.blank? ? nil : {:status => arg.to_i}) }
- scope :visible, lambda {|*args|
- nil
- }
-
-
- acts_as_customizable
- ############################added by william
- acts_as_taggable
- scope :by_join_date, order("created_on DESC")
- ############################# added by liuping 关注
- acts_as_watchable
- seems_rateable_rater
- has_one :user_extensions,:dependent => :destroy
- ## end
-
- # default_scope -> { includes(:user_extensions, :user_score) }
- scope :teacher, -> {
- joins(:user_extensions).where('user_extensions.identity = ?', UserExtensions::TEACHER)
- }
- scope :student, -> {
- joins(:user_extensions).where('user_extensions.identity = ?', UserExtensions::STUDENT)
- }
- scope :developer, -> {
- joins(:user_extensions).where('user_extensions.identity = ?', UserExtensions::DEVELOPER)
- }
- scope :enterprise, -> {
- joins(:user_extensions).where('user_extensions.identity = ?', UserExtensions::ENTERPRISE)
- }
-
- attr_accessor :password, :password_confirmation
- attr_accessor :last_before_login_on
- # Prevents unauthorized assignments
- attr_protected :login, :admin, :password, :password_confirmation, :hashed_password
-
- LOGIN_LENGTH_LIMIT = 25
- MAIL_LENGTH_LIMIT = 60
-
- validates_presence_of :login, :mail, :if => Proc.new { |user| !user.is_a?(AnonymousUser) }
- validates_uniqueness_of :login, :if => Proc.new { |user| user.login_changed? && user.login.present? }, :case_sensitive => false
- validates_uniqueness_of :mail, :if => Proc.new { |user| user.mail_changed? && user.mail.present? }, :case_sensitive => false
- # Login must contain letters, numbers, underscores only
- validates_format_of :login, :with => /\A[a-z0-9_\-@\.]*\z/i
- validates_length_of :login, :maximum => LOGIN_LENGTH_LIMIT
- validates_length_of :firstname, :maximum => 30
- validates_length_of :lastname, :maximum => 30
- validates_format_of :mail, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, :allow_blank => true
- validates_length_of :mail, :maximum => MAIL_LENGTH_LIMIT, :allow_nil => true
- validates_confirmation_of :password, :allow_nil => true
- validates_inclusion_of :mail_notification, :in => MAIL_NOTIFICATION_OPTIONS.collect(&:first), :allow_blank => true
- validate :validate_password_length
-
- before_create :set_mail_notification
- before_save :update_hashed_password
- before_destroy :remove_references_before_destroy
- # added by fq
- after_create :act_as_activity
- # end
-
- scope :in_group, lambda {|group|
- group_id = group.is_a?(Group) ? group.id : group.to_i
- where("#{User.table_name}.id IN (SELECT gu.user_id FROM #{table_name_prefix}groups_users#{table_name_suffix} gu WHERE gu.group_id = ?)", group_id)
- }
- scope :not_in_group, lambda {|group|
- group_id = group.is_a?(Group) ? group.id : group.to_i
- 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 :like, lambda {|arg|
- if arg.blank?
- where(nil)
- else
- pattern = "%#{arg.to_s.strip.downcase}%"
- #where(" LOWER(concat(lastname, firstname)) LIKE :p ", :p => pattern)
- where(" LOWER(login) LIKE :p ", :p => pattern)
- end
- }
-
-
- # ======================================================================
-
- def extensions
- self.user_extensions ||= UserExtensions.new
- end
-
- def user_score_attr
- self.user_score ||= UserScore.new
- end
-
- # ======================================================================
-
- #选择项目成员时显示的用户信息文字
- def userInfo
- info=self.nickname + ' (' + self.realname + ')';
- end
-
- ###添加留言 fq
- def add_jour(user, notes, reference_user_id = 0, options = {})
- if options.count == 0
- self.journals_for_messages << JournalsForMessage.new(:user_id => user.id, :notes => notes, :reply_id => reference_user_id, :status => true)
- else
- jfm = self.journals_for_messages.build(options)
- jfm.save
- jfm
- end
- end
-
- # 判断用户是否加入了竞赛中 fq
- def join_in_contest?(bid)
- joined = JoinInContest.where('user_id = ? and bid_id =?', self.id, bid.id)
- if joined.size > 0
- true
- else
- false
- end
- end
-
- ### fq
- def join_in?(course)
- joined = StudentsForCourse.where('student_id = ? and course_id = ?', self.id, course.id)
- if joined.size > 0
- true
- else
- false
- end
- end
-
- def show_name
- unless self.user_extensions.nil?
- if self.user_extensions.identity == 2
- firstname
- else
- lastname+firstname
- end
- else
- lastname+firstname
- end
- end
- ## end
-
- def count_new_jour
- count = self.new_jours.count
- end
-
- #added by nie
- def count_new_journal_reply
- count = self.journal_reply.count
- end
-
- def set_mail_notification
- ##add byxianbo
- thread=Thread.new do
- self.mail_notification = Setting.default_notification_option if self.mail_notification.blank?
- true
- end
- end
-
- def update_hashed_password
- # update hashed_password if password was set
- if self.password && self.auth_source_id.blank?
- salt_password(password)
- end
- end
-
- alias :base_reload :reload
- def reload(*args)
- @name = nil
- @projects_by_role = nil
- @courses_by_role = nil
- @membership_by_project_id = nil
- base_reload(*args)
- end
-
- def mail=(arg)
- write_attribute(:mail, arg.to_s.strip)
- end
-
- def identity_url=(url)
- if url.blank?
- write_attribute(:identity_url, '')
- else
- begin
- write_attribute(:identity_url, OpenIdAuthentication.normalize_identifier(url))
- rescue OpenIdAuthentication::InvalidOpenId
- # Invalid url, don't save
- end
- end
- self.read_attribute(:identity_url)
- end
-
- VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i
- # VALID_EMAIL_REGEX = /^[0-9a-zA-Z_-]+@[0-9a-zA-Z_-]+(\.[0-9a-zA-Z_-]+)+$/
- # Returns the user that matches provided login and password, or nil
- #登录,返回用户名与密码匹配的用户
- def self.try_to_login(login, password)
- login = login.to_s.lstrip.rstrip
- password = password.to_s
-
- # Make sure no one can sign in with an empty login or password
- return nil if login.empty? || password.empty?
- if (login =~ VALID_EMAIL_REGEX)
- user = find_by_mail(login)
- else
- user = find_by_login(login)
- end
- if user
- # user is already in local database
- #return nil unless user.active?
- return nil unless user.check_password?(password)
- else
- # user is not yet registered, try to authenticate with available sources
- attrs = AuthSource.authenticate(login, password)
- if attrs
- user = new(attrs)
- user.login = login
- user.language = Setting.default_language
- if user.save
- user.reload
- logger.info("User '#{user.login}' created from external auth source: #{user.auth_source.type} - #{user.auth_source.name}") if logger && user.auth_source
- end
- end
- end
- user.update_column(:last_login_on, Time.now) if user && !user.new_record?
- user
- rescue => text
- raise text
- end
-
- # Returns the user who matches the given autologin +key+ or nil
- def self.try_to_autologin(key)
- user = Token.find_active_user('autologin', key, Setting.autologin.to_i)
- if user
- user.update_column(:last_login_on, Time.now)
- user
- end
- end
-
- def self.name_formatter(formatter = nil)
- USER_FORMATS[formatter || Setting.user_format] || USER_FORMATS[:firstname_lastname]
- end
-
- # Returns an array of fields names than can be used to make an order statement for users
- # according to how user names are displayed
- # Examples:
- #
- # User.fields_for_order_statement => ['users.login', 'users.id']
- # User.fields_for_order_statement('authors') => ['authors.login', 'authors.id']
- def self.fields_for_order_statement(table=nil)
- table ||= table_name
- name_formatter[:order].map {|field| "#{table}.#{field}"}
- end
-
- # Return user's full name for display
- def realname(formatter = nil)
- f = self.class.name_formatter(formatter)
- if formatter
- eval('"' + f[:string] + '"')
- else
- @name ||= eval('"' + f[:string] + '"')
- end
- end
-
- def nickname(formatter = nil)
- login
- end
-
- def name(formatter = nil)
- login
- end
-
- def active?
- self.status == STATUS_ACTIVE
- end
-
- def registered?
- self.status == STATUS_REGISTERED
- end
-
- def locked?
- self.status == STATUS_LOCKED
- end
-
- def activate
- self.status = STATUS_ACTIVE
- end
-
- def register
- self.status = STATUS_REGISTERED
- end
-
- def lock
- self.status = STATUS_LOCKED
- end
-
- def activate!
- update_attribute(:status, STATUS_ACTIVE)
- end
-
- def register!
- update_attribute(:status, STATUS_REGISTERED)
- end
-
- def lock!
- update_attribute(:status, STATUS_LOCKED)
- end
-
- # Returns true if +clear_password+ is the correct user's password, otherwise false
- def check_password?(clear_password)
- if auth_source_id.present?
- auth_source.authenticate(self.login, clear_password)
- else
- User.hash_password("#{salt}#{User.hash_password clear_password}") == hashed_password
- end
- end
-
- # Generates a random salt and computes hashed_password for +clear_password+
- # The hashed password is stored in the following form: SHA1(salt + SHA1(password))
- def salt_password(clear_password)
- self.salt = User.generate_salt
- self.hashed_password = User.hash_password("#{salt}#{User.hash_password clear_password}")
- end
-
- # Does the backend storage allow this user to change their password?
- def change_password_allowed?
- return true if auth_source.nil?
- return auth_source.allow_password_changes?
- end
-
- # Generate and set a random password. Useful for automated user creation
- # Based on Token#generate_token_value
- #
- def random_password
- chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
- password = ''
- 40.times { |i| password << chars[rand(chars.size-1)] }
- self.password = password
- self.password_confirmation = password
- self
- end
-
- def pref
- self.preference ||= UserPreference.new(:user => self)
- end
-
- def time_zone
- @time_zone ||= (self.pref.time_zone.blank? ? nil : ActiveSupport::TimeZone[self.pref.time_zone])
- end
-
- def wants_comments_in_reverse_order?
- self.pref[:comments_sorting] == 'desc'
- end
-
- def wants_notificationcomments_in_reverse_order?
- self.pref[:notificationcomments_sorting] == 'desc'
- end
- # Return user's RSS key (a 40 chars long string), used to access feeds
- def rss_key
- if rss_token.nil?
- create_rss_token(:action => 'feeds')
- end
- rss_token.value
- end
-
- # Return user's API key (a 40 chars long string), used to access the API
- def api_key
- if api_token.nil?
- create_api_token(:action => 'api')
- end
- api_token.value
- end
-
- # Return an array of project ids for which the user has explicitly turned mail notifications on
- def notified_projects_ids
- @notified_projects_ids ||= memberships.select {|m| m.mail_notification?}.collect(&:project_id)
- end
-
- def notified_project_ids=(ids)
- Member.update_all("mail_notification = #{connection.quoted_false}", ['user_id = ?', id])
- Member.update_all("mail_notification = #{connection.quoted_true}", ['user_id = ? AND project_id IN (?)', id, ids]) if ids && !ids.empty?
- @notified_projects_ids = nil
- notified_projects_ids
- end
-
- def valid_notification_options
- self.class.valid_notification_options(self)
- end
-
- # Only users that belong to more than 1 project can select projects for which they are notified
- def self.valid_notification_options(user=nil)
- # Note that @user.membership.size would fail since AR ignores
- # :include association option when doing a count
- if user.nil? || user.memberships.length < 1
- MAIL_NOTIFICATION_OPTIONS.reject {|option| option.first == 'selected'}
- else
- MAIL_NOTIFICATION_OPTIONS
- end
- end
-
- # Find a user account by matching the exact login and then a case-insensitive
- # version. Exact matches will be given priority.
- #通过用户名查找相应的用户,若没有匹配到,则不区分大小写进行查询
- #修改:不再匹配不区分大小写情况 -zjc
- def self.find_by_login(login)
- if login.present?
- login = login.to_s
- # First look for an exact match
- user = where(:login => login).all.detect {|u| u.login == login}
- #unless user
- # # Fail over to case-insensitive if none was found
- # user = where("LOWER(login) = ?", login.downcase).first
- #end
- user
- end
- end
-
- def self.find_by_rss_key(key)
- Token.find_active_user('feeds', key)
- end
-
- def self.find_by_api_key(key)
- Token.find_active_user('api', key)
- end
-
- # Makes find_by_mail case-insensitive
- def self.find_by_mail(mail)
- where("LOWER(mail) = ?", mail.to_s.downcase).first
- end
-
- # Returns true if the default admin account can no longer be used
- def self.default_admin_account_changed?
- !User.active.find_by_login("admin").try(:check_password?, "admin")
- end
-
- def to_s
- name
- end
-
- CSS_CLASS_BY_STATUS = {
- STATUS_ANONYMOUS => 'anon',
- STATUS_ACTIVE => 'active',
- STATUS_REGISTERED => 'registered',
- STATUS_LOCKED => 'locked'
- }
-
- def css_classes
- "user #{CSS_CLASS_BY_STATUS[status]}"
- end
-
- # Returns the current day according to user's time zone
- def today
- if time_zone.nil?
- Date.today
- else
- Time.now.in_time_zone(time_zone).to_date
- end
- end
-
- # Returns the day of +time+ according to user's time zone
- def time_to_date(time)
- if time_zone.nil?
- time.to_date
- else
- time.in_time_zone(time_zone).to_date
- end
- end
-
- def logged?
- true
- end
-
- def anonymous?
- !logged?
- end
-
- # Returns user's membership for the given project
- # or nil if the user is not a member of project
- def membership(project)
- project_id = project.is_a?(Project) ? project.id : project
-
- @membership_by_project_id ||= Hash.new {|h, project_id|
- h[project_id] = memberships.where(:project_id => project_id).first
- }
- @membership_by_project_id[project_id]
- end
-
- def coursemembership(course)
- course_id = course.is_a?(Course) ? course.id : course
-
- @membership_by_course_id ||= Hash.new {|h, course_id|
- h[course_id] = coursememberships.where(:course_id => course_id).first
- }
- @membership_by_course_id[course_id]
- end
-
- # Return user's roles for project
- def roles_for_project(project)
- roles = []
- # No role on archived projects
- return roles if project.nil? || project.archived?
- if logged?
- # Find project membership
- membership = membership(project)
- if membership
- roles = membership.roles
- else
- @role_non_member ||= Role.non_member
- roles << @role_non_member
- end
- else
- @role_anonymous ||= Role.anonymous
- roles << @role_anonymous
- end
- roles
- end
-
- # 用户课程权限判断
- def roles_for_course(course)
- roles = []
- # No role on archived courses
- return roles if course.nil? || course.archived?
- if logged?
- # Find course membership
- membership = coursemembership(course)
- if membership
- roles = membership.roles
- else
- @role_non_member ||= Role.non_member
- roles << @role_non_member
- end
- else
- @role_anonymous ||= Role.anonymous
- roles << @role_anonymous
- end
- roles
- end
-
- # Return true if the user is a member of project
- def member_of?(project)
- projects.to_a.include?(project)
- end
-
- def member_of_course?(course)
- courses.to_a.include?(course)
- end
-
- # Returns a hash of user's projects grouped by roles
- def projects_by_role
- return @projects_by_role if @projects_by_role
-
- @projects_by_role = Hash.new([])
- memberships.each do |membership|
- if membership.project
- membership.roles.each do |role|
- @projects_by_role[role] = [] unless @projects_by_role.key?(role)
- @projects_by_role[role] << membership.project
- end
- end
- end
- @projects_by_role.each do |role, projects|
- projects.uniq!
- end
-
- @projects_by_role
- end
-
- # 课程的角色权限
- def courses_by_role
- return @courses_by_role if @courses_by_role
-
- @courses_by_role = Hash.new([])
- coursememberships.each do |membership|
- if membership.course
- membership.roles.each do |role|
- @courses_by_role[role] = [] unless @courses_by_role.key?(role)
- @courses_by_role[role] << membership.course
- end
- end
- end
- @courses_by_role.each do |role, courses|
- courses.uniq!
- end
-
- @courses_by_role
- end
- # Returns true if user is arg or belongs to arg
- def is_or_belongs_to?(arg)
- if arg.is_a?(User)
- self == arg
- elsif arg.is_a?(Group)
- arg.users.include?(self)
- else
- false
- end
- end
-
-
- # Return true if the user is allowed to do the specified action on a specific context
- # Action can be:
- # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')
- # * a permission Symbol (eg. :edit_project)
- # Context can be:
- # * a project : returns true if user is allowed to do the specified action on this project
- # * an array of projects : returns true if user is allowed on every project
- # * nil with options[:global] set : check if user has at least one role allowed for this action,
- # or falls back to Non Member / Anonymous permissions depending if the user is logged
- def allowed_to?(action, context, options={}, &block)
- if context && context.is_a?(Project)
- return false unless context.allows_to?(action)
- # Admin users are authorized for anything else
- return true if admin?
-
- roles = roles_for_project(context)
- return false unless roles
- roles.any? {|role|
- (context.is_public? || role.member?) &&
- role.allowed_to?(action) &&
- (block_given? ? yield(role, self) : true)
- }
- #添加课程相关的权限判断
- elsif context && context.is_a?(Course)
- return false unless context.allows_to?(action)
- # Admin users are authorized for anything else
- return true if admin?
-
- roles = roles_for_course(context)
- return false unless roles
- roles.any? {|role|
- (context.is_public? || role.member?) &&
- role.allowed_to?(action) &&
- (block_given? ? yield(role, self) : true)
- }
- elsif context && context.is_a?(Array)
- if context.empty?
- false
- else
- # Authorize if user is authorized on every element of the array
- context.map {|project| allowed_to?(action, project, options, &block)}.reduce(:&)
- end
- elsif options[:global]
- # Admin users are always authorized
- return true if admin?
-
- # authorize if user has at least one role that has this permission
- roles = memberships.collect {|m| m.roles}.flatten.uniq
- if roles.count == 0
- roles = coursememberships.collect {|m| m.roles}.flatten.uniq
- end
- roles << (self.logged? ? Role.non_member : Role.anonymous)
- roles.any? {|role|
- role.allowed_to?(action) &&
- (block_given? ? yield(role, self) : true)
- }
- else
- if admin?
- return true
- end
- #无项目时 查看Non member(id为1)角色是否有权限执行action
- Role.find('1').allowed_to?(action)
- # false
- end
- end
-
- # Is the user allowed to do the specified action on any project?
- # See allowed_to? for the actions and valid options.
- def allowed_to_globally?(action, options, &block)
- allowed_to?(action, nil, options.reverse_merge(:global => true), &block)
- end
-
- # Returns true if the user is allowed to delete his own account
- def own_account_deletable?
- Setting.unsubscribe? &&
- (!admin? || User.active.where("admin = ? AND id <> ?", true, id).exists?)
- end
-
- safe_attributes 'login',
- 'firstname',
- 'lastname',
- 'mail',
- 'mail_notification',
- 'language',
- 'custom_field_values',
- 'custom_fields',
- 'identity_url'
-
- safe_attributes 'status',
- 'auth_source_id',
- :if => lambda {|user, current_user| current_user.admin?}
-
- safe_attributes 'group_ids',
- :if => lambda {|user, current_user| current_user.admin? && !user.new_record?}
-
- # Utility method to help check if a user should be notified about an
- # event.
- #
- # TODO: only supports Issue events currently
- def notify_about?(object)
- if mail_notification == 'all'
- true
- elsif mail_notification.blank? || mail_notification == 'none'
- false
- else
- case object
- when Issue
- case mail_notification
- when 'selected', 'only_my_events'
- # user receives notifications for created/assigned issues on unselected projects
- object.author == self || is_or_belongs_to?(object.assigned_to) || is_or_belongs_to?(object.assigned_to_was)
- when 'only_assigned'
- is_or_belongs_to?(object.assigned_to) || is_or_belongs_to?(object.assigned_to_was)
- when 'only_owner'
- object.author == self
- end
- when News
- # always send to project members except when mail_notification is set to 'none'
- true
- #判定用户是否接受留言提醒邮件
- when JournalsForMessage
- ##如果是直接留言并且留言对象是Project并且Project类型是课程(课程留言)
- if !object.at_user && object.jour.class.to_s.to_sym == :Project && object.jour.project_type == 1
- #根据用户设置邮件接收模式判定当前用户是否接受邮件提醒
- is_notified_project object.jour
- end
-
- end
- end
- end
-
- #用户是否接收project的消息提醒
- def is_notified_project arg
- if arg.is_a?(Project)
- case mail_notification
- when 'selected'
- notified_projects_ids.include?(arg.id)
- when 'only_my_events'
- projects.include?(arg)
- when 'only_assigned'
- false
- when 'only_owner'
- course = Course.find_by_extra(arg.identifier)
- course.teacher == self
- end
- #勾选的项目或用户的项目 TODO:需改
- #notified_projects_ids.include?(arg) || projects.include?(arg)
- else
- false
- end
- end
-
- def self.current=(user)
- Thread.current[:current_user] = user
- end
-
- def self.current
- Thread.current[:current_user] ||= User.anonymous
- end
-
- # Returns the anonymous user. If the anonymous user does not exist, it is created. There can be only
- # one anonymous user per database.
- def self.anonymous
- anonymous_user = AnonymousUser.first
- if anonymous_user.nil?
- anonymous_user = AnonymousUser.create(:lastname => 'Anonymous', :firstname => '', :mail => '', :login => '', :status => 0)
- raise 'Unable to create the anonymous user.' if anonymous_user.new_record?
- end
- anonymous_user
- end
-
- # Salts all existing unsalted passwords
- # It changes password storage scheme from SHA1(password) to SHA1(salt + SHA1(password))
- # This method is used in the SaltPasswords migration and is to be kept as is
- def self.salt_unsalted_passwords!
- transaction do
- User.where("salt IS NULL OR salt = ''").find_each do |user|
- next if user.hashed_password.blank?
- salt = User.generate_salt
- hashed_password = User.hash_password("#{salt}#{user.hashed_password}")
- User.where(:id => user.id).update_all(:salt => salt, :hashed_password => hashed_password)
- end
- end
- end
-
- protected
-
- def validate_password_length
- # Password length validation based on setting
- if !password.nil? && password.size < Setting.password_min_length.to_i
- errors.add(:password, :too_short, :count => Setting.password_min_length.to_i)
- end
- end
- private
-
- def act_as_activity
- self.acts << Activity.new(:user_id => self.id)
- end
-
- # Removes references that are not handled by associations
- # Things that are not deleted are reassociated with the anonymous user
- def remove_references_before_destroy
- return if self.id.nil?
-
- substitute = User.anonymous
- Attachment.update_all ['author_id = ?', substitute.id], ['author_id = ?', id]
- Comment.update_all ['author_id = ?', substitute.id], ['author_id = ?', id]
- Notificationcomment.update_all ['author_id = ?', substitute.id], ['author_id = ?', id]
- Issue.update_all ['author_id = ?', substitute.id], ['author_id = ?', id]
- Issue.update_all 'assigned_to_id = NULL', ['assigned_to_id = ?', id]
- Journal.update_all ['user_id = ?', substitute.id], ['user_id = ?', id]
- JournalDetail.update_all ['old_value = ?', substitute.id.to_s], ["property = 'attr' AND prop_key = 'assigned_to_id' AND old_value = ?", id.to_s]
- JournalDetail.update_all ['value = ?', substitute.id.to_s], ["property = 'attr' AND prop_key = 'assigned_to_id' AND value = ?", id.to_s]
- Message.update_all ['author_id = ?', substitute.id], ['author_id = ?', id]
- News.update_all ['author_id = ?', substitute.id], ['author_id = ?', id]
- # Remove private queries and keep public ones
- ::Query.delete_all ['user_id = ? AND is_public = ?', id, false]
- ::Query.update_all ['user_id = ?', substitute.id], ['user_id = ?', id]
- TimeEntry.update_all ['user_id = ?', substitute.id], ['user_id = ?', id]
- Token.delete_all ['user_id = ?', id]
- Watcher.delete_all ['user_id = ?', id]
- WikiContent.update_all ['author_id = ?', substitute.id], ['author_id = ?', id]
- WikiContent::Version.update_all ['author_id = ?', substitute.id], ['author_id = ?', id]
- end
-
- # Return password digest
- def self.hash_password(clear_password)
- Digest::SHA1.hexdigest(clear_password || "")
- end
-
- # Returns a 128bits random salt as a hex string (32 chars long)
- def self.generate_salt
- Redmine::Utils.random_hex(16)
- end
-
-
-
-end
-
-class AnonymousUser < User
- validate :validate_anonymous_uniqueness, :on => :create
-
- def validate_anonymous_uniqueness
- # There should be only one AnonymousUser in the database
- errors.add :base, 'An anonymous user already exists.' if AnonymousUser.exists?
- end
-
- def available_custom_fields
- []
- end
-
- # Overrides a few properties
- def logged?; false end
- def admin; false end
- def name(*args); I18n.t(:label_user_anonymous) end
- def mail; nil end
- def time_zone; nil end
- def rss_key; nil end
-
- def pref
- UserPreference.new(:user => self)
- end
-
- # def member_of?(project)
- # false
- # end
-
- # Anonymous user can not be destroyed
- def destroy
- false
- end
-end
+# Redmine - project management software
+# Copyright (C) 2006-2013 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+require "digest/sha1"
+
+class User < Principal
+ TEACHER = 0
+ STUDENT = 1
+ ENTERPRISE = 2
+ DEVELOPER = 3
+
+ include Redmine::SafeAttributes
+
+ # Different ways of displaying/sorting users
+ USER_FORMATS = {
+ :firstname_lastname => {
+ :string => '#{firstname} #{lastname}',
+ :order => %w(firstname lastname id),
+ :setting_order => 1
+ },
+ :firstname_lastinitial => {
+ :string => '#{firstname} #{lastname.to_s.chars.first}.',
+ :order => %w(firstname lastname id),
+ :setting_order => 2
+ },
+ :firstname => {
+ :string => '#{firstname}',
+ :order => %w(firstname id),
+ :setting_order => 3
+ },
+ :lastname_firstname => {
+ :string => '#{lastname} #{firstname}',
+ :order => %w(lastname firstname id),
+ :setting_order => 4
+ },
+ :lastname_coma_firstname => {
+ :string => '#{lastname}, #{firstname}',
+ :order => %w(lastname firstname id),
+ :setting_order => 5
+ },
+ :lastname => {
+ :string => '#{lastname}',
+ :order => %w(lastname id),
+ :setting_order => 6
+ },
+ :username => {
+ :string => '#{login}',
+ :order => %w(login id),
+ :setting_order => 7
+ },
+ }
+
+ MAIL_NOTIFICATION_OPTIONS = [
+ ['all', :label_user_mail_option_all],
+ ['selected', :label_user_mail_option_selected],
+ ['only_my_events', :label_user_mail_option_only_my_events],
+ ['only_assigned', :label_user_mail_option_only_assigned],
+ ['only_owner', :label_user_mail_option_only_owner],
+ ['none', :label_user_mail_option_none]
+ ]
+
+ has_many :homework_users
+ has_many :homework_attaches, :through => :homework_users
+
+ has_and_belongs_to_many :groups, :after_add => Proc.new {|user, group| group.user_added(user)},
+ :after_remove => Proc.new {|user, group| group.user_removed(user)}
+ has_many :changesets, :dependent => :nullify
+ has_one :preference, :dependent => :destroy, :class_name => 'UserPreference'
+ has_one :rss_token, :class_name => 'Token', :conditions => "action='feeds'"
+ has_one :api_token, :class_name => 'Token', :conditions => "action='api'"
+ belongs_to :auth_source
+ belongs_to :ucourse, :class_name => 'Course', :foreign_key => :id #huang
+## added by xianbo for delete
+ has_many :biding_projects, :dependent => :destroy
+ has_many :contesting_projects, :dependent => :destroy
+ belongs_to :softapplication, :foreign_key => 'id', :dependent => :destroy
+##ended by xianbo
+
+#####fq
+ has_many :jours, :class_name => 'JournalsForMessage', :dependent => :destroy
+ has_many :journals_messages, :class_name => 'JournalsForMessage', :foreign_key => "user_id", :dependent => :destroy
+ has_many :bids, :foreign_key => 'author_id', :dependent => :destroy
+ has_many :contests, :foreign_key => 'author_id', :dependent => :destroy
+ has_many :softapplications, :foreign_key => 'user_id', :dependent => :destroy
+ has_many :journals_for_messages, :as => :jour, :dependent => :destroy
+ has_many :new_jours, :as => :jour, :class_name => 'JournalsForMessage', :conditions => "status=1"
+ has_many :journal_replies, :dependent => :destroy
+ has_many :activities, :dependent => :destroy
+ has_many :students_for_courses
+ #has_many :courses, :through => :students_for_courses, :source => :project
+ has_many :acts, :class_name => 'Activity', :as => :act, :dependent => :destroy
+ has_many :file_commit, :class_name => 'Attachment', :foreign_key => 'author_id', :conditions => "container_type = 'Project' or container_type = 'Version'"
+####
+# added by bai
+ has_many :join_in_contests, :dependent => :destroy
+ has_many :news, :foreign_key => 'author_id'
+ has_many :contestnotification, :foreign_key => 'author_id'
+ has_many :comments, :foreign_key => 'author_id'
+ has_many :notificationcomments, :foreign_key => 'author_id'
+ has_many :wiki_contents, :foreign_key => 'author_id'
+ has_many :journals
+ has_many :messages, :foreign_key => 'author_id'
+ has_one :user_score, :dependent => :destroy
+ has_many :documents # 项目中关联的文档再次与人关联
+# end
+
+######added by nie
+ has_many :project_infos, :dependent => :destroy
+ has_one :user_status, :dependent => :destroy
+ #####
+ has_many :shares ,:dependent => :destroy
+
+ # add by zjc
+ has_one :level, :class_name => 'UserLevels', :dependent => :destroy
+ has_many :memos , :foreign_key => 'author_id'
+ #####
+ scope :logged, lambda { where("#{User.table_name}.status <> #{STATUS_ANONYMOUS}") }
+ scope :status, lambda {|arg| where(arg.blank? ? nil : {:status => arg.to_i}) }
+ scope :visible, lambda {|*args|
+ nil
+ }
+
+
+ acts_as_customizable
+ ############################added by william
+ acts_as_taggable
+ scope :by_join_date, order("created_on DESC")
+ ############################# added by liuping 关注
+ acts_as_watchable
+ seems_rateable_rater
+ has_one :user_extensions,:dependent => :destroy
+ ## end
+
+ # default_scope -> { includes(:user_extensions, :user_score) }
+ scope :teacher, -> {
+ joins(:user_extensions).where('user_extensions.identity = ?', UserExtensions::TEACHER)
+ }
+ scope :student, -> {
+ joins(:user_extensions).where('user_extensions.identity = ?', UserExtensions::STUDENT)
+ }
+ scope :developer, -> {
+ joins(:user_extensions).where('user_extensions.identity = ?', UserExtensions::DEVELOPER)
+ }
+ scope :enterprise, -> {
+ joins(:user_extensions).where('user_extensions.identity = ?', UserExtensions::ENTERPRISE)
+ }
+
+ attr_accessor :password, :password_confirmation
+ attr_accessor :last_before_login_on
+ # Prevents unauthorized assignments
+ attr_protected :login, :admin, :password, :password_confirmation, :hashed_password
+
+ LOGIN_LENGTH_LIMIT = 25
+ MAIL_LENGTH_LIMIT = 60
+
+ validates_presence_of :login, :mail, :if => Proc.new { |user| !user.is_a?(AnonymousUser) }
+ validates_uniqueness_of :login, :if => Proc.new { |user| user.login_changed? && user.login.present? }, :case_sensitive => false
+ validates_uniqueness_of :mail, :if => Proc.new { |user| user.mail_changed? && user.mail.present? }, :case_sensitive => false
+ # Login must contain letters, numbers, underscores only
+ validates_format_of :login, :with => /\A[a-z0-9_\-@\.]*\z/i
+ validates_length_of :login, :maximum => LOGIN_LENGTH_LIMIT
+ validates_length_of :firstname, :maximum => 30
+ validates_length_of :lastname, :maximum => 30
+ validates_format_of :mail, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, :allow_blank => true
+ validates_length_of :mail, :maximum => MAIL_LENGTH_LIMIT, :allow_nil => true
+ validates_confirmation_of :password, :allow_nil => true
+ validates_inclusion_of :mail_notification, :in => MAIL_NOTIFICATION_OPTIONS.collect(&:first), :allow_blank => true
+ validate :validate_password_length
+
+ before_create :set_mail_notification
+ before_save :update_hashed_password
+ before_destroy :remove_references_before_destroy
+ # added by fq
+ after_create :act_as_activity
+ # end
+
+ scope :in_group, lambda {|group|
+ group_id = group.is_a?(Group) ? group.id : group.to_i
+ where("#{User.table_name}.id IN (SELECT gu.user_id FROM #{table_name_prefix}groups_users#{table_name_suffix} gu WHERE gu.group_id = ?)", group_id)
+ }
+ scope :not_in_group, lambda {|group|
+ group_id = group.is_a?(Group) ? group.id : group.to_i
+ 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 :like, lambda {|arg|
+ if arg.blank?
+ where(nil)
+ else
+ pattern = "%#{arg.to_s.strip.downcase}%"
+ #where(" LOWER(concat(lastname, firstname)) LIKE :p ", :p => pattern)
+ where(" LOWER(login) LIKE :p ", :p => pattern)
+ end
+ }
+
+
+ # ======================================================================
+
+ def extensions
+ self.user_extensions ||= UserExtensions.new
+ end
+
+ def user_score_attr
+ self.user_score ||= UserScore.new
+ end
+
+ # ======================================================================
+
+ #选择项目成员时显示的用户信息文字
+ def userInfo
+ info=self.nickname + ' (' + self.realname + ')';
+ end
+
+ ###添加留言 fq
+ def add_jour(user, notes, reference_user_id = 0, options = {})
+ if options.count == 0
+ self.journals_for_messages << JournalsForMessage.new(:user_id => user.id, :notes => notes, :reply_id => reference_user_id, :status => true)
+ else
+ jfm = self.journals_for_messages.build(options)
+ jfm.save
+ jfm
+ end
+ end
+
+ # 判断用户是否加入了竞赛中 fq
+ def join_in_contest?(bid)
+ joined = JoinInContest.where('user_id = ? and bid_id =?', self.id, bid.id)
+ if joined.size > 0
+ true
+ else
+ false
+ end
+ end
+
+ ### fq
+ def join_in?(course)
+ joined = StudentsForCourse.where('student_id = ? and course_id = ?', self.id, course.id)
+ if joined.size > 0
+ true
+ else
+ false
+ end
+ end
+
+ def show_name
+ unless self.user_extensions.nil?
+ if self.user_extensions.identity == 2
+ firstname
+ else
+ lastname+firstname
+ end
+ else
+ lastname+firstname
+ end
+ end
+ ## end
+
+ def count_new_jour
+ count = self.new_jours.count
+ end
+
+ #added by nie
+ def count_new_journal_reply
+ count = self.journal_reply.count
+ end
+
+ def set_mail_notification
+ ##add byxianbo
+ thread=Thread.new do
+ self.mail_notification = Setting.default_notification_option if self.mail_notification.blank?
+ true
+ end
+ end
+
+ def update_hashed_password
+ # update hashed_password if password was set
+ if self.password && self.auth_source_id.blank?
+ salt_password(password)
+ end
+ end
+
+ alias :base_reload :reload
+ def reload(*args)
+ @name = nil
+ @projects_by_role = nil
+ @courses_by_role = nil
+ @membership_by_project_id = nil
+ base_reload(*args)
+ end
+
+ def mail=(arg)
+ write_attribute(:mail, arg.to_s.strip)
+ end
+
+ def identity_url=(url)
+ if url.blank?
+ write_attribute(:identity_url, '')
+ else
+ begin
+ write_attribute(:identity_url, OpenIdAuthentication.normalize_identifier(url))
+ rescue OpenIdAuthentication::InvalidOpenId
+ # Invalid url, don't save
+ end
+ end
+ self.read_attribute(:identity_url)
+ end
+
+ VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i
+ # VALID_EMAIL_REGEX = /^[0-9a-zA-Z_-]+@[0-9a-zA-Z_-]+(\.[0-9a-zA-Z_-]+)+$/
+ # Returns the user that matches provided login and password, or nil
+ #登录,返回用户名与密码匹配的用户
+ def self.try_to_login(login, password)
+ login = login.to_s.lstrip.rstrip
+ password = password.to_s
+
+ # Make sure no one can sign in with an empty login or password
+ return nil if login.empty? || password.empty?
+ if (login =~ VALID_EMAIL_REGEX)
+ user = find_by_mail(login)
+ else
+ user = find_by_login(login)
+ end
+ if user
+ # user is already in local database
+ #return nil unless user.active?
+ return nil unless user.check_password?(password)
+ else
+ # user is not yet registered, try to authenticate with available sources
+ attrs = AuthSource.authenticate(login, password)
+ if attrs
+ user = new(attrs)
+ user.login = login
+ user.language = Setting.default_language
+ if user.save
+ user.reload
+ logger.info("User '#{user.login}' created from external auth source: #{user.auth_source.type} - #{user.auth_source.name}") if logger && user.auth_source
+ end
+ end
+ end
+ user.update_column(:last_login_on, Time.now) if user && !user.new_record?
+ user
+ rescue => text
+ raise text
+ end
+
+ # Returns the user who matches the given autologin +key+ or nil
+ def self.try_to_autologin(key)
+ user = Token.find_active_user('autologin', key, Setting.autologin.to_i)
+ if user
+ user.update_column(:last_login_on, Time.now)
+ user
+ end
+ end
+
+ def self.name_formatter(formatter = nil)
+ USER_FORMATS[formatter || Setting.user_format] || USER_FORMATS[:firstname_lastname]
+ end
+
+ # Returns an array of fields names than can be used to make an order statement for users
+ # according to how user names are displayed
+ # Examples:
+ #
+ # User.fields_for_order_statement => ['users.login', 'users.id']
+ # User.fields_for_order_statement('authors') => ['authors.login', 'authors.id']
+ def self.fields_for_order_statement(table=nil)
+ table ||= table_name
+ name_formatter[:order].map {|field| "#{table}.#{field}"}
+ end
+
+ # Return user's full name for display
+ def realname(formatter = nil)
+ f = self.class.name_formatter(formatter)
+ if formatter
+ eval('"' + f[:string] + '"')
+ else
+ @name ||= eval('"' + f[:string] + '"')
+ end
+ end
+
+ def nickname(formatter = nil)
+ login
+ end
+
+ def name(formatter = nil)
+ login
+ end
+
+ def active?
+ self.status == STATUS_ACTIVE
+ end
+
+ def registered?
+ self.status == STATUS_REGISTERED
+ end
+
+ def locked?
+ self.status == STATUS_LOCKED
+ end
+
+ def activate
+ self.status = STATUS_ACTIVE
+ end
+
+ def register
+ self.status = STATUS_REGISTERED
+ end
+
+ def lock
+ self.status = STATUS_LOCKED
+ end
+
+ def activate!
+ update_attribute(:status, STATUS_ACTIVE)
+ end
+
+ def register!
+ update_attribute(:status, STATUS_REGISTERED)
+ end
+
+ def lock!
+ update_attribute(:status, STATUS_LOCKED)
+ end
+
+ # Returns true if +clear_password+ is the correct user's password, otherwise false
+ def check_password?(clear_password)
+ if auth_source_id.present?
+ auth_source.authenticate(self.login, clear_password)
+ else
+ User.hash_password("#{salt}#{User.hash_password clear_password}") == hashed_password
+ end
+ end
+
+ # Generates a random salt and computes hashed_password for +clear_password+
+ # The hashed password is stored in the following form: SHA1(salt + SHA1(password))
+ def salt_password(clear_password)
+ self.salt = User.generate_salt
+ self.hashed_password = User.hash_password("#{salt}#{User.hash_password clear_password}")
+ end
+
+ # Does the backend storage allow this user to change their password?
+ def change_password_allowed?
+ return true if auth_source.nil?
+ return auth_source.allow_password_changes?
+ end
+
+ # Generate and set a random password. Useful for automated user creation
+ # Based on Token#generate_token_value
+ #
+ def random_password
+ chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
+ password = ''
+ 40.times { |i| password << chars[rand(chars.size-1)] }
+ self.password = password
+ self.password_confirmation = password
+ self
+ end
+
+ def pref
+ self.preference ||= UserPreference.new(:user => self)
+ end
+
+ def time_zone
+ @time_zone ||= (self.pref.time_zone.blank? ? nil : ActiveSupport::TimeZone[self.pref.time_zone])
+ end
+
+ def wants_comments_in_reverse_order?
+ self.pref[:comments_sorting] == 'desc'
+ end
+
+ def wants_notificationcomments_in_reverse_order?
+ self.pref[:notificationcomments_sorting] == 'desc'
+ end
+ # Return user's RSS key (a 40 chars long string), used to access feeds
+ def rss_key
+ if rss_token.nil?
+ create_rss_token(:action => 'feeds')
+ end
+ rss_token.value
+ end
+
+ # Return user's API key (a 40 chars long string), used to access the API
+ def api_key
+ if api_token.nil?
+ create_api_token(:action => 'api')
+ end
+ api_token.value
+ end
+
+ # Return an array of project ids for which the user has explicitly turned mail notifications on
+ def notified_projects_ids
+ @notified_projects_ids ||= memberships.select {|m| m.mail_notification?}.collect(&:project_id)
+ end
+
+ def notified_project_ids=(ids)
+ Member.update_all("mail_notification = #{connection.quoted_false}", ['user_id = ?', id])
+ Member.update_all("mail_notification = #{connection.quoted_true}", ['user_id = ? AND project_id IN (?)', id, ids]) if ids && !ids.empty?
+ @notified_projects_ids = nil
+ notified_projects_ids
+ end
+
+ def valid_notification_options
+ self.class.valid_notification_options(self)
+ end
+
+ # Only users that belong to more than 1 project can select projects for which they are notified
+ def self.valid_notification_options(user=nil)
+ # Note that @user.membership.size would fail since AR ignores
+ # :include association option when doing a count
+ if user.nil? || user.memberships.length < 1
+ MAIL_NOTIFICATION_OPTIONS.reject {|option| option.first == 'selected'}
+ else
+ MAIL_NOTIFICATION_OPTIONS
+ end
+ end
+
+ # Find a user account by matching the exact login and then a case-insensitive
+ # version. Exact matches will be given priority.
+ #通过用户名查找相应的用户,若没有匹配到,则不区分大小写进行查询
+ #修改:不再匹配不区分大小写情况 -zjc
+ def self.find_by_login(login)
+ if login.present?
+ login = login.to_s
+ # First look for an exact match
+ user = where(:login => login).all.detect {|u| u.login == login}
+ #unless user
+ # # Fail over to case-insensitive if none was found
+ # user = where("LOWER(login) = ?", login.downcase).first
+ #end
+ user
+ end
+ end
+
+ def self.find_by_rss_key(key)
+ Token.find_active_user('feeds', key)
+ end
+
+ def self.find_by_api_key(key)
+ Token.find_active_user('api', key)
+ end
+
+ # Makes find_by_mail case-insensitive
+ def self.find_by_mail(mail)
+ where("LOWER(mail) = ?", mail.to_s.downcase).first
+ end
+
+ # Returns true if the default admin account can no longer be used
+ def self.default_admin_account_changed?
+ !User.active.find_by_login("admin").try(:check_password?, "admin")
+ end
+
+ def to_s
+ name
+ end
+
+ CSS_CLASS_BY_STATUS = {
+ STATUS_ANONYMOUS => 'anon',
+ STATUS_ACTIVE => 'active',
+ STATUS_REGISTERED => 'registered',
+ STATUS_LOCKED => 'locked'
+ }
+
+ def css_classes
+ "user #{CSS_CLASS_BY_STATUS[status]}"
+ end
+
+ # Returns the current day according to user's time zone
+ def today
+ if time_zone.nil?
+ Date.today
+ else
+ Time.now.in_time_zone(time_zone).to_date
+ end
+ end
+
+ # Returns the day of +time+ according to user's time zone
+ def time_to_date(time)
+ if time_zone.nil?
+ time.to_date
+ else
+ time.in_time_zone(time_zone).to_date
+ end
+ end
+
+ def logged?
+ true
+ end
+
+ def anonymous?
+ !logged?
+ end
+
+ # Returns user's membership for the given project
+ # or nil if the user is not a member of project
+ def membership(project)
+ project_id = project.is_a?(Project) ? project.id : project
+
+ @membership_by_project_id ||= Hash.new {|h, project_id|
+ h[project_id] = memberships.where(:project_id => project_id).first
+ }
+ @membership_by_project_id[project_id]
+ end
+
+ def coursemembership(course)
+ course_id = course.is_a?(Course) ? course.id : course
+
+ @membership_by_course_id ||= Hash.new {|h, course_id|
+ h[course_id] = coursememberships.where(:course_id => course_id).first
+ }
+ @membership_by_course_id[course_id]
+ end
+
+ # Return user's roles for project
+ def roles_for_project(project)
+ roles = []
+ # No role on archived projects
+ return roles if project.nil? || project.archived?
+ if logged?
+ # Find project membership
+ membership = membership(project)
+ if membership
+ roles = membership.roles
+ else
+ @role_non_member ||= Role.non_member
+ roles << @role_non_member
+ end
+ else
+ @role_anonymous ||= Role.anonymous
+ roles << @role_anonymous
+ end
+ roles
+ end
+
+ # 用户课程权限判断
+ def roles_for_course(course)
+ roles = []
+ # No role on archived courses
+ return roles if course.nil? || course.archived?
+ if logged?
+ # Find course membership
+ membership = coursemembership(course)
+ if membership
+ roles = membership.roles
+ else
+ @role_non_member ||= Role.non_member
+ roles << @role_non_member
+ end
+ else
+ @role_anonymous ||= Role.anonymous
+ roles << @role_anonymous
+ end
+ roles
+ end
+
+ # Return true if the user is a member of project
+ def member_of?(project)
+ projects.to_a.include?(project)
+ end
+
+ def member_of_course?(course)
+ courses.to_a.include?(course)
+ end
+
+ # Returns a hash of user's projects grouped by roles
+ def projects_by_role
+ return @projects_by_role if @projects_by_role
+
+ @projects_by_role = Hash.new([])
+ memberships.each do |membership|
+ if membership.project
+ membership.roles.each do |role|
+ @projects_by_role[role] = [] unless @projects_by_role.key?(role)
+ @projects_by_role[role] << membership.project
+ end
+ end
+ end
+ @projects_by_role.each do |role, projects|
+ projects.uniq!
+ end
+
+ @projects_by_role
+ end
+
+ # 课程的角色权限
+ def courses_by_role
+ return @courses_by_role if @courses_by_role
+
+ @courses_by_role = Hash.new([])
+ coursememberships.each do |membership|
+ if membership.course
+ membership.roles.each do |role|
+ @courses_by_role[role] = [] unless @courses_by_role.key?(role)
+ @courses_by_role[role] << membership.course
+ end
+ end
+ end
+ @courses_by_role.each do |role, courses|
+ courses.uniq!
+ end
+
+ @courses_by_role
+ end
+ # Returns true if user is arg or belongs to arg
+ def is_or_belongs_to?(arg)
+ if arg.is_a?(User)
+ self == arg
+ elsif arg.is_a?(Group)
+ arg.users.include?(self)
+ else
+ false
+ end
+ end
+
+
+ # Return true if the user is allowed to do the specified action on a specific context
+ # Action can be:
+ # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')
+ # * a permission Symbol (eg. :edit_project)
+ # Context can be:
+ # * a project : returns true if user is allowed to do the specified action on this project
+ # * an array of projects : returns true if user is allowed on every project
+ # * nil with options[:global] set : check if user has at least one role allowed for this action,
+ # or falls back to Non Member / Anonymous permissions depending if the user is logged
+ def allowed_to?(action, context, options={}, &block)
+ if context && context.is_a?(Project)
+ return false unless context.allows_to?(action)
+ # Admin users are authorized for anything else
+ return true if admin?
+
+ roles = roles_for_project(context)
+ return false unless roles
+ roles.any? {|role|
+ (context.is_public? || role.member?) &&
+ role.allowed_to?(action) &&
+ (block_given? ? yield(role, self) : true)
+ }
+ #添加课程相关的权限判断
+ elsif context && context.is_a?(Course)
+ return false unless context.allows_to?(action)
+ # Admin users are authorized for anything else
+ return true if admin?
+
+ roles = roles_for_course(context)
+ return false unless roles
+ roles.any? {|role|
+ (context.is_public? || role.member?) &&
+ role.allowed_to?(action) &&
+ (block_given? ? yield(role, self) : true)
+ }
+ elsif context && context.is_a?(Array)
+ if context.empty?
+ false
+ else
+ # Authorize if user is authorized on every element of the array
+ context.map {|project| allowed_to?(action, project, options, &block)}.reduce(:&)
+ end
+ elsif options[:global]
+ # Admin users are always authorized
+ return true if admin?
+
+ # authorize if user has at least one role that has this permission
+ roles = memberships.collect {|m| m.roles}.flatten.uniq
+ if roles.count == 0
+ roles = coursememberships.collect {|m| m.roles}.flatten.uniq
+ end
+ roles << (self.logged? ? Role.non_member : Role.anonymous)
+ roles.any? {|role|
+ role.allowed_to?(action) &&
+ (block_given? ? yield(role, self) : true)
+ }
+ else
+ if admin?
+ return true
+ end
+ #无项目时 查看Non member(id为1)角色是否有权限执行action
+ Role.find('1').allowed_to?(action)
+ # false
+ end
+ end
+
+ # Is the user allowed to do the specified action on any project?
+ # See allowed_to? for the actions and valid options.
+ def allowed_to_globally?(action, options, &block)
+ allowed_to?(action, nil, options.reverse_merge(:global => true), &block)
+ end
+
+ # Returns true if the user is allowed to delete his own account
+ def own_account_deletable?
+ Setting.unsubscribe? &&
+ (!admin? || User.active.where("admin = ? AND id <> ?", true, id).exists?)
+ end
+
+ safe_attributes 'login',
+ 'firstname',
+ 'lastname',
+ 'mail',
+ 'mail_notification',
+ 'language',
+ 'custom_field_values',
+ 'custom_fields',
+ 'identity_url'
+
+ safe_attributes 'status',
+ 'auth_source_id',
+ :if => lambda {|user, current_user| current_user.admin?}
+
+ safe_attributes 'group_ids',
+ :if => lambda {|user, current_user| current_user.admin? && !user.new_record?}
+
+ # Utility method to help check if a user should be notified about an
+ # event.
+ #
+ # TODO: only supports Issue events currently
+ def notify_about?(object)
+ if mail_notification == 'all'
+ true
+ elsif mail_notification.blank? || mail_notification == 'none'
+ false
+ else
+ case object
+ when Issue
+ case mail_notification
+ when 'selected', 'only_my_events'
+ # user receives notifications for created/assigned issues on unselected projects
+ object.author == self || is_or_belongs_to?(object.assigned_to) || is_or_belongs_to?(object.assigned_to_was)
+ when 'only_assigned'
+ is_or_belongs_to?(object.assigned_to) || is_or_belongs_to?(object.assigned_to_was)
+ when 'only_owner'
+ object.author == self
+ end
+ when News
+ # always send to project members except when mail_notification is set to 'none'
+ true
+ #判定用户是否接受留言提醒邮件
+ when JournalsForMessage
+ ##如果是直接留言并且留言对象是Project并且Project类型是课程(课程留言)
+ if !object.at_user && object.jour.class.to_s.to_sym == :Project && object.jour.project_type == 1
+ #根据用户设置邮件接收模式判定当前用户是否接受邮件提醒
+ is_notified_project object.jour
+ end
+
+ end
+ end
+ end
+
+ #用户是否接收project的消息提醒
+ def is_notified_project arg
+ if arg.is_a?(Project)
+ case mail_notification
+ when 'selected'
+ notified_projects_ids.include?(arg.id)
+ when 'only_my_events'
+ projects.include?(arg)
+ when 'only_assigned'
+ false
+ when 'only_owner'
+ course = Course.find_by_extra(arg.identifier)
+ course.teacher == self
+ end
+ #勾选的项目或用户的项目 TODO:需改
+ #notified_projects_ids.include?(arg) || projects.include?(arg)
+ else
+ false
+ end
+ end
+
+ def self.current=(user)
+ Thread.current[:current_user] = user
+ end
+
+ def self.current
+ Thread.current[:current_user] ||= User.anonymous
+ end
+
+ # Returns the anonymous user. If the anonymous user does not exist, it is created. There can be only
+ # one anonymous user per database.
+ def self.anonymous
+ anonymous_user = AnonymousUser.first
+ if anonymous_user.nil?
+ anonymous_user = AnonymousUser.create(:lastname => 'Anonymous', :firstname => '', :mail => '', :login => '', :status => 0)
+ raise 'Unable to create the anonymous user.' if anonymous_user.new_record?
+ end
+ anonymous_user
+ end
+
+ # Salts all existing unsalted passwords
+ # It changes password storage scheme from SHA1(password) to SHA1(salt + SHA1(password))
+ # This method is used in the SaltPasswords migration and is to be kept as is
+ def self.salt_unsalted_passwords!
+ transaction do
+ User.where("salt IS NULL OR salt = ''").find_each do |user|
+ next if user.hashed_password.blank?
+ salt = User.generate_salt
+ hashed_password = User.hash_password("#{salt}#{user.hashed_password}")
+ User.where(:id => user.id).update_all(:salt => salt, :hashed_password => hashed_password)
+ end
+ end
+ end
+
+ protected
+
+ def validate_password_length
+ # Password length validation based on setting
+ if !password.nil? && password.size < Setting.password_min_length.to_i
+ errors.add(:password, :too_short, :count => Setting.password_min_length.to_i)
+ end
+ end
+ private
+
+ def act_as_activity
+ self.acts << Activity.new(:user_id => self.id)
+ end
+
+ # Removes references that are not handled by associations
+ # Things that are not deleted are reassociated with the anonymous user
+ def remove_references_before_destroy
+ return if self.id.nil?
+
+ substitute = User.anonymous
+ Attachment.update_all ['author_id = ?', substitute.id], ['author_id = ?', id]
+ Comment.update_all ['author_id = ?', substitute.id], ['author_id = ?', id]
+ Notificationcomment.update_all ['author_id = ?', substitute.id], ['author_id = ?', id]
+ Issue.update_all ['author_id = ?', substitute.id], ['author_id = ?', id]
+ Issue.update_all 'assigned_to_id = NULL', ['assigned_to_id = ?', id]
+ Journal.update_all ['user_id = ?', substitute.id], ['user_id = ?', id]
+ JournalDetail.update_all ['old_value = ?', substitute.id.to_s], ["property = 'attr' AND prop_key = 'assigned_to_id' AND old_value = ?", id.to_s]
+ JournalDetail.update_all ['value = ?', substitute.id.to_s], ["property = 'attr' AND prop_key = 'assigned_to_id' AND value = ?", id.to_s]
+ Message.update_all ['author_id = ?', substitute.id], ['author_id = ?', id]
+ News.update_all ['author_id = ?', substitute.id], ['author_id = ?', id]
+ # Remove private queries and keep public ones
+ ::Query.delete_all ['user_id = ? AND is_public = ?', id, false]
+ ::Query.update_all ['user_id = ?', substitute.id], ['user_id = ?', id]
+ TimeEntry.update_all ['user_id = ?', substitute.id], ['user_id = ?', id]
+ Token.delete_all ['user_id = ?', id]
+ Watcher.delete_all ['user_id = ?', id]
+ WikiContent.update_all ['author_id = ?', substitute.id], ['author_id = ?', id]
+ WikiContent::Version.update_all ['author_id = ?', substitute.id], ['author_id = ?', id]
+ end
+
+ # Return password digest
+ def self.hash_password(clear_password)
+ Digest::SHA1.hexdigest(clear_password || "")
+ end
+
+ # Returns a 128bits random salt as a hex string (32 chars long)
+ def self.generate_salt
+ Redmine::Utils.random_hex(16)
+ end
+
+
+
+end
+
+class AnonymousUser < User
+ validate :validate_anonymous_uniqueness, :on => :create
+
+ def validate_anonymous_uniqueness
+ # There should be only one AnonymousUser in the database
+ errors.add :base, 'An anonymous user already exists.' if AnonymousUser.exists?
+ end
+
+ def available_custom_fields
+ []
+ end
+
+ # Overrides a few properties
+ def logged?; false end
+ def admin; false end
+ def name(*args); I18n.t(:label_user_anonymous) end
+ def mail; nil end
+ def time_zone; nil end
+ def rss_key; nil end
+
+ def pref
+ UserPreference.new(:user => self)
+ end
+
+ # def member_of?(project)
+ # false
+ # end
+
+ # Anonymous user can not be destroyed
+ def destroy
+ false
+ end
+end
From 8cec84dca7ca8658c870eabf8d505eaf52bf51df Mon Sep 17 00:00:00 2001
From: alan <547533434@qq.com>
Date: Mon, 3 Nov 2014 15:16:56 +0800
Subject: [PATCH 12/18] =?UTF-8?q?=E6=B7=BB=E5=8A=A0<=E5=85=AC=E5=85=B1?=
=?UTF-8?q?=E8=B4=B4=E5=90=A7=20=E6=97=A0=E5=B8=96=E5=AD=90=E7=BD=AE?=
=?UTF-8?q?=E9=A1=B6=E5=8A=9F=E8=83=BD=20=E5=BB=BA=E8=AE=AE=E5=A2=9E?=
=?UTF-8?q?=E5=8A=A0>=EF=BC=8C<=E7=AE=A1=E7=90=86=E5=91=98=E5=8F=AF?=
=?UTF-8?q?=E4=BB=A5=E6=A0=B9=E6=8D=AE=E8=B4=B4=E5=90=A7=E7=9A=84=E7=83=AD?=
=?UTF-8?q?=E5=BA=A6=E9=80=89=E6=8B=A9=E5=B0=86=E8=B4=B4=E5=90=A7=E7=BD=AE?=
=?UTF-8?q?=E9=A1=B6>?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: alan <547533434@qq.com>
---
app/controllers/forums_controller.rb | 4 ++-
app/models/forum.rb | 4 ++-
app/views/forums/_form.html.erb | 12 ++++++++
app/views/forums/_forum_list.html.erb | 11 +++++--
app/views/forums/index.html.erb | 3 +-
app/views/memos/_form.html.erb | 2 +-
config/locales/zh.yml | 1 +
config/routes.rb | 1 +
.../20141030071656_add_data_for_school.rb | 26 -----------------
.../20141103015148_add_column_to_forums.rb | 6 ++++
...41103032156_set_sticky_locked_for_forum.rb | 9 ++++++
...20141103065703_add_data_for_school_name.rb | 29 +++++++++++++++++++
db/schema.rb | 4 ++-
13 files changed, 78 insertions(+), 34 deletions(-)
delete mode 100644 db/migrate/20141030071656_add_data_for_school.rb
create mode 100644 db/migrate/20141103015148_add_column_to_forums.rb
create mode 100644 db/migrate/20141103032156_set_sticky_locked_for_forum.rb
create mode 100644 db/migrate/20141103065703_add_data_for_school_name.rb
diff --git a/app/controllers/forums_controller.rb b/app/controllers/forums_controller.rb
index d5fc1770c..cd51d2e58 100644
--- a/app/controllers/forums_controller.rb
+++ b/app/controllers/forums_controller.rb
@@ -52,7 +52,7 @@ class ForumsController < ApplicationController
def index
@offset, @limit = api_offset_and_limit({:limit => 10})
- @forums_all = Forum.where('1=1')
+ @forums_all = Forum.reorder("sticky DESC")
@forums_count = @forums_all.count
@forums_pages = Paginator.new @forums_count, @limit, params['page']
@@ -208,6 +208,8 @@ class ForumsController < ApplicationController
end
end
+
+
private
diff --git a/app/models/forum.rb b/app/models/forum.rb
index 24b5b15e0..e0592723e 100644
--- a/app/models/forum.rb
+++ b/app/models/forum.rb
@@ -8,7 +8,9 @@ class Forum < ActiveRecord::Base
'topic_count',
'memo_count',
'last_memo_id',
- 'creator_id'
+ 'creator_id',
+ 'sticky',
+ 'locked'
validates_presence_of :name, :creator_id, :description
validates_length_of :name, maximum: 50
#validates_length_of :description, maximum: 255
diff --git a/app/views/forums/_form.html.erb b/app/views/forums/_form.html.erb
index 556238732..9b3519b05 100644
--- a/app/views/forums/_form.html.erb
+++ b/app/views/forums/_form.html.erb
@@ -17,6 +17,18 @@
<%= f.text_field :name, :required => true, :style => 'width: 100%;', :class => 'create-share' %>
+
+ <% if User.current.logged? && User.current.admin? %>
+ <% if @forum.safe_attribute? 'sticky' %>
+ <%= f.check_box :sticky %>
+ <%= label_tag 'message_sticky', l(:label_board_sticky) %>
+ <% end %>
+ <% if @forum.safe_attribute? 'locked' %>
+ <%= f.check_box :locked %>
+ <%= label_tag 'message_locked', l(:label_board_locked) %>
+ <% end %>
+ <% end %>
+
diff --git a/app/views/forums/_forum_list.html.erb b/app/views/forums/_forum_list.html.erb
index 9d0eba923..874dc355f 100644
--- a/app/views/forums/_forum_list.html.erb
+++ b/app/views/forums/_forum_list.html.erb
@@ -7,9 +7,14 @@
<%= forum.creator.nil? ? (link_to image_tag(url_to_avatar(forum.creator), :class => "avatar")) : (link_to image_tag(url_to_avatar(forum.creator), :class => "avatar"), user_path(forum.creator)) %>
-
<%= link_to h(forum.name), forum_path(forum) %>
-
<%= textAreailizable forum.description%>
-
<%= authoring forum.created_at, forum.creator %>
+
+
+ <%= link_to h(forum.name), forum_path(forum) %> |
+ <%= textAreailizable forum.description%> |
+ <%= authoring forum.created_at, forum.creator %> |
+
+
<%= link_to (forum.memo_count), forum_path(forum) %> | <%= link_to (forum.topic_count), forum_path(forum) %> |
回答 | 帖子 |
diff --git a/app/views/forums/index.html.erb b/app/views/forums/index.html.erb
index fa6e74ccd..31d00891e 100644
--- a/app/views/forums/index.html.erb
+++ b/app/views/forums/index.html.erb
@@ -11,7 +11,8 @@
<% if User.current.logged? %>
<%= link_to( l(:label_forum_new), new_forum_path, :class => 'icon icon-add') %>
- <% end %>
+ <% end %>
+
|
diff --git a/app/views/memos/_form.html.erb b/app/views/memos/_form.html.erb
index 41ea73fcd..961e54ded 100644
--- a/app/views/memos/_form.html.erb
+++ b/app/views/memos/_form.html.erb
@@ -1,3 +1,3 @@
<%= error_messages_for 'bid' %>
<%= f.text_field :content, :required => true, :size => 60, :style => "width:150px;" %>
- <%= hidden_field_tag 'subject', ||=@memo.subject %>
\ No newline at end of file
+ <%= hidden_field_tag 'subject'||=@memo.subject %>
\ No newline at end of file
diff --git a/config/locales/zh.yml b/config/locales/zh.yml
index 02a79397a..97dceb192 100644
--- a/config/locales/zh.yml
+++ b/config/locales/zh.yml
@@ -1960,6 +1960,7 @@ zh:
label_memo_new_from_forum: 发布帖子
label_forum: 公共贴吧
label_forum_new: 新建贴吧
+ label_forum_set: 贴吧设置
label_tags_forum_description: 贴吧描述
label_tags_forum: 贴吧名称
label_project_module_forums: 公共贴吧
diff --git a/config/routes.rb b/config/routes.rb
index 646a1a51f..9d0a945c0 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -157,6 +157,7 @@ RedmineApp::Application.routes.draw do
resources :forums do
collection do
match 'search_forum', :via => [:get, :post]
+
end
member do
post 'create_memo'
diff --git a/db/migrate/20141030071656_add_data_for_school.rb b/db/migrate/20141030071656_add_data_for_school.rb
deleted file mode 100644
index 94db0ea19..000000000
--- a/db/migrate/20141030071656_add_data_for_school.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-#encoding=UTF-8
-class AddDataForSchool < ActiveRecord::Migration
- def up
- sql = " Insert into schools (name, province, logo_link) values
- ('香港大学','香港','/images/transparent.png'),
- ('香港大学','香港','/images/transparent.png'),
- ('香港中文大学','香港','/images/transparent.png'),
- ('香港科技大学','香港','/images/transparent.png'),('香港理工大学','香港','/images/transparent.png'),
- ('香港城市大学','香港','/images/transparent.png'),('香港浸会大学','香港','/images/transparent.png'),
- ('香港教育学院','香港','/images/transparent.png'),('香港歌德学院','香港','/images/transparent.png'),
- ('香港岭南大学','香港','/images/transparent.png'),('澳门大学','澳门','/images/transparent.png'),
- ('澳门理工学院','澳门','/images/transparent.png'),('澳门科技大学','澳门','/images/transparent.png'),
- ('澳门保安部队高等学校','澳门','/images/transparent.png'),('亚洲国际公开大学','澳门','/images/transparent.png'),
- ('澳门旅游学院','澳门','/images/transparent.png'),('清华大学(新竹)','台湾','/images/transparent.png'),
- ('台湾大学','台湾','/images/transparent.png'),('交通大学','台湾','/images/transparent.png'),
- ('中央大学','台湾','/images/transparent.png'),('成功大学','台湾','/images/transparent.png'),
- ('中山大学','台湾','/images/transparent.png'),('中原大学','台湾','/images/transparent.png'),
- ('政治大学','台湾','/images/transparent.png'),('元智大学','台湾','/images/transparent.png'),
- ('天主教辅仁大学','台湾','/images/transparent.png'),('台湾科技大学','台湾','/images/transparent.png'),
- ('台湾师范大学','台湾','/images/transparent.png'),('台湾艺术大学','台湾','/images/transparent.png')"
- execute(sql)
- end
-
- def down
- end
-end
diff --git a/db/migrate/20141103015148_add_column_to_forums.rb b/db/migrate/20141103015148_add_column_to_forums.rb
new file mode 100644
index 000000000..5f8938eb9
--- /dev/null
+++ b/db/migrate/20141103015148_add_column_to_forums.rb
@@ -0,0 +1,6 @@
+class AddColumnToForums < ActiveRecord::Migration
+ def change
+ add_column :forums, :sticky, :integer
+ add_column :forums, :locked, :integer
+ end
+end
diff --git a/db/migrate/20141103032156_set_sticky_locked_for_forum.rb b/db/migrate/20141103032156_set_sticky_locked_for_forum.rb
new file mode 100644
index 000000000..743406d4b
--- /dev/null
+++ b/db/migrate/20141103032156_set_sticky_locked_for_forum.rb
@@ -0,0 +1,9 @@
+class SetStickyLockedForForum < ActiveRecord::Migration
+ def up
+ sql = "update forums set sticky=0, locked = 0 "
+ execute(sql)
+ end
+
+ def down
+ end
+end
diff --git a/db/migrate/20141103065703_add_data_for_school_name.rb b/db/migrate/20141103065703_add_data_for_school_name.rb
new file mode 100644
index 000000000..924f2e5da
--- /dev/null
+++ b/db/migrate/20141103065703_add_data_for_school_name.rb
@@ -0,0 +1,29 @@
+#encoding=UTF-8
+class AddDataForSchoolName < ActiveRecord::Migration
+ def up
+ sql = " Insert into schools (name, province, logo_link, created_at, updated_at) values
+ ('香港大学','香港','/images/transparent.png', NOW(),NOW()),
+ ('香港大学','香港','/images/transparent.png',NOW(),NOW()),
+ ('香港中文大学','香港','/images/transparent.png',NOW(),NOW()),
+ ('香港科技大学','香港','/images/transparent.png',NOW(),NOW()),('香港理工大学','香港','/images/transparent.png',NOW(),NOW()),
+ ('香港城市大学','香港','/images/transparent.png',NOW(),NOW()),('香港浸会大学','香港','/images/transparent.png',NOW(),NOW()),
+ ('香港教育学院','香港','/images/transparent.png',NOW(),NOW()),('香港歌德学院','香港','/images/transparent.png',NOW(),NOW()),
+ ('香港岭南大学','香港','/images/transparent.png',NOW(),NOW()),('澳门大学','澳门','/images/transparent.png',NOW(),NOW()),
+ ('澳门理工学院','澳门','/images/transparent.png',NOW(),NOW()),('澳门科技大学','澳门','/images/transparent.png',NOW(),NOW()),
+ ('澳门保安部队高等学校','澳门','/images/transparent.png',NOW(),NOW()),('亚洲国际公开大学','澳门','/images/transparent.png',NOW(),NOW()),
+ ('澳门旅游学院','澳门','/images/transparent.png',NOW(),NOW()),('清华大学(新竹)','台湾','/images/transparent.png',NOW(),NOW()),
+ ('台湾大学','台湾','/images/transparent.png',NOW(),NOW()),('交通大学','台湾','/images/transparent.png',NOW(),NOW()),
+ ('中央大学','台湾','/images/transparent.png',NOW(),NOW()),('成功大学','台湾','/images/transparent.png',NOW(),NOW()),
+ ('中山大学','台湾','/images/transparent.png',NOW(),NOW()),('中原大学','台湾','/images/transparent.png',NOW(),NOW()),
+ ('政治大学','台湾','/images/transparent.png',NOW(),NOW()),('元智大学','台湾','/images/transparent.png',NOW(),NOW()),
+ ('天主教辅仁大学','台湾','/images/transparent.png',NOW(),NOW()),('台湾科技大学','台湾','/images/transparent.png',NOW(),NOW()),
+ ('台湾师范大学','台湾','/images/transparent.png',NOW(),NOW()),('台湾艺术大学','台湾','/images/transparent.png',NOW(),NOW())"
+ execute(sql)
+
+ end
+
+
+
+ def down
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 70ed2ce36..c257fa97a 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 20141031122331) do
+ActiveRecord::Schema.define(:version => 20141103065703) do
create_table "activities", :force => true do |t|
t.integer "act_id", :null => false
@@ -457,6 +457,8 @@ ActiveRecord::Schema.define(:version => 20141031122331) do
t.integer "creator_id", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
+ t.integer "sticky"
+ t.integer "locked"
end
create_table "groups_users", :id => false, :force => true do |t|
From 495c4db43e31e5c0b5fc2be8f911f0a00072a751 Mon Sep 17 00:00:00 2001
From: alan <547533434@qq.com>
Date: Mon, 3 Nov 2014 17:00:01 +0800
Subject: [PATCH 13/18] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=8A=9F=E8=83=BD=
=?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AD=A6=E7=94=9F=E5=88=97=E8=A1=A8=E6=98=AF?=
=?UTF-8?q?=E5=90=A6=E5=85=AC=E5=BC=80=E5=8A=9F=E8=83=BD>=20Signed-off-by:?=
=?UTF-8?q?=20alan=20<547533434@qq.com>?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/models/course.rb | 5 +++--
app/views/courses/_course_form.html.erb | 8 +++++++-
app/views/layouts/base_courses.html.erb | 2 +-
config/locales/zh.yml | 2 ++
config/routes.rb | 2 +-
5 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/app/models/course.rb b/app/models/course.rb
index 1f0cb0979..b2da58a81 100644
--- a/app/models/course.rb
+++ b/app/models/course.rb
@@ -5,7 +5,7 @@ class Course < ActiveRecord::Base
STATUS_CLOSED = 5
STATUS_ARCHIVED = 9
- attr_accessible :code, :extra, :name, :state, :tea_id, :time , :location, :state, :term, :password,:is_public,:description,:class_period
+ attr_accessible :code, :extra, :name, :state, :tea_id, :time , :location, :state, :term, :password,:is_public,:description,:class_period, :open_student
belongs_to :project, :class_name => 'Course', :foreign_key => :extra, primary_key: :identifier
belongs_to :teacher, :class_name => 'User', :foreign_key => :tea_id # 定义一个方法teacher,该方法通过tea_id来调用User表
belongs_to :school, :class_name => 'School', :foreign_key => :school_id #定义一个方法school,该方法通过school_id来调用School表
@@ -52,7 +52,8 @@ class Course < ActiveRecord::Base
'term',
'is_public',
'description',
- 'class_period'
+ 'class_period',
+ 'open_student'
acts_as_customizable
diff --git a/app/views/courses/_course_form.html.erb b/app/views/courses/_course_form.html.erb
index 4324c5d47..cd8c71132 100644
--- a/app/views/courses/_course_form.html.erb
+++ b/app/views/courses/_course_form.html.erb
@@ -110,7 +110,13 @@
<%= f.check_box :is_public, :style => "margin-left:10px;" %>
<%= l(:label_course_public_info) %>
-
+
+
+
+ <%= f.check_box :open_student, :style => "margin-left:10px;" %>
+ <%= l(:label_course_open_student_info) %>
+
+
<%= f.text_field :course_type, :value => 1 %>
<%= wikitoolbar_for 'course_description' %>
<% @course.custom_field_values.each do |value| %>
diff --git a/app/views/layouts/base_courses.html.erb b/app/views/layouts/base_courses.html.erb
index 04249b3bc..714f3f5f7 100644
--- a/app/views/layouts/base_courses.html.erb
+++ b/app/views/layouts/base_courses.html.erb
@@ -121,7 +121,7 @@
<% end%>
|
- <% if User.current.member_of_course?(@course) %>
+ <% if (User.current.logged? && @course.open_student == 1) || (User.current.member_of_course?(@course)) %>
<%= link_to "#{studentCount(@course)}", course_member_path(@course, :role => 2), :course => '1' %>
<% else %>
diff --git a/config/locales/zh.yml b/config/locales/zh.yml
index 97dceb192..ef0af8ba1 100644
--- a/config/locales/zh.yml
+++ b/config/locales/zh.yml
@@ -288,6 +288,7 @@ zh:
field_class_period: 学时
field_code: 学分
field_is_public: 公开
+ field_open_student: 学生列表公开
field_parent: 上级项目
field_is_in_roadmap: 在路线图中显示
field_login: 昵称
@@ -1799,6 +1800,7 @@ zh:
label_course_join_student: 加入课程
label_public_info: (打钩为公开,不打钩则不公开,若不公开,仅项目成员可见该项目。)
label_course_public_info: (打钩为公开,不打钩则不公开,若不公开,仅课程成员可见该课程。)
+ label_course_open_student_info: (打钩为“学生列表公开”,不打钩为不公开,若不公开,则课程外部人员看不到学生列表)
label_course_view_student: 查看其他课程
label_course_student: 学生
label_homework: 课程作业
diff --git a/config/routes.rb b/config/routes.rb
index 9d0a945c0..a8c5afb96 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -157,7 +157,7 @@ RedmineApp::Application.routes.draw do
resources :forums do
collection do
match 'search_forum', :via => [:get, :post]
-
+
end
member do
post 'create_memo'
From 1d76d559ddddb39cc0d57f89702ed49be05a8c7b Mon Sep 17 00:00:00 2001
From: alan <547533434@qq.com>
Date: Tue, 4 Nov 2014 17:06:16 +0800
Subject: [PATCH 14/18] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8A=9F=E8=83=BD=
=?UTF-8?q?=E7=94=A8=E6=88=B7=E6=90=9C=E7=B4=A2=E7=9A=84=E9=97=AE=E9=A2=98?=
=?UTF-8?q?>?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: alan <547533434@qq.com>
---
app/controllers/users_controller.rb | 2 +-
app/models/user.rb | 10 ++++++++--
app/views/users/index.html.erb | 10 ++++++++--
app/views/users/search.html.erb | 6 +++++-
config/locales/zh.yml | 4 ++++
5 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 7e6e3d04a..5357c43ce 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -374,7 +374,7 @@ class UsersController < ApplicationController
"show_changesets" => true
}
scope = User.logged.status(@status)
- scope = scope.like(params[:name]) if params[:name].present?
+ scope = scope.like(params[:name],params[:search_by][:id]) if params[:name].present?
@user_count = scope.count
@user_pages = Paginator.new @user_count, @limit, params['page']
@user_base_tag = params[:id] ? 'base_users':'users_base'
diff --git a/app/models/user.rb b/app/models/user.rb
index 1e6c21c71..93356f58c 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -198,13 +198,19 @@ class User < Principal
}
scope :sorted, lambda { order(*User.fields_for_order_statement)}
- scope :like, lambda {|arg|
+ scope :like, lambda {|arg, type|
if arg.blank?
where(nil)
else
pattern = "%#{arg.to_s.strip.downcase}%"
#where(" LOWER(concat(lastname, firstname)) LIKE :p ", :p => pattern)
- where(" LOWER(login) LIKE :p ", :p => pattern)
+ if type == "0"
+ where(" LOWER(login) LIKE :p ", :p => pattern)
+ elsif type == "1"
+ where(" LOWER(concat(lastname, firstname)) LIKE :p ", :p => pattern)
+ else
+ where(" LOWER(mail) LIKE :p ", :p => pattern)
+ end
end
}
diff --git a/app/views/users/index.html.erb b/app/views/users/index.html.erb
index 25c1c15c8..65e1bf2f5 100644
--- a/app/views/users/index.html.erb
+++ b/app/views/users/index.html.erb
@@ -8,8 +8,10 @@
alert("搜索条件不能为空");
return;
}
+
$("#search_user_form").submit();
}
+
@@ -21,8 +23,12 @@
|
-
- <%= text_field_tag 'name', params[:name], :size => 30 %>
+
+
+ <%= select "search_by", "id",
+ { l(:label_search_by_login) => "0", l(:label_search_by_name) => "1", l(:label_search_by_email) => "2" },
+ :size => 20 %>
+ <%= text_field_tag 'name', params[:name], :size => 30 %>
<%#= submit_tag l(:label_search), :class => "enterprise", :name => nil %>
diff --git a/app/views/users/search.html.erb b/app/views/users/search.html.erb
index fa252ada0..f5bbc3b8d 100644
--- a/app/views/users/search.html.erb
+++ b/app/views/users/search.html.erb
@@ -19,7 +19,11 @@
|
-
+
+
+ <%= select "search_by", "id",
+ { l(:label_search_by_login) => "0", l(:label_search_by_name) => "1", l(:label_search_by_email) => "2" },
+ :size => 20 %>
<%= text_field_tag 'name', params[:name], :size => 30 %>
<%#= submit_tag l(:label_search), :class => "enterprise", :name => nil %>
diff --git a/config/locales/zh.yml b/config/locales/zh.yml
index ef0af8ba1..8e2e1b28b 100644
--- a/config/locales/zh.yml
+++ b/config/locales/zh.yml
@@ -852,6 +852,10 @@ zh:
label_roadmap_due_in: "截止日期到 %{value}"
label_roadmap_overdue: "%{value} 延期"
label_roadmap_no_issues: 该版本没有问题
+ label_user_search_type: 搜索类型
+ label_search_by_login: 昵称
+ label_search_by_name: 名字
+ label_search_by_email: 邮箱
label_search: 搜索
label_result_plural: 结果
label_all_words: 所有单词
From 2ac9456201212d49b85366e602f4d8c8a48e0007 Mon Sep 17 00:00:00 2001
From: alan <547533434@qq.com>
Date: Tue, 4 Nov 2014 17:14:18 +0800
Subject: [PATCH 15/18] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=8A=9F=E8=83=BD=
=?UTF-8?q?=E7=AE=A1=E7=90=86=E5=91=98=E5=9C=A8=E7=94=A8=E6=88=B7=E5=88=97?=
=?UTF-8?q?=E8=A1=A8=E4=B8=AD=E9=80=9A=E8=BF=87=E7=94=A8=E6=88=B7=E7=9A=84?=
=?UTF-8?q?=E2=80=9C=E5=90=8D=E5=AD=97=E2=80=9D=E5=92=8C=E2=80=9C=E9=82=AE?=
=?UTF-8?q?=E4=BB=B6=E5=9C=B0=E5=9D=80=E2=80=9D=E6=9D=A5=E6=90=9C=E7=B4=A2?=
=?UTF-8?q?=E7=94=A8=E6=88=B7>=20Signed-off-by:=20alan=20<547533434@qq.com?=
=?UTF-8?q?>?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/controllers/admin_controller.rb | 2 +-
app/views/admin/search.html.erb | 5 ++++-
app/views/admin/users.html.erb | 5 ++++-
3 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb
index 3326d0b1a..9b1e045e3 100644
--- a/app/controllers/admin_controller.rb
+++ b/app/controllers/admin_controller.rb
@@ -126,7 +126,7 @@ class AdminController < ApplicationController
@status = params[:status] || 1
scope = User.logged.status(@status)
- scope = scope.like(params[:name]) if params[:name].present?
+ scope = scope.like(params[:name],params[:search_by][:id]) if params[:name].present?
@user_count = scope.count
@user_pages = Paginator.new @user_count, @limit, params['page']
@user_base_tag = params[:id] ? 'base_users':'base'
diff --git a/app/views/admin/search.html.erb b/app/views/admin/search.html.erb
index 5d49d84fa..758c7b32f 100644
--- a/app/views/admin/search.html.erb
+++ b/app/views/admin/search.html.erb
@@ -17,7 +17,10 @@
<%= select_tag 'group_id', content_tag('option') + options_from_collection_for_select(@groups, :id, :name, params[:group_id].to_i), :onchange => "this.form.submit(); return false;" %>
<% end %>
-
+
+ <%= select "search_by", "id",
+ { l(:label_search_by_login) => "0", l(:label_search_by_name) => "1", l(:label_search_by_email) => "2" },
+ :size => 20 %>
<%= text_field_tag 'name', params[:name], :size => 30 %>
<%= submit_tag l(:label_search), :class => "small", :name => nil %>
diff --git a/app/views/admin/users.html.erb b/app/views/admin/users.html.erb
index 7bbdf1c3e..12aa95a16 100644
--- a/app/views/admin/users.html.erb
+++ b/app/views/admin/users.html.erb
@@ -17,7 +17,10 @@
<%= select_tag 'group_id', content_tag('option') + options_from_collection_for_select(@groups, :id, :name, params[:group_id].to_i), :onchange => "this.form.submit(); return false;" %>
<% end %>
-
+
+ <%= select "search_by", "id",
+ { l(:label_search_by_login) => "0", l(:label_search_by_name) => "1", l(:label_search_by_email) => "2" },
+ :size => 20 %>
<%= text_field_tag 'name', params[:name], :size => 30 %>
<%= submit_tag l(:label_search), :class => "small", :name => nil %>
From 591fc409b3b20a5caff3099d3bf1ec5cced017db Mon Sep 17 00:00:00 2001
From: alan <547533434@qq.com>
Date: Wed, 5 Nov 2014 15:01:36 +0800
Subject: [PATCH 16/18] =?UTF-8?q?=E4=BF=AE=E6=94=B9bug =20Signed-off-by:=20alan=20<547533434@qq.com?=
=?UTF-8?q?>?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/controllers/auto_completes_controller.rb | 6 +-
app/views/issues/_form.html.erb | 9 +-
config/routes.rb | 2 +-
public/javascripts/application.js | 916 +++++++++----------
4 files changed, 471 insertions(+), 462 deletions(-)
diff --git a/app/controllers/auto_completes_controller.rb b/app/controllers/auto_completes_controller.rb
index 9e7467bfc..205d4aa01 100644
--- a/app/controllers/auto_completes_controller.rb
+++ b/app/controllers/auto_completes_controller.rb
@@ -29,7 +29,11 @@ class AutoCompletesController < ApplicationController
@issues += scope.where("LOWER(#{Issue.table_name}.subject) LIKE LOWER(?)", "%#{q}%").order("#{Issue.table_name}.id DESC").limit(10).all
@issues.compact!
end
- render :layout => false
+ #render :layout => false
+ render :json => @issues.map {|issue| {
+ 'value' => issue[:subject]
+
+ }}
end
diff --git a/app/views/issues/_form.html.erb b/app/views/issues/_form.html.erb
index c19096f99..fb2fa9e55 100644
--- a/app/views/issues/_form.html.erb
+++ b/app/views/issues/_form.html.erb
@@ -30,8 +30,13 @@
<% if @issue.safe_attribute? 'subject' %>
<%= f.text_field :subject, :size => 80, :maxlength => 255, :required => true, :style => "font-size:small" %>
-<%= javascript_tag "observeAutocompleteField('issue_subject', '#{escape_javascript auto_complete_issues_path(:project_id => @project, :scope => (Setting.cross_project_issue_relations? ? 'all' : nil))}')" %>
-
+<%= javascript_tag do %>
+ observeAutocompleteField('issue_subject', '<%= escape_javascript auto_complete_issues_path(:project_id => @project,:scope => (Setting.cross_project_issue_relations? ? 'all' : nil)) %>',
+ { select: function(event, ui) {
+ $('input#issue_subject').val(ui.item.value);
+ }
+ });
+<% end %>
<% end %>
diff --git a/config/routes.rb b/config/routes.rb
index a8c5afb96..21949afd4 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -612,7 +612,7 @@ RedmineApp::Application.routes.draw do
get 'test_connection', :as => 'try_connection'
end
collection do
- get 'autocomplete_for_new_user'
+ get 'autocomplete_for_new_user'
end
end
diff --git a/public/javascripts/application.js b/public/javascripts/application.js
index 1dedc1b8c..e4c5d4089 100644
--- a/public/javascripts/application.js
+++ b/public/javascripts/application.js
@@ -1,419 +1,419 @@
//= require_directory ./rateable
/* Redmine - project management software
- Copyright (C) 2006-2013 Jean-Philippe Lang */
+ Copyright (C) 2006-2013 Jean-Philippe Lang */
function cleanArray (actual){
- var newArray = new Array();
+ var newArray = new Array();
for (var i = 0; i< actual.length; i++){
- if (actual[i]){
- newArray.push(actual[i]);
- }
+ if (actual[i]){
+ newArray.push(actual[i]);
+ }
}
- return newArray;
+ return newArray;
}
function checkAll(id, checked) {
- if (checked) {
- $('#'+id).find('input[type=checkbox]').attr('checked', true);
- } else {
- $('#'+id).find('input[type=checkbox]').removeAttr('checked');
- }
+ if (checked) {
+ $('#'+id).find('input[type=checkbox]').attr('checked', true);
+ } else {
+ $('#'+id).find('input[type=checkbox]').removeAttr('checked');
+ }
}
function toggleCheckboxesBySelector(selector) {
- var all_checked = true;
- $(selector).each(function(index) {
- if (!$(this).is(':checked')) { all_checked = false; }
- });
- $(selector).attr('checked', !all_checked);
+ var all_checked = true;
+ $(selector).each(function(index) {
+ if (!$(this).is(':checked')) { all_checked = false; }
+ });
+ $(selector).attr('checked', !all_checked);
}
function showAndScrollTo(id, focus) {
- $('#'+id).show();
- if (focus !== null) {
- $('#'+focus).focus();
- }
- $('html, body').animate({scrollTop: $('#'+id).offset().top}, 400);
+ $('#'+id).show();
+ if (focus !== null) {
+ $('#'+focus).focus();
+ }
+ $('html, body').animate({scrollTop: $('#'+id).offset().top}, 400);
}
function toggleRowGroup(el) {
- var tr = $(el).parents('tr').first();
- var n = tr.next();
- tr.toggleClass('open');
- while (n.length && !n.hasClass('group')) {
- n.toggle();
- n = n.next('tr');
- }
+ var tr = $(el).parents('tr').first();
+ var n = tr.next();
+ tr.toggleClass('open');
+ while (n.length && !n.hasClass('group')) {
+ n.toggle();
+ n = n.next('tr');
+ }
}
function collapseAllRowGroups(el) {
- var tbody = $(el).parents('tbody').first();
- tbody.children('tr').each(function(index) {
- if ($(this).hasClass('group')) {
- $(this).removeClass('open');
- } else {
- $(this).hide();
- }
- });
+ var tbody = $(el).parents('tbody').first();
+ tbody.children('tr').each(function(index) {
+ if ($(this).hasClass('group')) {
+ $(this).removeClass('open');
+ } else {
+ $(this).hide();
+ }
+ });
}
function expandAllRowGroups(el) {
- var tbody = $(el).parents('tbody').first();
- tbody.children('tr').each(function(index) {
- if ($(this).hasClass('group')) {
- $(this).addClass('open');
- } else {
- $(this).show();
- }
- });
+ var tbody = $(el).parents('tbody').first();
+ tbody.children('tr').each(function(index) {
+ if ($(this).hasClass('group')) {
+ $(this).addClass('open');
+ } else {
+ $(this).show();
+ }
+ });
}
function toggleAllRowGroups(el) {
- var tr = $(el).parents('tr').first();
- if (tr.hasClass('open')) {
- collapseAllRowGroups(el);
- } else {
- expandAllRowGroups(el);
- }
+ var tr = $(el).parents('tr').first();
+ if (tr.hasClass('open')) {
+ collapseAllRowGroups(el);
+ } else {
+ expandAllRowGroups(el);
+ }
}
function toggleFieldset(el) {
- var fieldset = $(el).parents('fieldset').first();
- fieldset.toggleClass('collapsed');
- fieldset.children('div').toggle();
+ var fieldset = $(el).parents('fieldset').first();
+ fieldset.toggleClass('collapsed');
+ fieldset.children('div').toggle();
}
function hideFieldset(el) {
- var fieldset = $(el).parents('fieldset').first();
- fieldset.toggleClass('collapsed');
- fieldset.children('div').hide();
+ var fieldset = $(el).parents('fieldset').first();
+ fieldset.toggleClass('collapsed');
+ fieldset.children('div').hide();
}
function initFilters(){
- $('#add_filter_select').change(function(){
- addFilter($(this).val(), '', []);
- });
- $('#filters-table td.field input[type=checkbox]').each(function(){
- toggleFilter($(this).val());
- });
- $('#filters-table td.field input[type=checkbox]').live('click',function(){
- toggleFilter($(this).val());
- });
- $('#filters-table .toggle-multiselect').live('click',function(){
- toggleMultiSelect($(this).siblings('select'));
- });
- $('#filters-table input[type=text]').live('keypress', function(e){
- if (e.keyCode == 13) submit_query_form("query_form");
- });
+ $('#add_filter_select').change(function(){
+ addFilter($(this).val(), '', []);
+ });
+ $('#filters-table td.field input[type=checkbox]').each(function(){
+ toggleFilter($(this).val());
+ });
+ $('#filters-table td.field input[type=checkbox]').live('click',function(){
+ toggleFilter($(this).val());
+ });
+ $('#filters-table .toggle-multiselect').live('click',function(){
+ toggleMultiSelect($(this).siblings('select'));
+ });
+ $('#filters-table input[type=text]').live('keypress', function(e){
+ if (e.keyCode == 13) submit_query_form("query_form");
+ });
}
function addFilter(field, operator, values) {
- var fieldId = field.replace('.', '_');
- var tr = $('#tr_'+fieldId);
- if (tr.length > 0) {
- tr.show();
- } else {
- buildFilterRow(field, operator, values);
- }
- $('#cb_'+fieldId).attr('checked', true);
- toggleFilter(field);
- $('#add_filter_select').val('').children('option').each(function(){
- if ($(this).attr('value') == field) {
- $(this).attr('disabled', true);
+ var fieldId = field.replace('.', '_');
+ var tr = $('#tr_'+fieldId);
+ if (tr.length > 0) {
+ tr.show();
+ } else {
+ buildFilterRow(field, operator, values);
}
- });
+ $('#cb_'+fieldId).attr('checked', true);
+ toggleFilter(field);
+ $('#add_filter_select').val('').children('option').each(function(){
+ if ($(this).attr('value') == field) {
+ $(this).attr('disabled', true);
+ }
+ });
}
function buildFilterRow(field, operator, values) {
- var fieldId = field.replace('.', '_');
- var filterTable = $("#filters-table");
- var filterOptions = availableFilters[field];
- var operators = operatorByType[filterOptions['type']];
- var filterValues = filterOptions['values'];
- var i, select;
+ var fieldId = field.replace('.', '_');
+ var filterTable = $("#filters-table");
+ var filterOptions = availableFilters[field];
+ var operators = operatorByType[filterOptions['type']];
+ var filterValues = filterOptions['values'];
+ var i, select;
- var tr = $('').attr('id', 'tr_'+fieldId).html(
- ' | ' +
- ' | ' +
- ' | '
- );
- filterTable.append(tr);
-
- select = tr.find('td.operator select');
- for (i=0;i').val(operators[i]).text(operatorLabels[operators[i]]);
- if (operators[i] == operator) { option.attr('selected', true); }
- select.append(option);
- }
- select.change(function(){ toggleOperator(field); });
-
- switch (filterOptions['type']){
- case "list":
- case "list_optional":
- case "list_status":
- case "list_subprojects":
- tr.find('td.values').append(
- '' +
- ' 复选/multi-select'
+ var tr = $('').attr('id', 'tr_'+fieldId).html(
+ ' | ' +
+ ' | ' +
+ ' | '
);
- select = tr.find('td.values select');
- if (values.length > 1) { select.attr('multiple', true); }
- for (i=0;i');
- if ($.isArray(filterValue)) {
- option.val(filterValue[1]).text(filterValue[0]);
- if ($.inArray(filterValue[1], values) > -1) {option.attr('selected', true);}
- } else {
- option.val(filterValue).text(filterValue);
- if ($.inArray(filterValue, values) > -1) {option.attr('selected', true);}
- }
- select.append(option);
+ filterTable.append(tr);
+
+ select = tr.find('td.operator select');
+ for (i=0;i').val(operators[i]).text(operatorLabels[operators[i]]);
+ if (operators[i] == operator) { option.attr('selected', true); }
+ select.append(option);
}
- break;
- case "date":
- case "date_past":
- tr.find('td.values').append(
- '' +
- ' ' +
- ' '+labelDayPlural+''
- );
- $('#values_'+fieldId+'_1').val(values[0]).datepicker(datepickerOptions);
- $('#values_'+fieldId+'_2').val(values[1]).datepicker(datepickerOptions);
- $('#values_'+fieldId).val(values[0]);
- break;
- case "string":
- case "text":
- tr.find('td.values').append(
- ''
- );
- $('#values_'+fieldId).val(values[0]);
- break;
- case "relation":
- tr.find('td.values').append(
- '' +
- ''
- );
- $('#values_'+fieldId).val(values[0]);
- select = tr.find('td.values select');
- for (i=0;i');
- option.val(filterValue[1]).text(filterValue[0]);
- if (values[0] == filterValue[1]) { option.attr('selected', true); }
- select.append(option);
+ select.change(function(){ toggleOperator(field); });
+
+ switch (filterOptions['type']){
+ case "list":
+ case "list_optional":
+ case "list_status":
+ case "list_subprojects":
+ tr.find('td.values').append(
+ '' +
+ ' 复选/multi-select'
+ );
+ select = tr.find('td.values select');
+ if (values.length > 1) { select.attr('multiple', true); }
+ for (i=0;i');
+ if ($.isArray(filterValue)) {
+ option.val(filterValue[1]).text(filterValue[0]);
+ if ($.inArray(filterValue[1], values) > -1) {option.attr('selected', true);}
+ } else {
+ option.val(filterValue).text(filterValue);
+ if ($.inArray(filterValue, values) > -1) {option.attr('selected', true);}
+ }
+ select.append(option);
+ }
+ break;
+ case "date":
+ case "date_past":
+ tr.find('td.values').append(
+ '' +
+ ' ' +
+ ' '+labelDayPlural+''
+ );
+ $('#values_'+fieldId+'_1').val(values[0]).datepicker(datepickerOptions);
+ $('#values_'+fieldId+'_2').val(values[1]).datepicker(datepickerOptions);
+ $('#values_'+fieldId).val(values[0]);
+ break;
+ case "string":
+ case "text":
+ tr.find('td.values').append(
+ ''
+ );
+ $('#values_'+fieldId).val(values[0]);
+ break;
+ case "relation":
+ tr.find('td.values').append(
+ '' +
+ ''
+ );
+ $('#values_'+fieldId).val(values[0]);
+ select = tr.find('td.values select');
+ for (i=0;i');
+ option.val(filterValue[1]).text(filterValue[0]);
+ if (values[0] == filterValue[1]) { option.attr('selected', true); }
+ select.append(option);
+ }
+ case "integer":
+ case "float":
+ tr.find('td.values').append(
+ '' +
+ ' '
+ );
+ $('#values_'+fieldId+'_1').val(values[0]);
+ $('#values_'+fieldId+'_2').val(values[1]);
+ break;
}
- case "integer":
- case "float":
- tr.find('td.values').append(
- '' +
- ' '
- );
- $('#values_'+fieldId+'_1').val(values[0]);
- $('#values_'+fieldId+'_2').val(values[1]);
- break;
- }
}
function toggleFilter(field) {
- var fieldId = field.replace('.', '_');
- if ($('#cb_' + fieldId).is(':checked')) {
- $("#operators_" + fieldId).show().removeAttr('disabled');
- toggleOperator(field);
- } else {
- $("#operators_" + fieldId).hide().attr('disabled', true);
- enableValues(field, []);
- }
+ var fieldId = field.replace('.', '_');
+ if ($('#cb_' + fieldId).is(':checked')) {
+ $("#operators_" + fieldId).show().removeAttr('disabled');
+ toggleOperator(field);
+ } else {
+ $("#operators_" + fieldId).hide().attr('disabled', true);
+ enableValues(field, []);
+ }
}
function enableValues(field, indexes) {
- var fieldId = field.replace('.', '_');
- $('#tr_'+fieldId+' td.values .value').each(function(index) {
- if ($.inArray(index, indexes) >= 0) {
- $(this).removeAttr('disabled');
- $(this).parents('span').first().show();
- } else {
- $(this).val('');
- $(this).attr('disabled', true);
- $(this).parents('span').first().hide();
- }
+ var fieldId = field.replace('.', '_');
+ $('#tr_'+fieldId+' td.values .value').each(function(index) {
+ if ($.inArray(index, indexes) >= 0) {
+ $(this).removeAttr('disabled');
+ $(this).parents('span').first().show();
+ } else {
+ $(this).val('');
+ $(this).attr('disabled', true);
+ $(this).parents('span').first().hide();
+ }
- if ($(this).hasClass('group')) {
- $(this).addClass('open');
- } else {
- $(this).show();
- }
- });
+ if ($(this).hasClass('group')) {
+ $(this).addClass('open');
+ } else {
+ $(this).show();
+ }
+ });
}
function toggleOperator(field) {
- var fieldId = field.replace('.', '_');
- var operator = $("#operators_" + fieldId);
- switch (operator.val()) {
- case "!*":
- case "*":
- case "t":
- case "ld":
- case "w":
- case "lw":
- case "l2w":
- case "m":
- case "lm":
- case "y":
- case "o":
- case "c":
- enableValues(field, []);
- break;
- case "><":
- enableValues(field, [0,1]);
- break;
- case "t+":
- case ">t-":
- case "<":
+ enableValues(field, [0,1]);
+ break;
+ case "t+":
+ case ">t-":
+ case "0) {
- lis.eq(i-1).show();
- }
+ var lis = $(el).parents('div.tabs').first().find('ul').children();
+ var i = 0;
+ while (i0) {
+ lis.eq(i-1).show();
+ }
}
function displayTabsButtons() {
- var lis;
- var tabsWidth = 0;
- var el;
- $('div.tabs').each(function() {
- el = $(this);
- lis = el.find('ul').children();
- lis.each(function(){
- if ($(this).is(':visible')) {
- tabsWidth += $(this).width() + 6;
- }
+ var lis;
+ var tabsWidth = 0;
+ var el;
+ $('div.tabs').each(function() {
+ el = $(this);
+ lis = el.find('ul').children();
+ lis.each(function(){
+ if ($(this).is(':visible')) {
+ tabsWidth += $(this).width() + 6;
+ }
+ });
+ if ((tabsWidth < el.width() - 60) && (lis.first().is(':visible'))) {
+ el.find('div.tabs-buttons').hide();
+ } else {
+ el.find('div.tabs-buttons').show();
+ }
});
- if ((tabsWidth < el.width() - 60) && (lis.first().is(':visible'))) {
- el.find('div.tabs-buttons').hide();
- } else {
- el.find('div.tabs-buttons').show();
- }
- });
}
function setPredecessorFieldsVisibility() {
- var relationType = $('#relation_relation_type');
- if (relationType.val() == "precedes" || relationType.val() == "follows") {
- $('#predecessor_fields').show();
- } else {
- $('#predecessor_fields').hide();
- }
+ var relationType = $('#relation_relation_type');
+ if (relationType.val() == "precedes" || relationType.val() == "follows") {
+ $('#predecessor_fields').show();
+ } else {
+ $('#predecessor_fields').hide();
+ }
}
function showModal(id, width) {
- var el = $('#'+id).first();
- if (el.length === 0 || el.is(':visible')) {return;}
- var title = el.find('h3.title').text();
- el.dialog({
- width: width,
- modal: true,
- resizable: false,
- dialogClass: 'modal',
- title: title
- });
- el.find("input[type=text], input[type=submit]").first().focus();
+ var el = $('#'+id).first();
+ if (el.length === 0 || el.is(':visible')) {return;}
+ var title = el.find('h3.title').text();
+ el.dialog({
+ width: width,
+ modal: true,
+ resizable: false,
+ dialogClass: 'modal',
+ title: title
+ });
+ el.find("input[type=text], input[type=submit]").first().focus();
}
function hideModal(el) {
- var modal;
- if (el) {
- modal = $(el).parents('.ui-dialog-content');
- } else {
- modal = $('#ajax-modal');
- }
- modal.dialog("close");
+ var modal;
+ if (el) {
+ modal = $(el).parents('.ui-dialog-content');
+ } else {
+ modal = $('#ajax-modal');
+ }
+ modal.dialog("close");
}
function submitPreview(url, form, target) {
- $.ajax({
- url: url,
- type: 'post',
- data: $('#'+form).serialize(),
- success: function(data){
- $('#'+target).html(data);
- }
- });
+ $.ajax({
+ url: url,
+ type: 'post',
+ data: $('#'+form).serialize(),
+ success: function(data){
+ $('#'+target).html(data);
+ }
+ });
}
function collapseScmEntry(id) {
- $('.'+id).each(function() {
- if ($(this).hasClass('open')) {
- collapseScmEntry($(this).attr('id'));
- }
- $(this).hide();
- });
- $('#'+id).removeClass('open');
+ $('.'+id).each(function() {
+ if ($(this).hasClass('open')) {
+ collapseScmEntry($(this).attr('id'));
+ }
+ $(this).hide();
+ });
+ $('#'+id).removeClass('open');
}
function expandScmEntry(id) {
- $('.'+id).each(function() {
- $(this).show();
- if ($(this).hasClass('loaded') && !$(this).hasClass('collapsed')) {
- expandScmEntry($(this).attr('id'));
- }
- });
- $('#'+id).addClass('open');
+ $('.'+id).each(function() {
+ $(this).show();
+ if ($(this).hasClass('loaded') && !$(this).hasClass('collapsed')) {
+ expandScmEntry($(this).attr('id'));
+ }
+ });
+ $('#'+id).addClass('open');
}
function scmEntryClick(id, url) {
@@ -432,190 +432,190 @@ function scmEntryClick(id, url) {
}
el.addClass('loading');
$.ajax({
- url: url,
- success: function(data){
- el.after(data);
- el.addClass('open').addClass('loaded').removeClass('loading');
- }
+ url: url,
+ success: function(data){
+ el.after(data);
+ el.addClass('open').addClass('loaded').removeClass('loading');
+ }
});
return true;
}
function randomKey(size) {
- var chars = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z');
- var key = '';
- for (i = 0; i < size; i++) {
- key += chars[Math.floor(Math.random() * chars.length)];
- }
- return key;
+ var chars = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z');
+ var key = '';
+ for (i = 0; i < size; i++) {
+ key += chars[Math.floor(Math.random() * chars.length)];
+ }
+ return key;
}
// Can't use Rails' remote select because we need the form data
function updateIssueFrom(url) {
- $.ajax({
- url: url,
- type: 'post',
- data: $('#issue-form').serialize()
- });
+ $.ajax({
+ url: url,
+ type: 'post',
+ data: $('#issue-form').serialize()
+ });
}
function updateBulkEditFrom(url) {
- $.ajax({
- url: url,
- type: 'post',
- data: $('#bulk_edit_form').serialize()
- });
+ $.ajax({
+ url: url,
+ type: 'post',
+ data: $('#bulk_edit_form').serialize()
+ });
}
function clearMessage(id) {
- $('#'+id).val("");
+ $('#'+id).val("");
}
function observeAutocompleteField(fieldId, url, options) {
- $(document).ready(function() {
- $('#'+fieldId).autocomplete($.extend({
- source: url,
- select: function(e,ui){self.location="/issues/"+ui.item.value;},
- minLength: 2,
- search: function(){$('#'+fieldId).addClass('ajax-loading');},
- response: function(){$('#'+fieldId).removeClass('ajax-loading');
- }
- }, options));
- $('#'+fieldId).addClass('autocomplete');
-
- });
-
+ $(document).ready(function() {
+ $('#'+fieldId).autocomplete($.extend({
+ source: url,
+ select: function(e,ui){self.location="/issues/"+ui.item.value;},
+ minLength: 2,
+ search: function(){$('#'+fieldId).addClass('ajax-loading');},
+ response: function(){$('#'+fieldId).removeClass('ajax-loading');
+ }
+ }, options));
+ $('#'+fieldId).addClass('autocomplete');
+
+ });
+
}
function observeSearchfield(fieldId, targetId, url) {
- $('#'+fieldId).each(function() {
- var $this = $(this);
- $this.addClass('autocomplete');
- $this.attr('data-value-was', $this.val());
- var check = function() {
- var val = $this.val();
- if ($this.attr('data-value-was') != val){
- $this.attr('data-value-was', val);
- $.ajax({
- url: url,
- type: 'get',
- data: {q: $this.val()},
- success: function(data){ if(targetId) $('#'+targetId).html(data); },
- beforeSend: function(){ $this.addClass('ajax-loading'); },
- complete: function(){ $this.removeClass('ajax-loading'); }
- });
- }
- };
- var reset = function() {
- if (timer) {
- clearInterval(timer);
- timer = setInterval(check, 300);
- }
- };
- var timer = setInterval(check, 300);
- $this.bind('keyup click mousemove', reset);
- });
+ $('#'+fieldId).each(function() {
+ var $this = $(this);
+ $this.addClass('autocomplete');
+ $this.attr('data-value-was', $this.val());
+ var check = function() {
+ var val = $this.val();
+ if ($this.attr('data-value-was') != val){
+ $this.attr('data-value-was', val);
+ $.ajax({
+ url: url,
+ type: 'get',
+ data: {q: $this.val()},
+ success: function(data){ if(targetId) $('#'+targetId).html(data); },
+ beforeSend: function(){ $this.addClass('ajax-loading'); },
+ complete: function(){ $this.removeClass('ajax-loading'); }
+ });
+ }
+ };
+ var reset = function() {
+ if (timer) {
+ clearInterval(timer);
+ timer = setInterval(check, 300);
+ }
+ };
+ var timer = setInterval(check, 300);
+ $this.bind('keyup click mousemove', reset);
+ });
}
function observeProjectModules() {
- var f = function() {
- /* Hides trackers and issues custom fields on the new project form when issue_tracking module is disabled */
- if ($('#project_enabled_module_names_issue_tracking').attr('checked')) {
- $('#project_trackers').show();
- }else{
- $('#project_trackers').hide();
- }
- };
+ var f = function() {
+ /* Hides trackers and issues custom fields on the new project form when issue_tracking module is disabled */
+ if ($('#project_enabled_module_names_issue_tracking').attr('checked')) {
+ $('#project_trackers').show();
+ }else{
+ $('#project_trackers').hide();
+ }
+ };
- $(window).load(f);
- $('#project_enabled_module_names_issue_tracking').change(f);
+ $(window).load(f);
+ $('#project_enabled_module_names_issue_tracking').change(f);
}
function initMyPageSortable(list, url) {
- $('#list-'+list).sortable({
- connectWith: '.block-receiver',
- tolerance: 'pointer',
- update: function(){
- $.ajax({
- url: url,
- type: 'post',
- data: {'blocks': $.map($('#list-'+list).children(), function(el){return $(el).attr('id');})}
- });
- }
- });
- $("#list-top, #list-left, #list-right").disableSelection();
+ $('#list-'+list).sortable({
+ connectWith: '.block-receiver',
+ tolerance: 'pointer',
+ update: function(){
+ $.ajax({
+ url: url,
+ type: 'post',
+ data: {'blocks': $.map($('#list-'+list).children(), function(el){return $(el).attr('id');})}
+ });
+ }
+ });
+ $("#list-top, #list-left, #list-right").disableSelection();
}
var warnLeavingUnsavedMessage;
function warnLeavingUnsaved(message) {
- warnLeavingUnsavedMessage = message;
+ warnLeavingUnsavedMessage = message;
- $('form').submit(function(){
- $('textarea').removeData('changed');
- });
- $('textarea').change(function(){
- $(this).data('changed', 'changed');
- });
- window.onbeforeunload = function(){
- var warn = false;
- $('textarea').blur().each(function(){
- if ($(this).data('changed')) {
- warn = true;
- }
+ $('form').submit(function(){
+ $('textarea').removeData('changed');
});
- if (warn) {return warnLeavingUnsavedMessage;}
- };
+ $('textarea').change(function(){
+ $(this).data('changed', 'changed');
+ });
+ window.onbeforeunload = function(){
+ var warn = false;
+ $('textarea').blur().each(function(){
+ if ($(this).data('changed')) {
+ warn = true;
+ }
+ });
+ if (warn) {return warnLeavingUnsavedMessage;}
+ };
}
function setupAjaxIndicator() {
- $('#ajax-indicator').bind('ajaxSend', function(event, xhr, settings) {
+ $('#ajax-indicator').bind('ajaxSend', function(event, xhr, settings) {
- if ($('.ajax-loading').length === 0 && settings.contentType != 'application/octet-stream') {
- $('#ajax-indicator').show();
- }
- });
-
- $('#ajax-indicator').bind('ajaxStop', function() {
- $('#ajax-indicator').hide();
- });
+ if ($('.ajax-loading').length === 0 && settings.contentType != 'application/octet-stream') {
+ $('#ajax-indicator').show();
+ }
+ });
+
+ $('#ajax-indicator').bind('ajaxStop', function() {
+ $('#ajax-indicator').hide();
+ });
}
function hideOnLoad() {
- $('.hol').hide();
+ $('.hol').hide();
}
function addFormObserversForDoubleSubmit() {
- $('form[method=post]').each(function() {
- if (!$(this).hasClass('multiple-submit')) {
- $(this).submit(function(form_submission) {
- if ($(form_submission.target).attr('data-submitted')) {
- form_submission.preventDefault();
- } else {
- $(form_submission.target).attr('data-submitted', true);
+ $('form[method=post]').each(function() {
+ if (!$(this).hasClass('multiple-submit')) {
+ $(this).submit(function(form_submission) {
+ if ($(form_submission.target).attr('data-submitted')) {
+ form_submission.preventDefault();
+ } else {
+ $(form_submission.target).attr('data-submitted', true);
+ }
+ });
}
- });
- }
- });
+ });
}
function blockEventPropagation(event) {
- event.stopPropagation();
- event.preventDefault();
+ event.stopPropagation();
+ event.preventDefault();
}
function toggleAndSettingWordsVal(parent_widget, text_widget, value){
- text_widget.val(value)
- parent_widget.slideToggle(400)
+ text_widget.val(value)
+ parent_widget.slideToggle(400)
}
function transpotUrl (scope) {
- $(scope).each(function(){
- var tmpContent = $(this).html();
- tmpContent = tmpContent.replace(/(^|[^\"\'])(http|ftp|mms|rstp|news|https)(\:\/\/[^<\s\+,,]+)/gi,"$1$2$3<\/a>");
- // tmpContent = tmpContent.replace(/(^|[^\/])(www\.[^<\s\+,,]+)/gi,"$1$2");
- $(this).html(tmpContent);
- });
+ $(scope).each(function(){
+ var tmpContent = $(this).html();
+ tmpContent = tmpContent.replace(/(^|[^\"\'])(http|ftp|mms|rstp|news|https)(\:\/\/[^<\s\+,,]+)/gi,"$1$2$3<\/a>");
+ // tmpContent = tmpContent.replace(/(^|[^\/])(www\.[^<\s\+,,]+)/gi,"$1$2");
+ $(this).html(tmpContent);
+ });
}
$(document).ready(setupAjaxIndicator);
@@ -623,14 +623,14 @@ $(document).ready(hideOnLoad);
$(document).ready(addFormObserversForDoubleSubmit);
function img_thumbnails() {
- $('.thumbnails a').colorbox({rel:'nofollow'});
- $('.attachments').find('a').each(function(index, element) {
- var href_value = $(element).attr('href');
- if (/\.(jpg|png|gif|bmp)$/.test(href_value)) {
- $(element).colorbox({rel:'nofollow'});
- }
+ $('.thumbnails a').colorbox({rel:'nofollow'});
+ $('.attachments').find('a').each(function(index, element) {
+ var href_value = $(element).attr('href');
+ if (/\.(jpg|png|gif|bmp)$/.test(href_value)) {
+ $(element).colorbox({rel:'nofollow'});
+ }
- });
+ });
}
$(document).ready(img_thumbnails);
From 0aae731eef3283c89b6c7be7b62c5408ce519fad Mon Sep 17 00:00:00 2001
From: alan <547533434@qq.com>
Date: Thu, 6 Nov 2014 14:45:59 +0800
Subject: [PATCH 17/18] =?UTF-8?q?=E4=BF=AE=E6=94=B9bug<=E7=82=B9=E5=87=BB?=
=?UTF-8?q?=E6=8E=92=E5=BA=8F=E5=90=8E=E5=86=85=E5=AE=B9=E7=B1=BB=E5=9E=8B?=
=?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=8F=98=E4=B8=BA=E5=85=A8=E9=83=A8=EF=BC=8C?=
=?UTF-8?q?=E4=BD=86=E5=8F=88=E5=B9=B6=E6=9C=AA=E6=98=BE=E7=A4=BA=E5=85=A8?=
=?UTF-8?q?=E9=83=A8=E8=B5=84=E6=BA=90>=20Signed-off-by:=20alan=20<5475334?=
=?UTF-8?q?34@qq.com>?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/models/issue.rb | 2 +-
app/views/files/_project_file.html.erb | 2 +-
app/views/users/new.html.erb | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 6bbcd727f..09e093177 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -1359,7 +1359,7 @@ class Issue < ActiveRecord::Base
# Callback on file attachment
def attachment_added(obj)
- if @current_journal && !obj.new_record?
+ if @current_journal && !obj.new_record? && @current_journal.journalized_id == obj.author_id
@current_journal.details << JournalDetail.new(:property => 'attachment', :prop_key => obj.id, :value => obj.filename)
end
end
diff --git a/app/views/files/_project_file.html.erb b/app/views/files/_project_file.html.erb
index 315314828..bc5b15ab1 100644
--- a/app/views/files/_project_file.html.erb
+++ b/app/views/files/_project_file.html.erb
@@ -52,7 +52,7 @@
<% if attachmenttypes.any? %>
- <%= select_tag "attachment_browse", content_tag(:option, l(:attachment_all), :value => '0') +options_from_collection_for_select(attachmenttypes, "id", "typeName"),
+ <%= select_tag "attachment_browse", content_tag(:option, l(:attachment_all), :value => '0') +options_from_collection_for_select(attachmenttypes, "id", "typeName",params[:type]),
:onchange => "attachmenttypes_searchex(this.value)" %>
<% end %>
<% if sufixtypes.any? %>
diff --git a/app/views/users/new.html.erb b/app/views/users/new.html.erb
index e718956f1..4311fd962 100644
--- a/app/views/users/new.html.erb
+++ b/app/views/users/new.html.erb
@@ -14,7 +14,7 @@
<% if @auth_sources.present? && @auth_sources.any?(&:searchable?) %>
<%= javascript_tag do %>
- observeAutocompleteField('user_login', '<%= escape_javascript autocomplete_for_new_user_auth_sources_path %>', {
+ ('user_login', '<%= escape_javascript autocomplete_for_new_user_auth_sources_path %>', {
select: function(event, ui) {
$('input#user_firstname').val(ui.item.firstname);
$('input#user_lastname').val(ui.item.lastname);
From fd8a8d1fe2ea51e911571c1ba137134f0bca89ca Mon Sep 17 00:00:00 2001
From: alan <547533434@qq.com>
Date: Thu, 6 Nov 2014 15:58:15 +0800
Subject: [PATCH 18/18] Signed-off-by: alan <547533434@qq.com>
---
app/views/files/_project_file.html.erb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/views/files/_project_file.html.erb b/app/views/files/_project_file.html.erb
index bc5b15ab1..f52b7d353 100644
--- a/app/views/files/_project_file.html.erb
+++ b/app/views/files/_project_file.html.erb
@@ -52,7 +52,7 @@
<% if attachmenttypes.any? %>
- <%= select_tag "attachment_browse", content_tag(:option, l(:attachment_all), :value => '0') +options_from_collection_for_select(attachmenttypes, "id", "typeName",params[:type]),
+ <%= select_tag "attachment_browse", content_tag(:option, l(:attachment_all), :value => '0') +options_from_collection_for_select(attachmenttypes, "id", "typeName",params[:type]),
:onchange => "attachmenttypes_searchex(this.value)" %>
<% end %>
<% if sufixtypes.any? %>
| | |