diff --git a/CHANGELOG.md b/CHANGELOG.md index d24953c4..a5250040 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,21 @@ # Changelog +## [v3.1.0](https://forgeplus.trustie.net/projects/jasder/forgeplus/releases) - 2021-06-09 + +* ENHANCEMENTS + * ADD 用户活动统计图表功能 + * ADD 用户精选项目功能 + * ADD 用户贡献度统计图表功能 + * ADD 用户开发能力数据统计工 + * ADD 用户角色定位展示功能 + * ADD 用户专业定位标签展示功能 + * ADD 修改用户基本资料功能 + * ADD 更改密码功能 + * ADD 用户个人主页基本现在展示可配置功能 + +* BUGFIXES + * Fix 解决一些bug + * Fix 优化美化页面 -## [v3.0.4](https://forgeplus.trustie.net/projects/jasder/forgeplus/releases) - 2021-05-24 * BUGFIXES * Fix 在线修改文件,页面文件显不及时的问题(46049) diff --git a/Gemfile.lock b/Gemfile.lock index 015c0a51..b1dc2cca 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -176,7 +176,9 @@ GEM mimemagic (~> 0.3.2) maruku (0.7.3) method_source (0.9.2) - mimemagic (0.3.4) + mimemagic (0.3.10) + nokogiri (~> 1) + rake mini_mime (1.0.2) mini_portile2 (2.4.0) minitest (5.14.0) diff --git a/LICENSE b/LICENSE index 8aa26455..2b9b385e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,124 @@ -MIT License +木兰宽松许可证, 第2版 -Copyright (c) [year] [fullname] +2020年1月 http://license.coscl.org.cn/MulanPSL2 -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +0. 定义 -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +“软件” 是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。 + +“贡献” 是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。 + +“贡献者” 是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。 + +“法人实体” 是指提交贡献的机构及其“关联实体”。 + +“关联实体” 是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。 + +1. 授予版权许可 + +每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。 + +2. 授予专利许可 + +每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。 + +3. 无商标许可 + +“本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定的声明义务而必须使用除外。 + +4. 分发限制 + +您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。 + +5. 免责声明与责任限制 + +“软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。 + +6. 语言 + +“本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文版为准。 + +条款结束 + +如何将木兰宽松许可证,第2版,应用到您的软件 + +如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步: + +1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字; + +2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中; + +3, 请将如下声明文本放入每个源文件的头部注释中。 + +Copyright (c) [Year] [name of copyright holder] +[Software Name] is licensed under Mulan PSL v2. +You can use this software according to the terms and conditions of the Mulan PSL v2. +You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +See the Mulan PSL v2 for more details. +Mulan Permissive Software License,Version 2 +Mulan Permissive Software License,Version 2 (Mulan PSL v2) + +January 2020 http://license.coscl.org.cn/MulanPSL2 + +Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions: + +0. Definition + +Software means the program and related documents which are licensed under this License and comprise all Contribution(s). + +Contribution means the copyrightable work licensed by a particular Contributor under this License. + +Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License. + +Legal Entity means the entity making a Contribution and all its Affiliates. + +Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, ‘control’ means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity. + +1. Grant of Copyright License + +Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not. + +2. Grant of Patent License + +Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken. + +3. No Trademark License + +No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in section 4. + +4. Distribution Restriction + +You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software. + +5. Disclaimer of Warranty and Limitation of Liability + +THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +6. Language + +THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL. + +END OF THE TERMS AND CONDITIONS + +How to Apply the Mulan Permissive Software License,Version 2 (Mulan PSL v2) to Your Software + +To apply the Mulan PSL v2 to your work, for easy identification by recipients, you are suggested to complete following three steps: + +Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner; +Create a file named "LICENSE" which contains the whole context of this License in the first directory of your software package; +Attach the statement to the appropriate annotated syntax at the beginning of each source file. +Copyright (c) [Year] [name of copyright holder] +[Software Name] is licensed under Mulan PSL v2. +You can use this software according to the terms and conditions of the Mulan PSL v2. +You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +See the Mulan PSL v2 for more details. \ No newline at end of file diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 3d002524..4b53ec62 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -210,6 +210,25 @@ class AccountsController < ApplicationController # session[:user_id] = @user.id end + def change_password + @user = User.find_by(login: params[:login]) + return render_error("未找到相关用户!") if @user.blank? + return render_error("旧密码不正确") unless @user.check_password?(params[:old_password]) + + sync_params = { + password: params[:password].to_s, + email: @user.mail + } + + interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params) + if interactor.success? + @user.update_attribute(:password, params[:password]) + render_ok + else + render_error(interactor.error) + end + end + # 忘记密码 def reset_password begin diff --git a/app/controllers/admins/auth_schools_controller.rb b/app/controllers/admins/auth_schools_controller.rb index e7c0253b..825c04cd 100644 --- a/app/controllers/admins/auth_schools_controller.rb +++ b/app/controllers/admins/auth_schools_controller.rb @@ -32,7 +32,7 @@ class Admins::AuthSchoolsController < Admins::BaseController def search_manager school = School.find_by(id: params[:school_id]) user_ids = school&.ec_school_users&.pluck(:user_id) - @users = User.where.not(id: user_ids).where("concat(lastname, firstname) like ?", "%#{params[:name].strip.to_s}%").limit(10) + @users = User.where.not(id: user_ids).where("CONCAT_WS(lastname, firstname, nickname) like ?", "%#{params[:name].strip.to_s}%").limit(10) end # 添加认证学校管理员 diff --git a/app/controllers/admins/laboratories_controller.rb b/app/controllers/admins/laboratories_controller.rb index f397b0f3..46463fed 100644 --- a/app/controllers/admins/laboratories_controller.rb +++ b/app/controllers/admins/laboratories_controller.rb @@ -32,7 +32,7 @@ class Admins::LaboratoriesController < Admins::BaseController keyword = params[:keyword].to_s.strip if keyword.present? - like_sql = 'shixuns.name LIKE :keyword OR CONCAT(users.lastname, users.firstname) LIKE :keyword '\ + like_sql = 'shixuns.name LIKE :keyword OR CONCAT_WS(users.lastname, users.firstname, users.nickname) LIKE :keyword '\ 'OR mirror_repositories.name LIKE :keyword' shixuns = shixuns.joins(:user, :mirror_repositories).where(like_sql, keyword: "%#{keyword}%") end @@ -48,7 +48,7 @@ class Admins::LaboratoriesController < Admins::BaseController keyword = params[:keyword].to_s.strip if keyword.present? - like_sql = 'subjects.name LIKE :keyword OR CONCAT(users.lastname, users.firstname) LIKE :keyword' + like_sql = 'subjects.name LIKE :keyword OR CONCAT_WS(users.lastname, users.firstname, users.nickname) LIKE :keyword' subjects = subjects.joins(:user).where(like_sql, keyword: "%#{keyword}%") end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 6875b815..8536147c 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -773,7 +773,26 @@ class ApplicationController < ActionController::Base def base_url request.base_url end + + def convert_image! + @image = params[:image] || user_params[:image] + return unless @image.present? + max_size = EduSetting.get('upload_avatar_max_size') || 2 * 1024 * 1024 # 2M + if @image.class == ActionDispatch::Http::UploadedFile + render_error('请上传文件') if @image.size.zero? + render_error('文件大小超过限制') if @image.size > max_size.to_i + else + image = @image.to_s.strip + return render_error('请上传正确的图片') if image.blank? + @image = Util.convert_base64_image(image, max_size: max_size.to_i) + end + rescue Base64ImageConverter::Error => ex + render_error(ex.message) + end + def avatar_path(object) + ApplicationController.helpers.disk_filename(object.class, object.id) + end private def object_not_found diff --git a/app/controllers/applied_projects_controller.rb b/app/controllers/applied_projects_controller.rb new file mode 100644 index 00000000..e2f55b27 --- /dev/null +++ b/app/controllers/applied_projects_controller.rb @@ -0,0 +1,13 @@ +class AppliedProjectsController < ApplicationController + before_action :require_login + def create + @applied_project = Projects::ApplyJoinService.call(current_user, applied_params) + rescue Projects::ApplyJoinService::Error => ex + render_error(ex.message) + end + + private + def applied_params + params.require(:applied_project).permit(:code, :role) + end +end \ No newline at end of file diff --git a/app/controllers/members_controller.rb b/app/controllers/members_controller.rb index 1a62bc29..e3e58be1 100644 --- a/app/controllers/members_controller.rb +++ b/app/controllers/members_controller.rb @@ -27,7 +27,7 @@ class MembersController < ApplicationController scope = @project.members.includes(:roles, user: :user_extension) search = params[:search].to_s.downcase role = params[:role].to_s - scope = scope.joins(:user).where("LOWER(concat(users.lastname, users.firstname, users.login, users.mail)) LIKE ?", "%#{search.split(" ").join('|')}%") if search.present? + scope = scope.joins(:user).where("LOWER(CONCAT_WS(users.lastname, users.firstname, users.login, users.mail, users.nickname)) LIKE ?", "%#{search.split(" ").join('|')}%") if search.present? scope = scope.joins(:roles).where("roles.name LIKE ?", "%#{role}%") if role.present? @total_count = scope.size diff --git a/app/controllers/organizations/organization_users_controller.rb b/app/controllers/organizations/organization_users_controller.rb index 8a7755a1..d2d6963a 100644 --- a/app/controllers/organizations/organization_users_controller.rb +++ b/app/controllers/organizations/organization_users_controller.rb @@ -5,7 +5,7 @@ class Organizations::OrganizationUsersController < Organizations::BaseController def index @organization_users = @organization.organization_users.includes(:user) search = params[:search].to_s.downcase - @organization_users = @organization_users.joins(:user).where("LOWER(CONCAT_WS(users.lastname, users.firstname, users.login, users.mail)) LIKE ?", "%#{search.split(" ").join('|')}%") if search.present? + @organization_users = @organization_users.joins(:user).where("LOWER(CONCAT_WS(users.lastname, users.firstname, users.login, users.mail, users.nickname)) LIKE ?", "%#{search.split(" ").join('|')}%") if search.present? @organization_users = kaminari_paginate(@organization_users) end diff --git a/app/controllers/organizations/organizations_controller.rb b/app/controllers/organizations/organizations_controller.rb index 29cb15a6..7be9390d 100644 --- a/app/controllers/organizations/organizations_controller.rb +++ b/app/controllers/organizations/organizations_controller.rb @@ -70,25 +70,6 @@ class Organizations::OrganizationsController < Organizations::BaseController end private - def convert_image! - return unless params[:image].present? - max_size = EduSetting.get('upload_avatar_max_size') || 2 * 1024 * 1024 # 2M - if params[:image].class == ActionDispatch::Http::UploadedFile - @image = params[:image] - render_error('请上传文件') if @image.size.zero? - render_error('文件大小超过限制') if @image.size > max_size.to_i - else - image = params[:image].to_s.strip - return render_error('请上传正确的图片') if image.blank? - @image = Util.convert_base64_image(image, max_size: max_size.to_i) - end - rescue Base64ImageConverter::Error => ex - render_error(ex.message) - end - - def avatar_path(organization) - ApplicationController.helpers.disk_filename(organization.class, organization.id) - end def organization_params params.permit(:name, :description, :website, :location, diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index b748123f..440e55f4 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -184,7 +184,7 @@ class ProjectsController < ApplicationController end def recommend - @projects = Project.recommend.includes(:repository, :project_category, :owner).order(id: :desc) + @projects = Project.recommend.includes(:repository, :project_category, :owner).order(visits: :desc) end def about diff --git a/app/controllers/users/applied_messages_controller.rb b/app/controllers/users/applied_messages_controller.rb index e80cabf9..950caa2b 100644 --- a/app/controllers/users/applied_messages_controller.rb +++ b/app/controllers/users/applied_messages_controller.rb @@ -9,7 +9,7 @@ class Users::AppliedMessagesController < Users::BaseController private def check_auth - return render_forbidden unless observed_logged_user? + return render_forbidden unless current_user.admin? || observed_logged_user? end def view_messages diff --git a/app/controllers/users/applied_projects_controller.rb b/app/controllers/users/applied_projects_controller.rb new file mode 100644 index 00000000..3663a6d3 --- /dev/null +++ b/app/controllers/users/applied_projects_controller.rb @@ -0,0 +1,39 @@ +class Users::AppliedProjectsController < Users::BaseController + before_action :check_auth + before_action :find_applied_project, except: [:index] + before_action :find_project, except: [:index] + + def index + @applied_projects = AppliedProject.where(project_id: observed_user.full_admin_projects) + @applied_projects = paginate @applied_projects.order("created_at desc") + end + + # 接受申请 + def accept + @applied_project = Projects::AcceptJoinService.call(current_user, @applied_project) + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + + # 拒绝申请 + def refuse + @applied_project = Projects::RefuseJoinService.call(current_user, @applied_project) + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + + private + def check_auth + return render_forbidden unless current_user.admin? || observed_logged_user? + end + + def find_applied_project + @applied_project = AppliedProject.find_by_id params[:id] + end + + def find_project + @project = @applied_project.project + end +end \ No newline at end of file diff --git a/app/controllers/users/applied_transfer_projects_controller.rb b/app/controllers/users/applied_transfer_projects_controller.rb index b1777f52..a4083394 100644 --- a/app/controllers/users/applied_transfer_projects_controller.rb +++ b/app/controllers/users/applied_transfer_projects_controller.rb @@ -28,7 +28,7 @@ class Users::AppliedTransferProjectsController < Users::BaseController private def check_auth - return render_forbidden unless observed_logged_user? + return render_forbidden unless current_user.admin? || observed_logged_user? end def find_applied_transfer_project diff --git a/app/controllers/users/headmaps_controller.rb b/app/controllers/users/headmaps_controller.rb new file mode 100644 index 00000000..81bd5771 --- /dev/null +++ b/app/controllers/users/headmaps_controller.rb @@ -0,0 +1,26 @@ +class Users::HeadmapsController < Users::BaseController + def index + result = Gitea::User::HeadmapService.call(observed_user.login, start_stamp, end_stamp) + @headmaps = result[2] + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + + private + def start_stamp + if params[:year].present? + Date.new(params[:year], 1).to_time.to_i + else + Date.today.to_time.to_i - 365*24*60*60 + end + end + + def end_stamp + if params[:year].present? + Date.new(params[:year], 1).to_time.to_i + 365*24*60*60 + else + Date.today.to_time.to_i + end + end +end \ No newline at end of file diff --git a/app/controllers/users/is_pinned_projects_controller.rb b/app/controllers/users/is_pinned_projects_controller.rb new file mode 100644 index 00000000..1ddadd27 --- /dev/null +++ b/app/controllers/users/is_pinned_projects_controller.rb @@ -0,0 +1,45 @@ +class Users::IsPinnedProjectsController < Users::BaseController + before_action :private_user_resources!, only: [:pin] + def index + @is_pinned_projects = observed_user.pinned_projects.order(position: :desc, created_at: :asc).includes(project: [:project_category, :project_language, :repository]).order(position: :desc) + @is_pinned_projects = kaminari_paginate(@is_pinned_projects) + end + + def pin + observed_user.is_pinned_project_ids = is_pinned_project_ids + render_ok + rescue ActiveRecord::RecordNotFound => e + render_not_found + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + + def update + @pinned_project = PinnedProject.find_by_id(params[:id]) + @pinned_project.attributes = pinned_project_params + if @pinned_project.save + render_ok + else + render_error + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + + private + def is_pinned_project_ids + if params[:is_pinned_project_ids].present? + return params[:is_pinned_project_ids].select{|id| observed_user.full_member_projects.visible.pluck(:id).include?(id.to_i) } + end + if params[:is_pinned_project_id].present? + return observed_user.is_pinned_project_ids unless observed_user.full_member_projects.visible.pluck(:id).include?(params[:is_pinned_project_id].to_i) + return observed_user.is_pinned_project_ids.include?(params[:is_pinned_project_id].to_i) ? observed_user.is_pinned_project_ids : observed_user.is_pinned_project_ids.push(params[:is_pinned_project_id].to_i) + end + end + + def pinned_project_params + params.require(:pinned_project).permit(:position) + end +end \ No newline at end of file diff --git a/app/controllers/users/project_trends_controller.rb b/app/controllers/users/project_trends_controller.rb new file mode 100644 index 00000000..9edd56f1 --- /dev/null +++ b/app/controllers/users/project_trends_controller.rb @@ -0,0 +1,11 @@ +class Users::ProjectTrendsController < Users::BaseController + + def index + if params[:date].present? + @project_trends = observed_user.project_trends.where("DATE(created_at) = ?", params[:date]) + else + @project_trends = observed_user.project_trends + end + @project_trends = kaminari_paginate(@project_trends.includes(:trend, :project).order(created_at: :desc)) + end +end \ No newline at end of file diff --git a/app/controllers/users/statistics_controller.rb b/app/controllers/users/statistics_controller.rb new file mode 100644 index 00000000..c6cc0d88 --- /dev/null +++ b/app/controllers/users/statistics_controller.rb @@ -0,0 +1,217 @@ +class Users::StatisticsController < Users::BaseController + before_action :preload_develop_data, only: [:develop] + + # 近期活动统计 + def activity + date_range = (1.week.ago.to_date..Date.today).to_a + commit_request = Gitea::User::HeadmapService.call(observed_user.login, 1.week.ago.to_date.to_time.to_i, Date.today.to_time.to_i) + commit_data = commit_request[2] + @date_data = [] + @issue_data = [] + @pull_request_data = [] + @commit_data = [] + date_range.each do |date| + @date_data << date.strftime("%Y.%m.%d") + @issue_data << observed_user.issues.where("DATE(created_on) = ?", date).size + @pull_request_data << observed_user.pull_requests.where("DATE(created_at) = ?", date).size + date_commit_data = commit_data.select{|item| item["timestamp"] == date.to_time.to_i} + @commit_data << (date_commit_data.blank? ? 0 : date_commit_data[0]["contributions"].to_i) + end + render :json => {dates: @date_data, issues_count: @issue_data, pull_requests_count: @pull_request_data, commits_count: @commit_data} + end + + # 开发能力 + def develop + if params[:start_time].present? && params[:end_time].present? + # 影响力 + @influence = (60.0 + @follow_count / (@follow_count + 10.0) * 40.0).to_i + @platform_influence = (60.0 + @platform_follow_count / (@platform_follow_count + 10.0) * 40.0).to_i + # 贡献度 + @contribution = (60.0 + @pullrequest_count / (@pullrequest_count + 10.0) * 40.0).to_i + @platform_contribution = (60.0 + @platform_pullrequest_count / (@platform_pullrequest_count + 10.0) * 40.0).to_i + # 活跃度 + @activity = (60.0 + @issues_count / (@issues_count + 10.0) * 40.0).to_i + @platform_activity = (60.0 + @platform_issues_count / (@platform_issues_count + 10.0) * 40.0).to_i + # 项目经验 + @experience = 10 * @project_count + 5 * @fork_count + @project_watchers_count + @project_praises_count + @experience = (60.0 + @experience / (@experience + 100.0) * 40.0).to_i + @platform_experience = 10 * @platform_project_count + 5 * @platform_fork_count + @platform_project_watchers_count + @platform_project_praises_count + @platform_experience = (60.0 + @platform_experience / (@platform_experience + 100.0) * 40.0).to_i + # 语言能力 + @language = (60.0 + @project_languages_count.length / (@project_languages_count.length + 5.0) * 40.0).to_i + @platform_language = (60.0 + @platform_project_languages_count.length / (@platform_project_languages_count.length + 5.0) * 40.0).to_i + # 语言百分比 + @languages_percent = Hash.new + for key in @project_languages_count.keys do + @languages_percent[key] = (@project_languages_count[key].to_f / @project_languages_count.values.sum).round(2) + end + @platform_languages_percent = Hash.new + for key in @platform_project_languages_count.keys do + @platform_languages_percent[key] = (@platform_project_languages_count[key].to_f / @platform_project_languages_count.values.sum).round(2) + end + # 各门语言分数 + @each_language_score = Hash.new + for key in @project_languages_count.keys do + @each_language_score[key] = (60.0 + @project_languages_count[key] / (@project_languages_count[key] + 5.0) * 40.0).to_i + end + @platform_each_language_score = Hash.new + for key in @platform_project_languages_count.keys do + @platform_each_language_score[key] = (60.0 + @platform_project_languages_count[key] / (@platform_project_languages_count[key] + 5.0) * 40.0).to_i + end + else + # 影响力 + @influence = (60.0 + @follow_count / (@follow_count + 20.0) * 40.0).to_i + @platform_influence = (60.0 + @platform_follow_count / (@platform_follow_count + 20.0) * 40.0).to_i + + # 贡献度 + @contribution = (60.0 + @pullrequest_count / (@pullrequest_count + 20.0) * 40.0).to_i + @platform_contribution = (60.0 + @platform_pullrequest_count / (@platform_pullrequest_count + 20.0) * 40.0).to_i + + # 活跃度 + @activity = (60.0 + @issues_count / (@issues_count + 80.0) * 40.0).to_i + @platform_activity = (60.0 + @platform_issues_count / (@platform_issues_count + 80.0) * 40.0).to_i + + # 项目经验 + @experience = 10 * @project_count + 5 * @fork_count + @project_watchers_count + @project_praises_count + @experience = (60.0 + @experience / (@experience + 100.0) * 40.0).to_i + @platform_experience = 10 * @platform_project_count + 5 * @platform_fork_count + @platform_project_watchers_count + @platform_project_praises_count + @platform_experience = (60.0 + @platform_experience / (@platform_experience + 100.0) * 40.0).to_i + # 语言能力 + @language = (60.0 + @project_languages_count.length / (@project_languages_count.length + 5.0) * 40.0).to_i + @platform_language = (60.0 + @platform_project_languages_count.length / (@platform_project_languages_count.length + 5.0) * 40.0).to_i + + # 语言百分比 + @languages_percent = Hash.new + for key in @project_languages_count.keys do + @languages_percent[key] = (@project_languages_count[key].to_f / @project_languages_count.values.sum).round(2) + end + # @platform_languages_percent = Hash.new + # for key in @platform_project_languages_count.keys do + # @platform_languages_percent[key] = (@platform_project_languages_count[key].to_f / @platform_project_languages_count.values.sum).round(2) + # end + # 各门语言分数 + @each_language_score = Hash.new + for key in @project_languages_count.keys do + @each_language_score[key] = (60.0 + @project_languages_count[key] / (@project_languages_count[key] + 5.0) * 40.0).to_i + end + # @platform_each_language_score = Hash.new + # for key in @platform_project_languages_count.keys do + # @platform_each_language_score[key] = (60.0 + @platform_project_languages_count[key] / (@platform_project_languages_count[key] + 5.0) * 40.0).to_i + # end + end + + end + + # 角色定位 + def role + full_member_projects = observed_user.full_member_projects + owner_projects = filter_member_projects_by_role("Owner") + manager_projects = filter_member_projects_by_role("Manager").where.not(id: owner_projects.ids) + developer_projects = filter_member_projects_by_role("Developer").where.not(id: owner_projects.ids + manager_projects.ids) + reporter_projects = filter_member_projects_by_role("Reporter").where.not(id: owner_projects.ids + manager_projects.ids + developer_projects.ids) + + @full_member_projects_count = full_member_projects.size + @owner_projects_count = owner_projects.size + @manager_projects_count = manager_projects.size + @developer_projects_count = developer_projects.size + @reporter_projects_count = reporter_projects.size + + end + + # 专业定位 + def major + # 参与项目 + join_normal_projects_sql = Project.members_projects(observed_user.id).to_sql + join_org_projects_sql = Project.joins(team_projects: [team: :team_users]).where(team_users: {user_id: observed_user.id}).to_sql + # 关注项目 + star_projects_sql = Project.joins(:watchers).where(watchers: {watchable_type: "Project", user_id: observed_user.id}).to_sql + # fork项目 + fork_projects_sql = Project.where(id: observed_user.fork_users.select(:id, :fork_project_id).pluck(:fork_project_id)).to_sql + major_projects = Project.from("( #{ join_normal_projects_sql} UNION #{ join_org_projects_sql } UNION #{ star_projects_sql } UNION #{fork_projects_sql}) AS projects").distinct + categories = ProjectCategory.joins(:projects).merge(Project.where(id: time_filter(major_projects, 'created_on'))).distinct.pluck(:name) + render :json => {categories: categories} + end + + private + def time_filter(collection, time_field) + if params[:start_time].present? && params[:end_time].present? + return collection.where("#{time_field} > ? AND #{time_field} < ?", Time.at(params[:start_time].to_i).beginning_of_day, Time.at(params[:end_time].to_i).end_of_day) + else + return collection + end + rescue + return collection + end + + def filter_member_projects_by_role(role) + case role + when 'Owner' + normal_projects_sql = Project.joins(members: :roles).where(user_id: observed_user.id).where(members: {user_id: observed_user.id}, roles: {name: 'Manager'}).to_sql + org_projects_sql = Project.joins(:owner, teams: :team_users).where(users: {type: 'Organization'}, teams: {authorize: "owner"}, team_users: {user_id: observed_user.id}).to_sql + when "Manager" + normal_projects_sql = Project.joins(members: :roles).where.not(user_id: observed_user.id).where(members: {user_id: observed_user.id}, roles: {name: 'Manager'}).to_sql + org_projects_sql = Project.joins(:owner, teams: :team_users).where(users: {type: 'Organization'}, teams: {authorize: "admin"}, team_users: {user_id: observed_user.id}).to_sql + when "Developer" + normal_projects_sql = Project.joins(members: :roles).where.not(user_id: observed_user.id).where(members: {user_id: observed_user.id}, roles: {name: 'Developer'}).to_sql + org_projects_sql = Project.joins(:owner, teams: :team_users).where(users: {type: 'Organization'}, teams: {authorize: "write"}, team_users: {user_id: observed_user.id}).to_sql + when "Reporter" + normal_projects_sql = Project.joins(members: :roles).where.not(user_id: observed_user.id).where(members: {user_id: observed_user.id}, roles: {name: 'Reporter'}).to_sql + org_projects_sql = Project.joins(:owner, teams: :team_users).where(users: {type: 'Organization'}, teams: {authorize: "read"}, team_users: {user_id: observed_user.id}).to_sql + end + return time_filter(Project.from("( #{normal_projects_sql} UNION #{org_projects_sql} ) AS projects").distinct, 'created_on') + end + + def preload_develop_data + if params[:start_time].present? && params[:end_time].present? + # 用户被follow数量 + @follow_count = time_filter(Watcher.where(watchable: observed_user), 'created_at').count + @platform_follow_count = time_filter(Watcher.where(watchable_type: 'User'), 'created_at').count + # 用户pr数量 + @pullrequest_count = time_filter(PullRequest.where(user_id: observed_user.id), 'created_at').count + @platform_pullrequest_count = time_filter(PullRequest, 'created_at').count + # 用户issue数量 + @issues_count = time_filter(Issue.where(author_id: observed_user.id), 'created_on').count + @platform_issues_count = time_filter(Issue, 'created_on').count + # 用户总项目数 + @project_count = time_filter(Project.where(user_id:observed_user.id), 'created_on').count + @platform_project_count = time_filter(Project, 'created_on').count + # 用户项目被fork数量 + @fork_count = time_filter(Project.where(user_id:observed_user.id), 'created_on').sum("forked_count") + @platform_fork_count = time_filter(Project, 'created_on').sum("forked_count") + # 用户项目关注数 + @project_watchers_count = time_filter(Project.where(user_id: observed_user.id), 'created_on').sum("watchers_count") + @platform_project_watchers_count = time_filter(Project, 'created_on').sum("watchers_count") + # 用户项目点赞数 + @project_praises_count = time_filter(Project.where(user_id: observed_user.id), 'created_on').sum("praises_count") + @platform_project_praises_count = time_filter(Project, 'created_on').sum("praises_count") + # 用户不同语言项目数量 + @project_languages_count = time_filter(Project.where(user_id: observed_user.id), 'created_on').joins(:project_language).group("project_languages.name").count + @platform_project_languages_count = time_filter(Project, 'created_on').joins(:project_language).group("project_languages.name").count + else + # 用户被follow数量 + @follow_count = Cache::UserFollowCountService.call(observed_user) + @platform_follow_count = Cache::PlatformFollowCountService.call + # 用户pr数量 + @pullrequest_count = Cache::UserPullrequestCountService.call(observed_user) + @platform_pullrequest_count = Cache::PlatformPullrequestCountService.call + # 用户issue数量 + @issues_count = Cache::UserIssueCountService.call(observed_user) + @platform_issues_count = Cache::PlatformIssueCountService.call + # 用户总项目数 + @project_count = Cache::UserProjectCountService.call(observed_user) + @platform_project_count = Cache::PlatformProjectCountService.call + # 用户项目被fork数量 + @fork_count = Cache::UserProjectForkCountService.call(observed_user) + @platform_fork_count = Cache::PlatformProjectForkCountService.call + # 用户项目关注数 + @project_watchers_count = Cache::UserProjectWatchersCountService.call(observed_user) + @platform_project_watchers_count = Cache::PlatformProjectWatchersCountService.call + # 用户项目点赞数 + @project_praises_count = Cache::UserProjectPraisesCountService.call(observed_user) + @platform_project_praises_count = Cache::PlatformProjectPraisesCountService.call + # 用户不同语言项目数量 + @project_languages_count = Cache::UserProjectLanguagesCountService.call(observed_user) + @platform_project_languages_count = Cache::PlatformProjectLanguagesCountService.call + end + end +end \ No newline at end of file diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index d163547e..6c6af73e 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -6,6 +6,7 @@ class UsersController < ApplicationController before_action :check_user_exist, only: [:show, :homepage_info,:projects, :watch_users, :fan_users, :hovercard] before_action :require_login, only: %i[me list change_password change_email] before_action :connect_to_ci_db, only: [:get_user_info] + before_action :convert_image!, only: [:update] skip_before_action :check_sign, only: [:attachment_show] def connect_to_ci_db(options={}) @@ -27,13 +28,15 @@ class UsersController < ApplicationController def show #待办事项,现在未做 - if User.current.login == @user.login + if User.current.admin? || User.current.login == @user.login @waiting_applied_messages = @user.applied_messages.waiting @common_applied_transfer_projects = AppliedTransferProject.where(owner_id: @user.id).common + AppliedTransferProject.where(owner_id: Organization.joins(team_users: :team).where(team_users: {user_id: @user.id}, teams: {authorize: %w(admin owner)} )).common - @undo_events = @waiting_applied_messages.size + @common_applied_transfer_projects.size + @common_applied_projects = AppliedProject.where(project_id: @user.full_admin_projects).common + @undo_events = @waiting_applied_messages.size + @common_applied_transfer_projects.size + @common_applied_projects.size else @waiting_applied_messages = AppliedMessage.none @common_applied_transfer_projects = AppliedTransferProject.none + @common_applied_projects = AppliedProject.none @undo_events = 0 end #用户的组织数量 @@ -62,7 +65,7 @@ class UsersController < ApplicationController def fan_users watchers = @user.watchers.includes(:user).order("watchers.created_at desc") - watchers = watchers.joins(:user).where("LOWER(concat(users.lastname, users.firstname, users.login)) LIKE ?", "%#{params[:search].split(" ").join('|')}%") if params[:search].present? + watchers = watchers.joins(:user).where("LOWER(CONCAT_WS(users.lastname, users.firstname, users.login, users.nickname)) LIKE ?", "%#{params[:search].split(" ").join('|')}%") if params[:search].present? @watchers_count = watchers.size @watchers = paginate(watchers) @@ -72,9 +75,13 @@ class UsersController < ApplicationController end def update - @user = User.find params[:id] - @user.update!(user_params) - render_ok + return render_not_found unless @user = User.find_by_id(params[:id]) || User.find_by(login: params[:id]) + return render_forbidden unless User.current.logged? && (current_user&.admin? || current_user.id == @user.id) + Util.write_file(@image, avatar_path(@user)) if user_params[:image].present? + @user.attributes = user_params.except(:image) + unless @user.save + render_error(@user.errors.full_messages.join(", ")) + end end def me @@ -311,11 +318,13 @@ class UsersController < ApplicationController end def user_params - params.require(:user).permit(:nickname, :lastname, :show_realname,:login,:mail, + params.require(:user).permit(:nickname, :image, user_extension_attributes: [ :gender, :location, :location_city, :occupation, :technical_title, - :school_id, :department_id,:identity, :student_id, :description] + :school_id, :department_id, :province, :city, + :custom_department, :identity, :student_id, :description, + :show_email, :show_location, :show_department] ) end diff --git a/app/controllers/users_for_private_messages_controller.rb b/app/controllers/users_for_private_messages_controller.rb index 610bf5d5..3a53a1af 100644 --- a/app/controllers/users_for_private_messages_controller.rb +++ b/app/controllers/users_for_private_messages_controller.rb @@ -11,7 +11,7 @@ class UsersForPrivateMessagesController < ApplicationController return end - users = users.where('LOWER(concat(lastname, firstname, nickname)) LIKE ?', "%#{keyword}%") + users = users.where('LOWER(CONCAT_WS(lastname, firstname, nickname)) LIKE ?', "%#{keyword}%") @users = users.limit(10).includes(:user_extension) end diff --git a/app/controllers/weapps/courses_controller.rb b/app/controllers/weapps/courses_controller.rb index ccd5d1bc..72782f5c 100644 --- a/app/controllers/weapps/courses_controller.rb +++ b/app/controllers/weapps/courses_controller.rb @@ -86,7 +86,7 @@ class Weapps::CoursesController < Weapps::BaseController end if search.present? - @teacher_list = @teacher_list.joins(:user).where("LOWER(CONCAT(users.lastname, users.firstname)) like ?", "%#{search}%") + @teacher_list = @teacher_list.joins(:user).where("LOWER(CONCAT_WS(users.lastname, users.firstname, users.nickname)) like ?", "%#{search}%") end @teacher_list_size = @teacher_list.size @@ -127,7 +127,7 @@ class Weapps::CoursesController < Weapps::BaseController @students = CourseMember.students(@course) if search.present? - @students = @students.joins(user: :user_extension).where("LOWER(CONCAT(users.lastname, users.firstname)) like ? or + @students = @students.joins(user: :user_extension).where("LOWER(CONCAT_WS(users.lastname, users.firstname, users.nickname)) like ? or user_extensions.student_id like ?", "%#{search}%", "%#{search}%") end diff --git a/app/controllers/zips_controller.rb b/app/controllers/zips_controller.rb index 3ed1eb8b..0c226211 100644 --- a/app/controllers/zips_controller.rb +++ b/app/controllers/zips_controller.rb @@ -86,7 +86,7 @@ class ZipsController < ApplicationController #搜索 if params[:search].present? - @ex_users = @ex_users.joins(user: :user_extension).where("CONCAT(lastname, firstname) like ? OR student_id like ?", "%#{params[:search]}%", "%#{params[:search]}%") + @ex_users = @ex_users.joins(user: :user_extension).where("CONCAT_WS(lastname, firstname, nickname) like ? OR student_id like ?", "%#{params[:search]}%", "%#{params[:search]}%") end default_ex_users_size = @ex_users&.size @@ -130,7 +130,7 @@ class ZipsController < ApplicationController end unless params[:search].blank? - @all_student_works = @all_student_works.joins(user: :user_extension).where("concat(lastname, firstname) like ? + @all_student_works = @all_student_works.joins(user: :user_extension).where("CONCAT_WS(lastname, firstname, nickname) like ? or student_id like ?", "%#{params[:search]}%", "%#{params[:search]}%") end diff --git a/app/docs/slate/source/includes/_projects.md b/app/docs/slate/source/includes/_projects.md index 87a37c45..2b6dd76d 100644 --- a/app/docs/slate/source/includes/_projects.md +++ b/app/docs/slate/source/includes/_projects.md @@ -1,5 +1,91 @@ # Projects +## 申请加入项目 +申请加入项目 + +> 示例: + +```shell +curl -X POST http://localhost:3000/api/applied_projects.json +``` + +```javascript +await octokit.request('POST /api/appliedr_projects.json') +``` + +### HTTP 请求 +`POST /api/applied_projects.json` + +### 请求参数 +参数 | 必选 | 默认 | 类型 | 字段说明 +--------- | ------- | ------- | -------- | ---------- +|applied_project.code |是| |string |邀请码 | +|applied_project.role |否| |string |项目权限,reporter: 报告者, developer: 开发者,manager:管理员 | + +> 请求的JSON示例 + +```json +{ + "applied_project": { + "code": "1una34", + "role": "developer" + } +} +``` + +### 返回字段说明 +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|id |int |申请id | +|status |string |申请状态,canceled:取消,common:正在申请, accept:已接受,refuse:已拒绝| +|time_ago |string |项目申请创建的时间 | +|project.id |int |申请项目的id | +|project.identifier |string |申请项目的标识 | +|project.name |string |申请项目的名称 | +|project.description |string |申请项目的描述 | +|project.is_public |bool |申请项目是否公开 | +|project.owner.id |bool |申请项目拥有者id | +|project.owner.type |string |申请项目拥有者类型 | +|project.owner.name |string |申请项目拥有者昵称 | +|project.owner.login |string |申请项目拥有者标识 | +|project.owner.image_url |string |申请项目拥有者头像 | +|user.id |int |申请创建者的id | +|user.type |string |申请创建者的类型 | +|user.name |string |申请创建者的名称 | +|user.login |string |申请创建者的标识 | +|user.image_url |string |申请创建者头像 | +> 返回的JSON示例: + +```json +{ + "project": { + "id": 74, + "identifier": "hehuisssjssjjsjs", + "name": "hehuisssjssjjsjs", + "description": "wwww", + "is_public": false, + "owner": { + "id": 10, + "type": "User", + "name": "testforge1", + "login": "testforge1", + "image_url": "system/lets/letter_avatars/2/T/19_237_174/120.png" + } + }, + "user": { + "id": 6, + "type": "User", + "name": "何慧", + "login": "yystopf", + "image_url": "images/avatars/User/6?t=1622513134" + }, + "id": 7, + "status": "common", + "created_at": "2021-06-09 16:41", + "time_ago": "1分钟前" +} +``` + ## 获取项目列表 获取项目列表,也可以更加相关条件过滤搜素 diff --git a/app/docs/slate/source/includes/_users.md b/app/docs/slate/source/includes/_users.md index 1d1afc02..bb4fd2b6 100644 --- a/app/docs/slate/source/includes/_users.md +++ b/app/docs/slate/source/includes/_users.md @@ -1,7 +1,7 @@ # Users @@ -47,6 +47,918 @@ await octokit.request('GET /api/users/me.json') Success Data. +## 更改用户信息 +更改用户信息 + +> 示例: + +```shell +curl -X PATCH/PUT http://localhost:3000/api/users/yystopf.json +``` + +```javascript +await octokit.request('PATCH/PUT /api/users/:login.json') +``` + +### HTTP 请求 +`PATCH/PUT /api/users/:login.json` + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|user.nickname |string |用户昵称 | +|user.image |base64/file |用户头像 | +|user.user_extension_attributes.gender |int |性别, 0男 1女 | +|user.user_extension_attributes.province |string |省份 | +|user.user_extension_attributes.city |string |城市 | +|user.user_extension_attributes.description |string |简介 | +|user.user_extension_attributes.custom_department|string |单位名称 | +|user.user_extension_attributes.technical_title |string |职业 | +|user.user_extension_attributes.show_email |bool |是否展示邮箱 | +|user.user_extension_attributes.show_location |bool |是否展示位置 | +|user.user_extension_attributes.show_department |bool |是否展示公司 | + +> 请求的JSON示例: + +```json +{ + "user": { + "nickname": "xxx", + "user_extension_attributes": { + "gender": 0, + "province": "湖南", + "city": "长沙", + "description": "个性签名", + "custom_department": "湖南智擎科技有限公司", + } + } +} +``` + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} +``` +## 获取用户星标项目 +获取用户星标项目 + +> 示例: + +```shell +curl -X GET http://localhost:3000/api/users/yystopf/is_pinned_projects.json +``` + +```javascript +await octokit.request('GET /api/users/:login/is_pinned_projects.json') +``` + +### HTTP 请求 +`GET api/users/:login/is_pinned_projects.json` + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|total_count |int |星标项目数量 | +|identifier |string |项目标识 | +|name |string |项目名称 | +|description |string |项目描述 | +|visits |int |项目访问数量| +|praises_count |int |项目点赞数量| +|watchers_count |int |项目关注数量| +|issues_count |int |项目issue数量| +|pull_requests_count |int |项目合并请求数量| +|forked_count |int |项目复刻数量| +|is_public |bool |项目是否公开| +|mirror_url |string |镜像地址| +|type |int |项目类型 0 普通项目 1 普通镜像项目 2 同步镜像项目| +|time_ago |string |上次更新时间| +|open_devops |int |是否开启devops| +|forked_from_project_id |int |fork项目id| +|platform |string |项目平台| +|author.name |string |项目拥有者名称| +|author.type |string |项目拥有者类型| +|author.login |string |项目拥有者用户名| +|author.image_url |string |项目拥有者头像| +|category.name |string |项目分类名称| +|language.name |string |项目语言名称| +|position |int |项目排序| + + +> 返回的JSON示例: + +```json +{ + "total_count": 1, + "projects": [ + { + "id": 89, + "repo_id": 89, + "identifier": "monkey", + "name": "boke", + "description": "dkkd", + "visits": 4, + "praises_count": 0, + "watchers_count": 0, + "issues_count": 0, + "pull_requests_count": 0, + "forked_count": 0, + "is_public": true, + "mirror_url": "https://github.com/viletyy/monkey.git", + "type": 1, + "last_update_time": 1619685144, + "time_ago": "27天前", + "forked_from_project_id": null, + "open_devops": false, + "platform": "forge", + "author": { + "name": "测试组织", + "type": "Organization", + "login": "ceshi_org", + "image_url": "images/avatars/Organization/9?t=1612706073" + }, + "category": { + "id": 3, + "name": "深度学习" + }, + "language": { + "id": 2, + "name": "C" + } + } + ] +} +``` + + +## 用户添加星标项目 +用户添加星标项目 + +> 示例: + +```shell +curl -X POST http://localhost:3000/api/users/yystopf/is_pinned_projects/pin.json +``` + +```javascript +await octokit.request('GET /api/users/:login/is_pinned_projects/pin.json') +``` + +### HTTP 请求 +`POST /api/users/:login/is_pinned_projects/pin.json` + +### 请求字段说明: +#### 同时设定多个星标项目 +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|is_pinned_project_ids |array |设定为星标项目的id | + +#### 只设定一个星标项目 +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|is_pinned_project_id |integer |设定为星标项目的id | + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} +``` + + +## 星标项目展示排序 +星标项目展示排序 + +> 示例: + +```shell +curl -X PATCH http://localhost:3000/api/users/yystopf/is_pinned_projects/11.json +``` + +```javascript +await octokit.request('PATCH/PUT /api/users/:login/is_pinned_projects/:id.json') +``` + +### HTTP 请求 +`PATCH/PUT /api/users/:login/is_pinned_projects/:id.json` + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|pinned_projects.position |int |排序,数字越大排名越前 | + +> 请求的JSON示例: + +```json +{ + "pinned_project": { + "position": 1 + } +} +``` + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} +``` +## 用户近期活动统计 +用户近期活动统计, 默认显示近一周的数据 + +> 示例: + +```shell +curl -X GET http://localhost:3000/api/users/yystopf/statistics/activity.json +``` + +```javascript +await octokit.request('GET /api/users/:login/statistics/activity.json') +``` + +### HTTP 请求 +`GET /api/users/:login/statistics/activity.json` + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|dates |array |时间 | +|issues_count |array |易修数量| +|pull_requests_count |array |合并请求数量| +|commtis_count |array |贡献数量| + + +> 返回的JSON示例: + +```json +{ + "dates": [ + "2021.05.21", + "2021.05.22", + "2021.05.23", + "2021.05.24", + "2021.05.25", + "2021.05.26", + "2021.05.27", + "2021.05.28" + ], + "issues_count": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "pull_requests_count": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "commits_count": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] +} +``` + + + +## 获取用户贡献度 +获取用户贡献度 + +> 示例: + +```shell +curl -X GET http://localhost:3000/api/users/yystopf/headmaps.json +``` + +```javascript +await octokit.request('GET /api/users/:login/headmaps.json') +``` + +### HTTP 请求 +`GET api/users/:login/headmaps.json` + + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|year |string |年份 | + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|total_contributions |int |所选时间内的总贡献度 | +|headmaps.date |string|时间| +|headmaps.contributions |int|贡献度| + + +> 返回的JSON示例: + +```json +{ + "total_contributions": 139, + "headmaps": [ + { + "date": "2021-02-07", + "contributions": 1 + }, + { + "date": "2021-02-21", + "contributions": 13 + }, + { + "date": "2021-02-25", + "contributions": 5 + }, + { + "date": "2021-03-01", + "contributions": 2 + }, + { + "date": "2021-03-04", + "contributions": 1 + }, + { + "date": "2021-03-15", + "contributions": 9 + }, + { + "date": "2021-03-22", + "contributions": 14 + }, + { + "date": "2021-03-24", + "contributions": 1 + }, + { + "date": "2021-03-30", + "contributions": 11 + }, + { + "date": "2021-04-06", + "contributions": 1 + }, + { + "date": "2021-04-12", + "contributions": 1 + }, + { + "date": "2021-04-13", + "contributions": 2 + }, + { + "date": "2021-04-19", + "contributions": 3 + }, + { + "date": "2021-04-23", + "contributions": 37 + }, + { + "date": "2021-04-25", + "contributions": 2 + }, + { + "date": "2021-04-26", + "contributions": 6 + }, + { + "date": "2021-04-28", + "contributions": 1 + }, + { + "date": "2021-04-29", + "contributions": 18 + }, + { + "date": "2021-04-30", + "contributions": 9 + }, + { + "date": "2021-05-04", + "contributions": 1 + }, + { + "date": "2021-05-06", + "contributions": 1 + } + ] +} +``` + + +## 获取用户动态 +获取用户动态 + +> 示例: + +```shell +curl -X GET http://localhost:3000/api/users/yystopf/project_trends.json +``` + +```javascript +await octokit.request('GET /api/users/:login/project_trends.json') +``` + +### HTTP 请求 +`GET api/users/:login/project_trends.json` + + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|date |string |日期,格式: 2021-05-28 | + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|total_count |int |所选时间内的总动态数 | +|project_trends.trend_type |string|动态类型,Issue:易修,VersionRelease:版本发布,PullRequest:合并请求| +|project_trends.action_type |string|操作类型| +|project_trends.trend_id |integer|动态id| +|project_trends.user_name |string|用户名称| +|project_trends.user_login |string|用户用户名| +|project_trends.user_avatar |string|用户头像| +|project_trends.action_time |string|操作时间| +|project_trends.name |string|动态标题| + +> 返回的JSON示例: + +```json +{ + "total_count": 16, + "project_trends": [ + { + "id": 27, + "trend_type": "Issue", + "action_type": "创建了工单", + "trend_id": 18, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "21天前", + "name": "31213123123", + "issue_type": "1", + "status_id": 2, + "priority_id": 4, + "created_at": "2021-05-07 15:39", + "updated_at": "2021-05-27 15:42", + "assign_user_name": "yystopf", + "assign_user_login": "yystopf", + "issue_journal_size": 1, + "issue_journals": [] + }, + { + "id": 8, + "trend_type": "VersionRelease", + "action_type": "创建了版本发布", + "trend_id": 8, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "24天前", + "name": "heihei1", + "tag_name": "v1.0", + "target_commitish": "master", + "tarball_url": "http://localhost:10080/forgeceshiorg1/ceshi1/archive/v1.0.tar.gz", + "zipball_url": "http://localhost:10080/forgeceshiorg1/ceshi1/archive/v1.0.zip", + "url": "http://localhost:10080/api/v1/repos/forgeceshiorg1/ceshi1/releases/84", + "version_gid": "84", + "created_at": "2021-05-04 12:04" + }, + { + "id": 25, + "trend_type": "PullRequest", + "action_type": "关闭了合并请求", + "trend_id": 14, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "28天前", + "name": "13", + "created_at": "2021-04-30 15:39" + }, + { + "id": 24, + "trend_type": "PullRequest", + "action_type": "创建了合并请求", + "trend_id": 13, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "28天前", + "name": "211212", + "created_at": "2021-04-30 15:37" + }, + { + "id": 23, + "trend_type": "PullRequest", + "action_type": "创建了合并请求", + "trend_id": 12, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "28天前", + "name": "奇偶哦iu", + "created_at": "2021-04-30 10:19" + }, + { + "id": 22, + "trend_type": "PullRequest", + "action_type": "创建了合并请求", + "trend_id": 11, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "28天前", + "name": "2112123", + "created_at": "2021-04-29 18:46" + }, + { + "id": 21, + "trend_type": "PullRequest", + "action_type": "关闭了合并请求", + "trend_id": 10, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "28天前", + "name": "23123", + "created_at": "2021-04-29 18:45" + }, + { + "id": 20, + "trend_type": "PullRequest", + "action_type": "创建了合并请求", + "trend_id": 9, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "28天前", + "name": "33", + "created_at": "2021-04-29 18:37" + }, + { + "id": 19, + "trend_type": "PullRequest", + "action_type": "关闭了合并请求", + "trend_id": 8, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "28天前", + "name": "gggg", + "created_at": "2021-04-29 17:51" + }, + { + "id": 16, + "trend_type": "Issue", + "action_type": "创建了工单", + "trend_id": 8, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "1个月前", + "name": "hjhkj", + "issue_type": "1", + "status_id": 1, + "priority_id": 2, + "created_at": "2021-04-19 10:52", + "updated_at": "2021-04-19 10:52", + "assign_user_name": null, + "assign_user_login": null, + "issue_journal_size": 0, + "issue_journals": [] + }, + { + "id": 7, + "trend_type": "VersionRelease", + "action_type": "创建了版本发布", + "trend_id": 7, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "1个月前", + "name": "v3.0.1", + "tag_name": "v3.0.1", + "target_commitish": "master", + "tarball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v3.0.1.tar.gz", + "zipball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v3.0.1.zip", + "url": "http://localhost:10080/api/v1/repos/yystopf/ceshirepo1/releases/78", + "version_gid": "78", + "created_at": "2021-03-30 15:51" + }, + { + "id": 6, + "trend_type": "VersionRelease", + "action_type": "创建了版本发布", + "trend_id": 6, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "1个月前", + "name": "v3.0.0", + "tag_name": "v3.0.0", + "target_commitish": "master", + "tarball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v3.0.0.tar.gz", + "zipball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v3.0.0.zip", + "url": "http://localhost:10080/api/v1/repos/yystopf/ceshirepo1/releases/77", + "version_gid": "77", + "created_at": "2021-03-30 15:33" + }, + { + "id": 5, + "trend_type": "VersionRelease", + "action_type": "创建了版本发布", + "trend_id": 5, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "1个月前", + "name": "v1.0.0", + "tag_name": "v1.0.0", + "target_commitish": "master", + "tarball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v1.0.0.tar.gz", + "zipball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v1.0.0.zip", + "url": "http://localhost:10080/api/v1/repos/yystopf/ceshirepo1/releases/76", + "version_gid": "76", + "created_at": "2021-03-30 15:27" + }, + { + "id": 2, + "trend_type": "VersionRelease", + "action_type": "创建了版本发布", + "trend_id": 2, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "2个月前", + "name": "vvvv", + "tag_name": "v1.1", + "target_commitish": "dev", + "tarball_url": "http://localhost:10080/yystopf/virus_blog/archive/v1.1.tar.gz", + "zipball_url": "http://localhost:10080/yystopf/virus_blog/archive/v1.1.zip", + "url": "http://localhost:10080/api/v1/repos/yystopf/virus_blog/releases/6", + "version_gid": "6", + "created_at": "2021-03-15 14:18" + }, + { + "id": 2, + "trend_type": "PullRequest", + "action_type": "创建了合并请求", + "trend_id": 2, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "3个月前", + "name": "444", + "created_at": "2021-02-25 17:31" + } + ] +} +``` + + +## 用户开发能力 +用户开发能力, 默认为所有时间下的开发能力 + +> 示例: + +```shell +curl -X GET http://localhost:3000/api/users/yystopf/statistics/develop.json +``` + +```javascript +await octokit.request('GET /api/users/:login/statistics/develop.json') +``` + +### HTTP 请求 +`GET /api/users/:login/statistics/develop.json` + + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|start_time |integer |时间戳,开始时间,格式:1621526400| +|end_time |integer |时间戳,结束时间,格式:1622131200| + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|influence |int |影响力 | +|contribution |int |贡献度| +|activity |int |活跃度| +|experience |int |项目经验| +|language |int |语言能力| +|languages_percent |float |语言百分比| +|each_language_score |int |各门语言分数| + + +> 返回的JSON示例: + +```json +{ + "platform": { + "influence": 61, + "contribution": 75, + "activity": 66, + "experience": 95, + "language": 87, + "languages_percent": { + "CSS": 0.03, + "C#": 0.13, + "Ruby": 0.04, + "Go": 0.05, + "C": 0.19, + "Java": 0.34, + "Python": 0.09, + "C+": 0.01, + "C++": 0.11, + "Scala": 0.01, + "HTML": 0.01 + }, + "each_language_score": { + "CSS": 71, + "C#": 86, + "Ruby": 75, + "Go": 77, + "C": 90, + "Java": 93, + "Python": 83, + "C+": 66, + "C++": 85, + "Scala": 66, + "HTML": 66 + } + }, + "user": { + "influence": 60, + "contribution": 72, + "activity": 65, + "experience": 88, + "language": 84, + "languages_percent": { + "C": 0.25, + "C#": 0.33, + "C++": 0.13, + "CSS": 0.08, + "Go": 0.04, + "HTML": 0.04, + "Java": 0.04, + "Ruby": 0.08 + }, + "each_language_score": { + "C": 81, + "C#": 84, + "C++": 75, + "CSS": 71, + "Go": 66, + "HTML": 66, + "Java": 66, + "Ruby": 71 + } + } +} +``` + + +## 用户角色定位 +用户角色定位,默认显示所有时间下的角色定位数据 + +> 示例: + +```shell +curl -X GET http://localhost:3000/api/users/yystopf/statistics/role.json +``` + +```javascript +await octokit.request('GET /api/users/:login/statistics/role.json') +``` + +### HTTP 请求 +`GET /api/users/:login/statistics/role.json` + + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|start_time |integer |时间戳,开始时间,格式:1621526400| +|end_time |integer |时间戳,结束时间,格式:1622131200| + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|total_projects_count |int |用户所有的项目数量 | +|role.object.count |int |用户该语言下的项目数量| +|role.object.percent |float |用户该语言下的项目占比| + +> 返回的JSON示例: + +```json +{ + "total_projects_count": 27, + "role": { + "owner": { + "count": 24, + "percent": 0.89 + }, + "manager": { + "count": 1, + "percent": 0.04 + }, + "developer": { + "count": 2, + "percent": 0.07 + }, + "reporter": { + "count": 0, + "percent": 0.0 + } + } +} +``` + + +## 用户专业定位 +用户专业定位,默认显示所有时间下的专业定位数据 + +> 示例: + +```shell +curl -X GET http://localhost:3000/api/users/yystopf/statistics/major.json +``` + +```javascript +await octokit.request('GET /api/users/:login/statistics/major.json') +``` + +### HTTP 请求 +`GET /api/users/:login/statistics/major.json` + + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|start_time |integer |时间戳,开始时间,格式:1621526400| +|end_time |integer |时间戳,结束时间,格式:1622131200| + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|categories |int |用户项目分类 | + +> 返回的JSON示例: + +```json +{ + "categories": [ + "大数据", + "机器学习", + "深度学习", + "人工智能", + "智慧医疗", + "云计算" + ] +} +``` + + ## 待办事项-用户通知信息 待办事项-用户通知信息 @@ -90,11 +1002,11 @@ await octokit.request('GET /api/users/:login/applied_messages.json') |applied.user.name |string |通知主体的迁移创建者的名称 | |applied.user.login |string |通知主体的迁移创建者的标识 | |applied.user.image_url |string |通知主体的迁移创建者头像 | -|applied.owner.id |int |通知主体的迁移接受者的id | -|applied.owner.type |string |通知主体的迁移接受者的类型 | -|applied.owner.name |string |通知主体的迁移接受者的名称 | -|applied.owner.login |string |通知主体的迁移接受者的标识 | -|applied.owner.image_url |string |通知主体的迁移接受者头像 | +|applied_user.id |int |通知发起者的id | +|applied_user.type |string |通知发起者的类型 | +|applied_user.name |string |通知发起者的名称 | +|applied_user.login |string |通知发起者的标识 | +|applied_user.image_url |string |通知发起者头像 | |applied_type |string |通知类型 | |name |string | 通知内容 | |viewed |string|是否已读,waiting:未读,viewed:已读| @@ -108,6 +1020,48 @@ await octokit.request('GET /api/users/:login/applied_messages.json') { "total_count": 5, "applied_messages": [ + { + "applied": { + "project": { + "id": 74, + "identifier": "hehuisssjssjjsjs", + "name": "hehuisssjssjjsjs", + "description": "wwww", + "is_public": false, + "owner": { + "id": 10, + "type": "User", + "name": "testforge1", + "login": "testforge1", + "image_url": "system/lets/letter_avatars/2/T/19_237_174/120.png" + } + }, + "user": { + "id": 6, + "type": "User", + "name": "何慧", + "login": "yystopf", + "image_url": "images/avatars/User/6?t=1622513134" + }, + "id": 6, + "status": "accepted", + "created_at": "2021-06-09 16:34", + "time_ago": "1分钟前" + }, + "applied_user": { + "id": 6, + "type": "User", + "name": "何慧", + "login": "yystopf", + "image_url": "images/avatars/User/6?t=1622513134" + }, + "applied_type": "AppliedProject", + "name": "已通过你加入【hehuisssjssjjsjs】仓库的申请。", + "viewed": "waiting", + "status": "successed", + "created_at": "2021-06-09 16:34", + "time_ago": "1分钟前" + }, { "applied": { "project": { @@ -432,4 +1386,240 @@ await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/refus "created_at": "2021-04-25 18:06", "time_ago": "16小时前" } +``` + + +## 待办事项-项目申请 +待办事项-项目申请 + +> 示例: + +```shell +curl -X GET http://localhost:3000/api/users/yystopf/applied_projects.json +``` + +```javascript +await octokit.request('GET /api/users/:login/applied_projects.json') +``` + +### HTTP 请求 +`GET /api/users/:login/applied_projects.json` + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|login |string |用户标识 | + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|id |int |申请id | +|status |string |申请状态,canceled:取消,common:正在申请, accept:已接受,refuse:已拒绝| +|time_ago |string |申请创建的时间 | +|project.id |int |申请项目的id | +|project.identifier |string |申请项目的标识 | +|project.name |string |申请项目的名称 | +|project.description |string |申请项目的描述 | +|project.is_public |bool |申请项目是否公开 | +|project.owner.id |bool |申请项目拥有者id | +|project.owner.type |string |申请项目拥有者类型 | +|project.owner.name |string |申请项目拥有者昵称 | +|project.owner.login |string |申请项目拥有者标识 | +|project.owner.image_url |string |申请项目拥有者头像 | +|user.id |int |申请创建者的id | +|user.type |string |申请创建者的类型 | +|user.name |string |申请创建者的名称 | +|user.login |string |申请创建者的标识 | +|user.image_url |string |申请创建者头像 | + + +> 返回的JSON示例: + +```json +{ + "total_count": 4, + "applied_transfer_projects": [ + { + "project": { + "id": 74, + "identifier": "hehuisssjssjjsjs", + "name": "hehuisssjssjjsjs", + "description": "wwww", + "is_public": false, + "owner": { + "id": 10, + "type": "User", + "name": "testforge1", + "login": "testforge1", + "image_url": "system/lets/letter_avatars/2/T/19_237_174/120.png" + } + }, + "user": { + "id": 6, + "type": "User", + "name": "何慧", + "login": "yystopf", + "image_url": "images/avatars/User/6?t=1622513134" + }, + "id": 7, + "status": "common", + "created_at": "2021-06-09 16:41", + "time_ago": "7分钟前" + }, + ... + ] +} +``` + +## 用户接受申请 +用户接受申请 + +> 示例: + +```shell +curl -X POST http://localhost:3000/api/users/yystopf/applied_projects/2/accept.json +``` + +```javascript +await octokit.request('GET /api/users/:login/applied_projects/:id/accept.json') +``` + +### HTTP 请求 +`GET /api/users/:login/applied_projects/:id/accept.json` + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|login |string |用户标识 | +|id |int |申请id | + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|id |int |申请id | +|status |string |申请状态,canceled:取消,common:正在申请, accept:已接受,refuse:已拒绝| +|time_ago |string |申请创建的时间 | +|project.id |int |申请项目的id | +|project.identifier |string |申请项目的标识 | +|project.name |string |申请项目的名称 | +|project.description |string |申请项目的描述 | +|project.is_public |bool |申请项目是否公开 | +|project.owner.id |bool |申请项目拥有者id | +|project.owner.type |string |申请项目拥有者类型 | +|project.owner.name |string |申请项目拥有者昵称 | +|project.owner.login |string |申请项目拥有者标识 | +|project.owner.image_url |string |申请项目拥有者头像 | +|user.id |int |申请创建者的id | +|user.type |string |申请创建者的类型 | +|user.name |string |申请创建者的名称 | +|user.login |string |申请创建者的标识 | +|user.image_url |string |申请创建者头像 | + + +> 返回的JSON示例: + +```json +{ + "project": { + "id": 74, + "identifier": "hehuisssjssjjsjs", + "name": "hehuisssjssjjsjs", + "description": "wwww", + "is_public": false, + "owner": { + "id": 10, + "type": "User", + "name": "testforge1", + "login": "testforge1", + "image_url": "system/lets/letter_avatars/2/T/19_237_174/120.png" + } + }, + "user": { + "id": 6, + "type": "User", + "name": "何慧", + "login": "yystopf", + "image_url": "images/avatars/User/6?t=1622513134" + }, + "id": 7, + "status": "accept", + "created_at": "2021-06-09 16:41", + "time_ago": "7分钟前" +} +``` + +## 用户拒绝申请 +用户拒绝申请 + +> 示例: + +```shell +curl -X POST http://localhost:3000/api/users/yystopf/applied_projects/2/refuse.json +``` + +```javascript +await octokit.request('GET /api/users/:login/applied_projects/:id/refuse.json') +``` + +### HTTP 请求 +`GET /api/users/:login/applied_projects/:id/refuse.json` + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|login |string |用户标识 | +|id |int |申请id | + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|id |int |申请id | +|status |string |申请状态,canceled:取消,common:正在申请, accept:已接受,refuse:已拒绝| +|time_ago |string |申请创建的时间 | +|project.id |int |申请项目的id | +|project.identifier |string |申请项目的标识 | +|project.name |string |申请项目的名称 | +|project.description |string |申请项目的描述 | +|project.is_public |bool |申请项目是否公开 | +|project.owner.id |bool |申请项目拥有者id | +|project.owner.type |string |申请项目拥有者类型 | +|project.owner.name |string |申请项目拥有者昵称 | +|project.owner.login |string |申请项目拥有者标识 | +|project.owner.image_url |string |申请项目拥有者头像 | +|user.id |int |申请创建者的id | +|user.type |string |申请创建者的类型 | +|user.name |string |申请创建者的名称 | +|user.login |string |申请创建者的标识 | +|user.image_url |string |申请创建者头像 | + +> 返回的JSON示例: + +```json +{ + "project": { + "id": 74, + "identifier": "hehuisssjssjjsjs", + "name": "hehuisssjssjjsjs", + "description": "wwww", + "is_public": false, + "owner": { + "id": 10, + "type": "User", + "name": "testforge1", + "login": "testforge1", + "image_url": "system/lets/letter_avatars/2/T/19_237_174/120.png" + } + }, + "user": { + "id": 6, + "type": "User", + "name": "何慧", + "login": "yystopf", + "image_url": "images/avatars/User/6?t=1622513134" + }, + "id": 7, + "status": "accept", + "created_at": "2021-06-09 16:41", + "time_ago": "7分钟前" +} ``` \ No newline at end of file diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index ccc45df0..a1aea4ae 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -438,4 +438,14 @@ module ApplicationHelper return nil if str.blank? Base64.decode64 str end + + def render_admin_statistics_item + url = Rails.application.config_for(:configuration)["admin_statistics_url"] + + return if url.blank? + content_tag(:li) do + sidebar_item(url, "数据统计", icon: 'bar-chart', controller: 'root') + end + end + end diff --git a/app/helpers/tag_chosen_helper.rb b/app/helpers/tag_chosen_helper.rb index 1e7879d1..5193c9ab 100644 --- a/app/helpers/tag_chosen_helper.rb +++ b/app/helpers/tag_chosen_helper.rb @@ -94,7 +94,7 @@ module TagChosenHelper def render_issue_tags(project) # project.issue_tags.last&.cache_key - cache_key = "all_issue_tags/#{project.issue_tags.maximum('updated_at')}" + cache_key = "project-#{project.id}/all_issue_tags/size-#{project.issue_tags.size}/#{project.issue_tags.maximum('updated_at')}" Rails.cache.fetch(cache_key) do project.issue_tags.select(:id, :name, :color).collect do |event| @@ -109,7 +109,7 @@ module TagChosenHelper end def render_cache_milestones(project) - cache_key = "all_milestones/#{project.versions.maximum('updated_on')}" + cache_key = "project-#{project.id}/all_milestones/size-#{project.versions.size}/#{project.versions.maximum('updated_on')}" Rails.cache.fetch(cache_key) do project.versions.select(:id, :name, :status).collect do |event| @@ -124,7 +124,7 @@ module TagChosenHelper end def render_cache_collaborators(project) - cache_key = "all_collaborators/#{project.all_collaborators.maximum('created_on')}" + cache_key = "project-#{project.id}/all_collaborators/size-#{project.all_collaborators.size}/#{project.all_collaborators.maximum('updated_on')}" Rails.cache.fetch(cache_key) do project.all_collaborators.order(created_on: :desc).collect do |user| { diff --git a/app/interactors/projects/add_member_interactor.rb b/app/interactors/projects/add_member_interactor.rb index a3fe9e33..0c3785c6 100644 --- a/app/interactors/projects/add_member_interactor.rb +++ b/app/interactors/projects/add_member_interactor.rb @@ -23,7 +23,7 @@ module Projects ActiveRecord::Base.transaction do gitea_result = Gitea::Repository::Members::AddService.new(owner, project.identifier, collaborator.login, permission).call if gitea_result.status == 204 - project.add_member!(collaborator.id) + project.add_member!(collaborator.id, role_name) end fail!(nil) end @@ -38,5 +38,20 @@ module Projects @error = error end + def role_name + case permission + when 'read' + 'Reporter' + when 'write' + 'Developer' + when 'admin' + 'Manager' + when 'owner' + 'Manager' + else + 'Reporter' + end + end + end end diff --git a/app/jobs/reset_platform_cache_job.rb b/app/jobs/reset_platform_cache_job.rb new file mode 100644 index 00000000..bdc5b6aa --- /dev/null +++ b/app/jobs/reset_platform_cache_job.rb @@ -0,0 +1,14 @@ +class ResetPlatformCacheJob < ApplicationJob + queue_as :cache + + def perform + Cache::PlatformFollowCountService.new.reset + Cache::PlatformIssueCountService.new.reset + Cache::PlatformProjectCountService.new.reset + Cache::PlatformProjectForkCountService.new.reset + Cache::PlatformProjectLanguagesCountService.new.reset + Cache::PlatformProjectPraisesCountService.new.reset + Cache::PlatformProjectWatchersCountService.new.reset + Cache::PlatformPullrequestCountService.new.reset + end +end \ No newline at end of file diff --git a/app/jobs/reset_user_cache_job.rb b/app/jobs/reset_user_cache_job.rb new file mode 100644 index 00000000..3562475c --- /dev/null +++ b/app/jobs/reset_user_cache_job.rb @@ -0,0 +1,14 @@ +class ResetUserCacheJob < ApplicationJob + queue_as :cache + + def perform(user) + Cache::UserFollowCountService.new(user).reset + Cache::UserIssueCountService.new(user).reset + Cache::UserProjectCountService.new(user).reset + Cache::UserProjectForkCountService.new(user).reset + Cache::UserProjectLanguagesCountService.new(user).reset + Cache::UserProjectPraisesCountService.new(user).reset + Cache::UserProjectWatchersCountService.new(user).reset + Cache::UserPullrequestCountService.new(user).reset + end +end \ No newline at end of file diff --git a/app/jobs/send_join_project_applied_message_job.rb b/app/jobs/send_join_project_applied_message_job.rb new file mode 100644 index 00000000..557878ed --- /dev/null +++ b/app/jobs/send_join_project_applied_message_job.rb @@ -0,0 +1,27 @@ +class SendJoinProjectAppliedMessageJob < ApplicationJob + queue_as :default + + def perform(applied_project, applied_user, message_status) + project = applied_project.project + return unless project.present? + return unless applied_user.present? + return unless applied_project.user.present? + AppliedMessage.find_or_create_by!(user_id: applied_project.user_id, + applied: applied_project, + status: message_status, + name: build_name(project.name, message_status), + applied_user_id: applied_user.id, + project_id: project.id) + end + + private + def build_name(repo_name, message_status, applied_name="") + case message_status + when 'successed' + return "已通过你加入【#{repo_name}】仓库的申请。" + when 'failure' + return "已拒绝你加入【#{repo_name}】仓库的申请。" + end + "" + end +end \ No newline at end of file diff --git a/app/jobs/sync_mirrored_repository_job.rb b/app/jobs/sync_mirrored_repository_job.rb index f0617146..a1408153 100644 --- a/app/jobs/sync_mirrored_repository_job.rb +++ b/app/jobs/sync_mirrored_repository_job.rb @@ -5,7 +5,27 @@ class SyncMirroredRepositoryJob < ApplicationJob repo = Repository.find_by(id: repo_id) current_user = User.find_by(id: user_id) return if repo.blank? || current_user.blank? - result = Gitea::Repository::SyncMirroredService.new(repo.owner.login, repo.identifier, token: current_user.gitea_token).call + + # TODO + # 先同步镜像库 + if repo.config_accelerator? + puts "[gitea-accelerator]: ###### 镜像库开始同步 ######" + result = Gitea::Accelerator::SyncMirroredService.call(repo.identifier) + puts "[gitea-accelerator]: ###### 镜像库同步状态为 #{result[:status]}" + + # TODO 暂时解决从镜像库镜像动作时间先执行的问题 + # 避免了Gitea::Repository::SyncMirroredService先执行后,加速器Gitea::Accelerator::SyncMirroredService + # 再执行的导致Gitea::Repository::SyncMirroredService执行镜像不是最新代码的问题 + sleep 3.seconds + end + + sync_common!(repo, current_user) + end + + def sync_common!(repo, user) + result = Gitea::Repository::SyncMirroredService.call(repo.owner.login, + repo.identifier, token: user.gitea_token) repo&.mirror.set_status! if result[:status] === 200 end + end diff --git a/app/models/application_record.rb b/app/models/application_record.rb index 888c6542..3ab2b11e 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -16,4 +16,12 @@ class ApplicationRecord < ActiveRecord::Base def allow_sync_to_trustie? Rails.env.production? && EduSetting.get('host_name') == 'https://www.educoder.net' end + + def reset_user_cache_async_job(user) + ResetUserCacheJob.perform_later(user) + end + + def reset_platform_cache_async_job + ResetPlatformCacheJob.perform_later + end end diff --git a/app/models/applied_project.rb b/app/models/applied_project.rb index 68095d0e..d1fea2f7 100644 --- a/app/models/applied_project.rb +++ b/app/models/applied_project.rb @@ -7,6 +7,8 @@ # user_id :integer not null # role :integer default("0") # status :integer default("0") +# created_at :datetime +# updated_at :datetime # class AppliedProject < ApplicationRecord @@ -14,7 +16,9 @@ class AppliedProject < ApplicationRecord belongs_to :project has_many :applied_messages, as: :applied, dependent: :destroy - has_many :forge_activities, as: :forge_act, dependent: :destroy + # has_many :forge_activities, as: :forge_act, dependent: :destroy + + enum role: {manager: 3, developer: 4, reporter: 5} + enum status: {canceled: -1, common: 0, accepted: 1, refused: 2} # -1 已取消 0 待操作 1 已接收 2 已拒绝 - scope :pending, -> { where(status: 0) } end diff --git a/app/models/attachment.rb b/app/models/attachment.rb index 1ca17345..721cf84b 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -17,7 +17,7 @@ # disk_directory :string(255) # attachtype :integer default("1") # is_public :integer default("1") -# copy_from :string(255) +# copy_from :integer # quotes :integer default("0") # is_publish :integer default("1") # publish_time :datetime @@ -26,17 +26,18 @@ # cloud_url :string(255) default("") # course_second_category_id :integer default("0") # delay_publish :boolean default("0") -# link :string(255) -# clone_id :integer # # Indexes # # index_attachments_on_author_id (author_id) -# index_attachments_on_clone_id (clone_id) # index_attachments_on_container_id_and_container_type (container_id,container_type) +# index_attachments_on_course_second_category_id (course_second_category_id) # index_attachments_on_created_on (created_on) +# index_attachments_on_is_public (is_public) +# index_attachments_on_quotes (quotes) # + class Attachment < ApplicationRecord include BaseModel include Publicable @@ -51,7 +52,7 @@ class Attachment < ApplicationRecord # 二级目录 # belongs_to :course_second_category, optional: true - scope :by_filename_or_user_name, -> (keywords) { joins(:author).where("filename like :search or LOWER(concat(users.lastname, users.firstname)) LIKE :search", + scope :by_filename_or_user_name, -> (keywords) { joins(:author).where("filename like :search or LOWER(CONCAT_WS(users.lastname, users.firstname, users.nickname)) LIKE :search", :search => "%#{keywords.split(" ").join('|')}%") unless keywords.blank? } scope :by_keywords, -> (keywords) { where("filename LIKE ?", "%#{keywords.split(" ").join('|')}%") unless keywords.blank? } scope :ordered, -> (opts = {}) { order("#{opts[:sort_type]} #{opts[:sort] == 1 ? 'asc': 'desc'}") } diff --git a/app/models/ci/user.rb b/app/models/ci/user.rb index e4a4d062..c263a172 100644 --- a/app/models/ci/user.rb +++ b/app/models/ci/user.rb @@ -39,15 +39,17 @@ # business :boolean default("0") # profile_completed :boolean default("0") # laboratory_id :integer -# is_shixun_marker :boolean default("0") -# admin_visitable :boolean default("0") -# collaborator :boolean default("0") +# platform :string(255) default("0") +# gitea_token :string(255) # gitea_uid :integer +# is_shixun_marker :boolean default("0") # is_sync_pwd :boolean default("1") # watchers_count :integer default("0") # devops_step :integer default("0") -# gitea_token :string(255) -# platform :string(255) +# sponsor_certification :integer default("0") +# sponsor_num :integer default("0") +# sponsored_num :integer default("0") +# award_time :datetime # # Indexes # @@ -55,9 +57,8 @@ # index_users_on_homepage_engineer (homepage_engineer) # index_users_on_homepage_teacher (homepage_teacher) # index_users_on_laboratory_id (laboratory_id) -# index_users_on_login (login) UNIQUE -# index_users_on_mail (mail) UNIQUE -# index_users_on_phone (phone) UNIQUE +# index_users_on_login (login) +# index_users_on_mail (mail) # index_users_on_type (type) # diff --git a/app/models/concerns/dcodes.rb b/app/models/concerns/dcodes.rb new file mode 100644 index 00000000..6c2ff13b --- /dev/null +++ b/app/models/concerns/dcodes.rb @@ -0,0 +1,28 @@ +module Dcodes + DCODES = %W(1 2 3 4 5 6 7 8 9 a b c f 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) + + extend ActiveSupport::Concern + + def generate_dcode(field, num, pre='') + code = DCODES.sample(num).join + while self.class.exists?("#{field}": pre+code) do + code = DCODES.sample(num).join + end + code + end + + def init_project_invite_code + while Project.where(invite_code: nil).size > 0 do + projects = Project.where(invite_code: nil).limit(1000) + set_sql = "" + projects.each do |p| + set_sql += "WHEN #{p.id} THEN '#{DCODES.sample(6).join}' " + end + sql = "UPDATE projects SET invite_code = CASE id "+ set_sql+ "END WHERE id IN(#{projects.ids.join(",")})" + Project.connection.execute(sql) + end + repeat_codes = Project.group(:invite_code).count.select{|k,v| v>1} + Project.where(invite_code: repeat_code.keys).update_all(invite_code: nil) + end + +end \ No newline at end of file diff --git a/app/models/concerns/project_operable.rb b/app/models/concerns/project_operable.rb index b8adf5c8..79d099a2 100644 --- a/app/models/concerns/project_operable.rb +++ b/app/models/concerns/project_operable.rb @@ -9,6 +9,7 @@ module ProjectOperable has_many :reporters, -> { joins(:roles).where(roles: { name: 'Reporter' }) }, class_name: 'Member' has_many :writable_members, -> { joins(:roles).where.not(roles: {name: 'Reporter'}) }, class_name: 'Member' has_many :team_projects, dependent: :destroy + has_many :teams, through: :team_projects, source: :team end def set_owner_permission(creator) @@ -64,7 +65,7 @@ module ProjectOperable if owner.is_a?(User) managers.exists?(user_id: user.id) elsif owner.is_a?(Organization) - managers.exists?(user_id: user.id) || owner.is_admin?(user.id) + managers.exists?(user_id: user.id) || owner.is_only_admin?(user.id) else false end @@ -75,7 +76,7 @@ module ProjectOperable if owner.is_a?(User) developers.exists?(user_id: user.id) elsif owner.is_a?(Organization) - developers.exists?(user_id: user.id) || owner.is_write?(user.id) + developers.exists?(user_id: user.id) || owner.is_only_write?(user.id) else false end diff --git a/app/models/fork_user.rb b/app/models/fork_user.rb index d0915f15..0936f6bf 100644 --- a/app/models/fork_user.rb +++ b/app/models/fork_user.rb @@ -20,4 +20,12 @@ class ForkUser < ApplicationRecord belongs_to :user belongs_to :fork_project, class_name: 'Project', foreign_key: :fork_project_id + after_save :reset_cache_data + after_destroy :reset_cache_data + + def reset_cache_data + self.reset_platform_cache_async_job + self.reset_user_cache_async_job(self.project.owner) + end + end diff --git a/app/models/issue.rb b/app/models/issue.rb index 934e1d31..826ad3a5 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -50,7 +50,7 @@ class Issue < ApplicationRecord #issue_type 1为普通,2为悬赏 - belongs_to :project, :counter_cache => true + belongs_to :project, counter_cache: true, touch: true belongs_to :tracker,optional: true has_many :project_trends, as: :trend, dependent: :destroy has_one :pull_request @@ -73,10 +73,15 @@ class Issue < ApplicationRecord scope :issue_issue, ->{where(issue_classify: [nil,"issue"])} scope :issue_pull_request, ->{where(issue_classify: "pull_request")} scope :issue_index_includes, ->{includes(:tracker, :priority, :version, :issue_status, :journals,:issue_tags,user: :user_extension)} - + scope :closed, ->{where(status_id: 5)} after_update :change_versions_count - after_destroy :update_closed_issues_count_in_project! + after_save :reset_cache_data + after_destroy :update_closed_issues_count_in_project!, :reset_cache_data + def reset_cache_data + self.reset_platform_cache_async_job + self.reset_user_cache_async_job(self.user) + end def get_assign_user User&.find_by_id(self.assigned_to_id) if self.assigned_to_id.present? diff --git a/app/models/laboratory.rb b/app/models/laboratory.rb index 9d3ca07d..699800c9 100644 --- a/app/models/laboratory.rb +++ b/app/models/laboratory.rb @@ -10,7 +10,6 @@ # sync_course :boolean default("0") # sync_subject :boolean default("0") # sync_shixun :boolean default("0") -# is_local :boolean default("0") # # Indexes # diff --git a/app/models/license.rb b/app/models/license.rb index 0a14fb85..dcd5528f 100644 --- a/app/models/license.rb +++ b/app/models/license.rb @@ -7,6 +7,7 @@ # content :text(65535) # created_at :datetime not null # updated_at :datetime not null +# is_secret :boolean default("0") # class License < ApplicationRecord diff --git a/app/models/member.rb b/app/models/member.rb index e72ae7c6..408710a0 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -11,6 +11,7 @@ # course_group_id :integer default("0") # is_collect :integer default("1") # graduation_group_id :integer default("0") +# is_apply_signature :boolean default("0") # # Indexes # diff --git a/app/models/organization.rb b/app/models/organization.rb index 444938e7..666e13ff 100644 --- a/app/models/organization.rb +++ b/app/models/organization.rb @@ -39,15 +39,17 @@ # business :boolean default("0") # profile_completed :boolean default("0") # laboratory_id :integer -# is_shixun_marker :boolean default("0") -# admin_visitable :boolean default("0") -# collaborator :boolean default("0") +# platform :string(255) default("0") +# gitea_token :string(255) # gitea_uid :integer +# is_shixun_marker :boolean default("0") # is_sync_pwd :boolean default("1") # watchers_count :integer default("0") # devops_step :integer default("0") -# gitea_token :string(255) -# platform :string(255) +# sponsor_certification :integer default("0") +# sponsor_num :integer default("0") +# sponsored_num :integer default("0") +# award_time :datetime # # Indexes # @@ -55,9 +57,8 @@ # index_users_on_homepage_engineer (homepage_engineer) # index_users_on_homepage_teacher (homepage_teacher) # index_users_on_laboratory_id (laboratory_id) -# index_users_on_login (login) UNIQUE -# index_users_on_mail (mail) UNIQUE -# index_users_on_phone (phone) UNIQUE +# index_users_on_login (login) +# index_users_on_mail (mail) # index_users_on_type (type) # @@ -109,6 +110,14 @@ class Organization < Owner team_users.joins(:team).where(user_id: user_id, teams: {authorize: %w(read write admin owner)}).present? end + def is_only_admin?(user_id) + team_users.joins(:team).where(user_id: user_id, teams: {authorize: %w(admin)}).present? + end + + def is_only_write?(user_id) + team_users.joins(:team).where(user_id: user_id, teams: {authorize: %w(write)}).present? + end + def is_only_read?(user_id) team_users.joins(:team).where(user_id: user_id, teams: {authorize: %w(read)}).present? end diff --git a/app/models/pinned_project.rb b/app/models/pinned_project.rb new file mode 100644 index 00000000..8e47c9ea --- /dev/null +++ b/app/models/pinned_project.rb @@ -0,0 +1,22 @@ +# == Schema Information +# +# Table name: pinned_projects +# +# id :integer not null, primary key +# user_id :integer +# project_id :integer +# position :integer default("0") +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_pinned_projects_on_project_id (project_id) +# index_pinned_projects_on_user_id (user_id) +# + +class PinnedProject < ApplicationRecord + + belongs_to :user + belongs_to :project +end diff --git a/app/models/praise_tread.rb b/app/models/praise_tread.rb index d13c17dd..5a9c1916 100644 --- a/app/models/praise_tread.rb +++ b/app/models/praise_tread.rb @@ -15,12 +15,22 @@ # praise_tread (praise_tread_object_id,praise_tread_object_type) # + class PraiseTread < ApplicationRecord belongs_to :user belongs_to :praise_tread_object, polymorphic: true, counter_cache: :praises_count has_many :tidings, :as => :container, :dependent => :destroy after_create :send_tiding + after_save :reset_cache_data + after_destroy :reset_cache_data + + def reset_cache_data + self.reset_platform_cache_async_job + if self.praise_tread_object.is_a?(Project) + self.reset_user_cache_async_job(self.praise_tread_object&.owner) + end + end def send_tiding case self.praise_tread_object_type diff --git a/app/models/project.rb b/app/models/project.rb index a75cf3de..ba657c7f 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1,82 +1,85 @@ -# == Schema Information -# -# Table name: projects -# -# id :integer not null, primary key -# name :string(255) default(""), not null -# description :text(4294967295) -# homepage :string(255) default("") -# is_public :boolean default("1"), not null -# parent_id :integer -# created_on :datetime -# updated_on :datetime -# identifier :string(255) -# status :integer default("1"), not null -# lft :integer -# rgt :integer -# inherit_members :boolean default("0"), not null -# project_type :integer default("0") -# hidden_repo :boolean default("0"), not null -# attachmenttype :integer default("1") -# user_id :integer -# dts_test :integer default("0") -# enterprise_name :string(255) -# organization_id :integer -# project_new_type :integer -# gpid :integer -# forked_from_project_id :integer -# forked_count :integer default("0") -# publish_resource :integer default("0") -# visits :integer default("0") -# hot :integer default("0") -# invite_code :string(255) -# qrcode :string(255) -# qrcode_expiretime :integer default("0") -# script :text(65535) -# training_status :integer default("0") -# rep_identifier :string(255) -# project_category_id :integer -# project_language_id :integer -# praises_count :integer default("0") -# watchers_count :integer default("0") -# issues_count :integer default("0") -# pull_requests_count :integer default("0") -# language :string(255) -# versions_count :integer default("0") -# issue_tags_count :integer default("0") -# closed_issues_count :integer default("0") -# open_devops :boolean default("0") -# gitea_webhook_id :integer -# open_devops_count :integer default("0") -# recommend :boolean default("0") -# platform :integer default("0") -# license_id :integer -# ignore_id :integer -# default_branch :string(255) default("master") -# website :string(255) -# lesson_url :string(255) -# -# Indexes -# -# index_projects_on_forked_from_project_id (forked_from_project_id) -# index_projects_on_identifier (identifier) -# index_projects_on_is_public (is_public) -# index_projects_on_lft (lft) -# index_projects_on_name (name) -# index_projects_on_platform (platform) -# index_projects_on_project_type (project_type) -# index_projects_on_recommend (recommend) -# index_projects_on_rgt (rgt) -# index_projects_on_status (status) -# index_projects_on_updated_on (updated_on) -# - +# == Schema Information +# +# Table name: projects +# +# id :integer not null, primary key +# name :string(255) default(""), not null +# description :text(4294967295) +# homepage :string(255) default("") +# is_public :boolean default("1"), not null +# parent_id :integer +# created_on :datetime +# updated_on :datetime +# identifier :string(255) +# status :integer default("1"), not null +# lft :integer +# rgt :integer +# inherit_members :boolean default("0"), not null +# project_type :integer default("0") +# hidden_repo :boolean default("0"), not null +# attachmenttype :integer default("1") +# user_id :integer +# dts_test :integer default("0") +# enterprise_name :string(255) +# organization_id :integer +# project_new_type :integer +# gpid :integer +# forked_from_project_id :integer +# forked_count :integer default("0") +# publish_resource :integer default("0") +# visits :integer default("0") +# hot :integer default("0") +# invite_code :string(255) +# qrcode :string(255) +# qrcode_expiretime :integer default("0") +# script :text(65535) +# training_status :integer default("0") +# rep_identifier :string(255) +# project_category_id :integer +# project_language_id :integer +# license_id :integer +# ignore_id :integer +# praises_count :integer default("0") +# watchers_count :integer default("0") +# issues_count :integer default("0") +# pull_requests_count :integer default("0") +# language :string(255) +# versions_count :integer default("0") +# issue_tags_count :integer default("0") +# closed_issues_count :integer default("0") +# open_devops :boolean default("0") +# gitea_webhook_id :integer +# open_devops_count :integer default("0") +# recommend :boolean default("0") +# platform :integer default("0") +# default_branch :string(255) default("master") +# website :string(255) +# order_index :integer default("0") +# lesson_url :string(255) +# +# Indexes +# +# index_projects_on_forked_from_project_id (forked_from_project_id) +# index_projects_on_identifier (identifier) +# index_projects_on_is_public (is_public) +# index_projects_on_lft (lft) +# index_projects_on_name (name) +# index_projects_on_platform (platform) +# index_projects_on_project_type (project_type) +# index_projects_on_recommend (recommend) +# index_projects_on_rgt (rgt) +# index_projects_on_status (status) +# index_projects_on_updated_on (updated_on) +# + + class Project < ApplicationRecord include Matchable include Publicable include Watchable include ProjectOperable + include Dcodes # common:开源托管项目 # mirror:普通镜像项目,没有定时同步功能 @@ -112,11 +115,14 @@ class Project < ApplicationRecord has_many :praise_treads, as: :praise_tread_object, dependent: :destroy has_and_belongs_to_many :trackers, :order => "#{Tracker.table_name}.position" has_one :project_detail, dependent: :destroy - has_many :team_projects, dependent: :destroy has_many :project_units, dependent: :destroy has_one :applied_transfer_project,-> { order created_at: :desc }, dependent: :destroy + has_many :pinned_projects, dependent: :destroy + has_many :has_pinned_users, through: :pinned_projects, source: :user - after_save :check_project_members + after_save :check_project_members, :reset_cache_data + before_save :set_invite_code + after_destroy :reset_cache_data scope :project_statics_select, -> {select(:id,:name, :is_public, :identifier, :status, :project_type, :user_id, :forked_count, :visits, :project_category_id, :project_language_id, :license_id, :ignore_id, :watchers_count, :created_on)} scope :no_anomory_projects, -> {where("projects.user_id is not null and projects.user_id != ?", 2)} scope :recommend, -> { visible.project_statics_select.where(recommend: true) } @@ -124,6 +130,20 @@ class Project < ApplicationRecord delegate :content, to: :project_detail, allow_nil: true delegate :name, to: :license, prefix: true, allow_nil: true + def reset_cache_data + if changes[:user_id].present? + first_owner = Owner.find_by_id(changes[:user_id].first) + self.reset_user_cache_async_job(first_owner) + end + self.reset_platform_cache_async_job + self.reset_user_cache_async_job(self.owner) + end + + def set_invite_code + if self.invite_code.nil? + self.invite_code= self.generate_dcode('invite_code', 6) + end + end def self.search_project(search) ransack(name_or_identifier_cont: search) diff --git a/app/models/project_category.rb b/app/models/project_category.rb index 67b80299..3a981981 100644 --- a/app/models/project_category.rb +++ b/app/models/project_category.rb @@ -8,6 +8,11 @@ # projects_count :integer default("0") # created_at :datetime not null # updated_at :datetime not null +# ancestry :string(255) +# +# Indexes +# +# index_project_categories_on_ancestry (ancestry) # class ProjectCategory < ApplicationRecord diff --git a/app/models/pull_request.rb b/app/models/pull_request.rb index cf057c3f..7ce08acc 100644 --- a/app/models/pull_request.rb +++ b/app/models/pull_request.rb @@ -31,13 +31,23 @@ class PullRequest < ApplicationRecord belongs_to :issue belongs_to :user - belongs_to :project, :counter_cache => true + belongs_to :project, counter_cache: true, touch: true # belongs_to :fork_project, foreign_key: :fork_project_id has_many :pull_request_assigns, foreign_key: :pull_request_id has_many :pull_request_tags, foreign_key: :pull_request_id has_many :project_trends, as: :trend, dependent: :destroy has_many :attachments, as: :container, dependent: :destroy + scope :merged_and_closed, ->{where.not(status: 1)} + + after_save :reset_cache_data + after_destroy :reset_cache_data + + def reset_cache_data + self.reset_platform_cache_async_job + self.reset_user_cache_async_job(self.user) + end + def fork_project Project.find_by(id: self.fork_project_id) end diff --git a/app/models/repository.rb b/app/models/repository.rb index 0daa4b91..cefdf6ea 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -27,6 +27,7 @@ # # Indexes # +# index_repositories_on_identifier (identifier) # index_repositories_on_project_id (project_id) # index_repositories_on_user_id (user_id) # @@ -82,5 +83,8 @@ class Repository < ApplicationRecord source_clone_url.blank? ? mirror_url : source_clone_url end + def config_accelerator? + !source_clone_url.blank? + end end diff --git a/app/models/user.rb b/app/models/user.rb index 948a55f3..fa862130 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -39,15 +39,17 @@ # business :boolean default("0") # profile_completed :boolean default("0") # laboratory_id :integer -# is_shixun_marker :boolean default("0") -# admin_visitable :boolean default("0") -# collaborator :boolean default("0") +# platform :string(255) default("0") +# gitea_token :string(255) # gitea_uid :integer +# is_shixun_marker :boolean default("0") # is_sync_pwd :boolean default("1") # watchers_count :integer default("0") # devops_step :integer default("0") -# gitea_token :string(255) -# platform :string(255) +# sponsor_certification :integer default("0") +# sponsor_num :integer default("0") +# sponsored_num :integer default("0") +# award_time :datetime # # Indexes # @@ -55,9 +57,8 @@ # index_users_on_homepage_engineer (homepage_engineer) # index_users_on_homepage_teacher (homepage_teacher) # index_users_on_laboratory_id (laboratory_id) -# index_users_on_login (login) UNIQUE -# index_users_on_mail (mail) UNIQUE -# index_users_on_phone (phone) UNIQUE +# index_users_on_login (login) +# index_users_on_mail (mail) # index_users_on_type (type) # @@ -164,6 +165,11 @@ class User < Owner has_many :organization_users, dependent: :destroy has_many :organizations, through: :organization_users + has_many :pinned_projects, dependent: :destroy + has_many :is_pinned_projects, through: :pinned_projects, source: :project + accepts_nested_attributes_for :is_pinned_projects + has_many :issues, dependent: :destroy, foreign_key: :author_id + has_many :pull_requests, dependent: :destroy # Groups and active users scope :active, lambda { where(status: STATUS_ACTIVE) } @@ -176,7 +182,9 @@ class User < Owner attr_accessor :password, :password_confirmation - delegate :gender, :department_id, :school_id, :location, :location_city, :technical_title, to: :user_extension, allow_nil: true + delegate :description, :gender, :department_id, :school_id, :location, :location_city, + :show_email, :show_location, :show_department, + :technical_title, :province, :city, :custom_department, to: :user_extension, allow_nil: true before_save :update_hashed_password after_create do @@ -195,6 +203,20 @@ class User < Owner validate :validate_sensitive_string validate :validate_password_length + # 用户参与的所有项目 + def full_member_projects + normal_projects = Project.members_projects(self.id).to_sql + org_projects = Project.joins(teams: :team_users).where(team_users: {user_id: self.id}).to_sql + return Project.from("( #{ normal_projects} UNION #{ org_projects } ) AS projects").distinct + end + + # 用户管理的所有项目 + def full_admin_projects + normal_projects = Project.joins(members: :roles).where(roles: {name: 'Manager'}, members: {user_id: self.id}).to_sql + org_projects = Project.joins(teams: :team_users).where(teams: {authorize: %w(admin owner)}, team_users: {user_id: self.id}).to_sql + return Project.from("( #{ normal_projects} UNION #{ org_projects } ) AS projects").distinct + end + def name login end diff --git a/app/models/user_action.rb b/app/models/user_action.rb index 17935969..3ad8010e 100644 --- a/app/models/user_action.rb +++ b/app/models/user_action.rb @@ -12,9 +12,7 @@ # # Indexes # -# index_user_actions_on_ip (ip) -# index_user_actions_on_user_id (user_id) -# index_user_actions_on_user_id_and_action_type (user_id,action_type) +# index_user_actions_on_ip (ip) # class UserAction < ApplicationRecord diff --git a/app/models/user_agent.rb b/app/models/user_agent.rb index ba519d6f..49d7b35a 100644 --- a/app/models/user_agent.rb +++ b/app/models/user_agent.rb @@ -10,13 +10,10 @@ # updated_at :datetime not null # register_status :integer default("0") # action_status :integer default("0") -# is_delete :boolean default("0") -# user_id :integer # # Indexes # -# index_user_agents_on_ip (ip) -# index_user_agents_on_user_id (user_id) +# index_user_agents_on_ip (ip) UNIQUE # class UserAgent < ApplicationRecord diff --git a/app/models/user_extension.rb b/app/models/user_extension.rb index 4afd89bd..0749d1f7 100644 --- a/app/models/user_extension.rb +++ b/app/models/user_extension.rb @@ -22,9 +22,12 @@ # school_id :integer # description :string(255) default("") # department_id :integer -# honor :text(65535) -# edu_background :integer -# edu_entry_year :integer +# province :string(255) +# city :string(255) +# custom_department :string(255) +# show_email :boolean default("0") +# show_location :boolean default("0") +# show_department :boolean default("0") # # Indexes # @@ -33,25 +36,25 @@ # index_user_extensions_on_user_id (user_id) # -class UserExtension < ApplicationRecord - # identity 0: 教师教授 1: 学生, 2: 专业人士, 3: 开发者 - enum identity: { teacher: 0, student: 1, professional: 2, developer: 3, enterprise: 4, unselect: -1 } - - belongs_to :user, touch: true - belongs_to :school, optional: true - # belongs_to :department, optional: true - - # before_save :set_laboratory_school - - def identity_text - I18n.t("user.identity.#{identity}") - end - - private - - def set_laboratory_school - # return unless new_record? - - # self.school_id = Laboratory.current.school_id if school_id.blank? && !Laboratory.current.main_site? - end -end +class UserExtension < ApplicationRecord + # identity 0: 教师教授 1: 学生, 2: 专业人士, 3: 开发者 + enum identity: { teacher: 0, student: 1, professional: 2, developer: 3, enterprise: 4, unselect: -1 } + + belongs_to :user, touch: true + belongs_to :school, optional: true + # belongs_to :department, optional: true + + # before_save :set_laboratory_school + + def identity_text + I18n.t("user.identity.#{identity}") + end + + private + + def set_laboratory_school + # return unless new_record? + + # self.school_id = Laboratory.current.school_id if school_id.blank? && !Laboratory.current.main_site? + end +end diff --git a/app/models/version.rb b/app/models/version.rb index 9ba59cb4..4907af2c 100644 --- a/app/models/version.rb +++ b/app/models/version.rb @@ -24,11 +24,12 @@ # class Version < ApplicationRecord - belongs_to :project, counter_cache: true, optional: true + belongs_to :project, counter_cache: true, touch: true, optional: true has_many :issues, class_name: "Issue", foreign_key: "fixed_version_id" belongs_to :user, optional: true scope :version_includes, ->{includes(:issues, :user)} + scope :closed, ->{where(status: 'closed')} # def open_issues_count # issues.select(:id,:status_id).where(status_id: [1,2,3,4,6]).size diff --git a/app/models/watcher.rb b/app/models/watcher.rb index 76a82702..ccc8eefa 100644 --- a/app/models/watcher.rb +++ b/app/models/watcher.rb @@ -15,10 +15,24 @@ # watchers_user_id_type (user_id,watchable_type) # -class Watcher < ApplicationRecord - belongs_to :user - - belongs_to :watchable, polymorphic: true, counter_cache: :watchers_count - - scope :watching_users, ->(watchable_id){ where("watchable_type = ? and user_id = ?",'User',watchable_id)} -end +class Watcher < ApplicationRecord + belongs_to :user + + belongs_to :watchable, polymorphic: true, counter_cache: :watchers_count + + scope :watching_users, ->(watchable_id){ where("watchable_type = ? and user_id = ?",'User',watchable_id)} + + after_save :reset_cache_data + after_destroy :reset_cache_data + + def reset_cache_data + if self.watchable.is_a?(User) + self.reset_user_cache_async_job(self.watchable) + end + if self.watchable.is_a?(Project) + self.reset_user_cache_async_job(self.watchable&.owner) + end + self.reset_platform_cache_async_job + end + +end diff --git a/app/queries/admins/apply_item_bank_query.rb b/app/queries/admins/apply_item_bank_query.rb index 37b6d25a..922d136e 100644 --- a/app/queries/admins/apply_item_bank_query.rb +++ b/app/queries/admins/apply_item_bank_query.rb @@ -26,7 +26,7 @@ class Admins::ApplyItemBankQuery < ApplicationQuery keyword = params[:keyword].to_s.strip if keyword.present? applies = applies.joins(user: { user_extension: :school }) - .where('CONCAT(lastname,firstname) LIKE :keyword OR schools.name LIKE :keyword', keyword: "%#{keyword}%") + .where('CONCAT_WS(lastname,firstname, nickname) LIKE :keyword OR schools.name LIKE :keyword', keyword: "%#{keyword}%") end custom_sort(applies, params[:sort_by], params[:sort_direction]) diff --git a/app/queries/admins/apply_user_authentication_query.rb b/app/queries/admins/apply_user_authentication_query.rb index a4d1c2a4..60b781d1 100644 --- a/app/queries/admins/apply_user_authentication_query.rb +++ b/app/queries/admins/apply_user_authentication_query.rb @@ -26,7 +26,7 @@ class Admins::ApplyUserAuthenticationQuery < ApplicationQuery keyword = params[:keyword].to_s.strip if keyword.present? applies = applies.joins(user: { user_extension: :school }) - .where('CONCAT(lastname,firstname) LIKE :keyword OR schools.name LIKE :keyword', keyword: "%#{keyword}%") + .where('CONCAT_WS(lastname,firstname,nickname) LIKE :keyword OR schools.name LIKE :keyword', keyword: "%#{keyword}%") end custom_sort(applies, params[:sort_by], params[:sort_direction]) diff --git a/app/queries/admins/course_list_query.rb b/app/queries/admins/course_list_query.rb index 24eedaf1..b97a9ceb 100644 --- a/app/queries/admins/course_list_query.rb +++ b/app/queries/admins/course_list_query.rb @@ -19,7 +19,7 @@ class Admins::CourseListQuery < ApplicationQuery case search_type when "0" course_lists = course_lists.joins(:user) - .where('CONCAT(lastname, firstname) like :keyword', keyword: "%#{keyword}%") + .where('CONCAT_WS(lastname, firstname, nickname) like :keyword', keyword: "%#{keyword}%") when "1" course_lists = course_lists.where('name like :keyword', keyword: "%#{keyword}%") end diff --git a/app/queries/admins/course_query.rb b/app/queries/admins/course_query.rb index e883650d..b1466e22 100644 --- a/app/queries/admins/course_query.rb +++ b/app/queries/admins/course_query.rb @@ -35,7 +35,7 @@ class Admins::CourseQuery < ApplicationQuery # 关键字 keyword = params[:keyword].to_s.strip if keyword - sql = 'CONCAT(lastname, firstname) LIKE :keyword OR courses.name LIKE :keyword OR course_lists.name LIKE :keyword' + sql = 'CONCAT_WS(lastname, firstname, nickname) LIKE :keyword OR courses.name LIKE :keyword OR course_lists.name LIKE :keyword' courses = courses.joins(:teacher, :course_list).where(sql, keyword: "%#{keyword}%") end diff --git a/app/queries/admins/laboratory_shixun_query.rb b/app/queries/admins/laboratory_shixun_query.rb index d489aed2..9b9bf6a2 100644 --- a/app/queries/admins/laboratory_shixun_query.rb +++ b/app/queries/admins/laboratory_shixun_query.rb @@ -11,7 +11,7 @@ class Admins::LaboratoryShixunQuery < ApplicationQuery keyword = params[:keyword].to_s.strip if keyword.present? - like_sql = 'shixuns.name LIKE :keyword OR CONCAT(users.lastname, users.firstname) LIKE :keyword' + like_sql = 'shixuns.name LIKE :keyword OR CONCAT_WS(users.lastname, users.firstname, users.nickname) LIKE :keyword' laboratory_shixuns = laboratory_shixuns.joins(shixun: :user).where(like_sql, keyword: "%#{keyword}%") end diff --git a/app/queries/admins/laboratory_subject_query.rb b/app/queries/admins/laboratory_subject_query.rb index 316ea974..619aeb2c 100644 --- a/app/queries/admins/laboratory_subject_query.rb +++ b/app/queries/admins/laboratory_subject_query.rb @@ -11,7 +11,7 @@ class Admins::LaboratorySubjectQuery < ApplicationQuery keyword = params[:keyword].to_s.strip if keyword.present? - like_sql = 'subjects.name LIKE :keyword OR CONCAT(users.lastname, users.firstname) LIKE :keyword' + like_sql = 'subjects.name LIKE :keyword OR CONCAT_WS(users.lastname, users.firstname, users.nickname) LIKE :keyword' laboratory_subjects = laboratory_subjects.joins(subject: :user).where(like_sql, keyword: "%#{keyword}%") end diff --git a/app/queries/admins/subject_query.rb b/app/queries/admins/subject_query.rb index 0415deb9..df2ac40e 100644 --- a/app/queries/admins/subject_query.rb +++ b/app/queries/admins/subject_query.rb @@ -40,7 +40,7 @@ class Admins::SubjectQuery < ApplicationQuery # 关键字 keyword = params[:keyword].to_s.strip if keyword - sql = 'CONCAT(lastname, firstname) LIKE :keyword OR subjects.name LIKE :keyword' + sql = 'CONCAT_WS(lastname, firstname, nickname) LIKE :keyword OR subjects.name LIKE :keyword' subjects = subjects.joins(:user).where(sql, keyword: "%#{keyword}%") end diff --git a/app/queries/admins/user_query.rb b/app/queries/admins/user_query.rb index cdf158c6..670eef58 100644 --- a/app/queries/admins/user_query.rb +++ b/app/queries/admins/user_query.rb @@ -30,14 +30,14 @@ class Admins::UserQuery < ApplicationQuery # 关键字检索 keyword = params[:keyword].to_s.strip.presence if keyword - sql = 'CONCAT(lastname, firstname) LIKE :keyword OR login LIKE :keyword OR mail LIKE :keyword OR phone LIKE :keyword' + sql = 'CONCAT_WS(lastname, firstname, nickname) LIKE :keyword OR login LIKE :keyword OR mail LIKE :keyword OR phone LIKE :keyword' users = users.where(sql, keyword: "%#{keyword}%") end # 姓名 name = params[:name].to_s.strip.presence if name.present? - users = users.where('CONCAT(lastname, firstname) LIKE :name', name: "%#{name}%") + users = users.where('CONCAT_WS(lastname, firstname, nickname) LIKE :name', name: "%#{name}%") end # 单位ID diff --git a/app/queries/projects/list_my_query.rb b/app/queries/projects/list_my_query.rb index 5bda5612..c9f4544d 100644 --- a/app/queries/projects/list_my_query.rb +++ b/app/queries/projects/list_my_query.rb @@ -53,10 +53,15 @@ class Projects::ListMyQuery < ApplicationQuery q = projects.ransack(name_or_identifier_cont: params[:search]) - scope = q.result.includes(:project_category, :project_language,:owner, :repository) + scope = q.result.includes(:project_category, :project_language,:owner, :repository, :has_pinned_users) sort = params[:sort_by] || "updated_on" sort_direction = params[:sort_direction] || "desc" - scope.order("projects.#{sort} #{sort_direction}") + + if params[:choosed].present? && params[:choosed].is_a?(Array) + scope.order("FIELD(id, #{params[:choosed].reverse.join(",")}) desc") + else + scope.order("projects.#{sort} #{sort_direction}") + end end end diff --git a/app/queries/user_query.rb b/app/queries/user_query.rb index 326665fe..f2964c7d 100644 --- a/app/queries/user_query.rb +++ b/app/queries/user_query.rb @@ -10,7 +10,7 @@ class UserQuery < ApplicationQuery # 真实姓名 if name = strip_param(:name) - users = users.where('LOWER(CONCAT(users.lastname, users.firstname)) LIKE ?', "%#{name.downcase}%") + users = users.where('LOWER(CONCAT_WS(users.lastname, users.firstname, users.nickname)) LIKE ?', "%#{name.downcase}%") end # 单位名称 diff --git a/app/services/admins/import_user_service.rb b/app/services/admins/import_user_service.rb index f3408051..298bf1e1 100644 --- a/app/services/admins/import_user_service.rb +++ b/app/services/admins/import_user_service.rb @@ -84,7 +84,7 @@ class Admins::ImportUserService < ApplicationService if data.identity.to_i == 1 users = users.where(user_extensions: { student_id: data.student_id }) else - users = users.where(user_extensions: { technical_title: data.technical_title }).where('CONCAT(users.lastname,users.firstname) = ?', data.name) + users = users.where(user_extensions: { technical_title: data.technical_title }).where('CONCAT_WS(users.lastname,users.firstname,users.nickname) = ?', data.name) end users.first diff --git a/app/services/cache/platform_follow_count_service.rb b/app/services/cache/platform_follow_count_service.rb new file mode 100644 index 00000000..5398da5a --- /dev/null +++ b/app/services/cache/platform_follow_count_service.rb @@ -0,0 +1,41 @@ +class Cache::PlatformFollowCountService < ApplicationService + attr_reader :increment_count + + def initialize(increment_count=0) + @increment_count = increment_count + end + + def call + set_platform_follow_count + + platform_follow_count + end + + def reset + reset_platform_follow_count + + platform_follow_count + end + + private + + def platform_follow_count_key + "platform-follow-count" + end + + def platform_follow_count + $redis_cache.get(platform_follow_count_key).to_i + end + + def set_platform_follow_count + if $redis_cache.exists(platform_follow_count_key) + $redis_cache.incrby(platform_follow_count_key, increment_count) + else + reset_platform_follow_count + end + end + + def reset_platform_follow_count + $redis_cache.set(platform_follow_count_key, Watcher.where(watchable_type: 'User').count) + end +end \ No newline at end of file diff --git a/app/services/cache/platform_issue_count_service.rb b/app/services/cache/platform_issue_count_service.rb new file mode 100644 index 00000000..95511f48 --- /dev/null +++ b/app/services/cache/platform_issue_count_service.rb @@ -0,0 +1,41 @@ +class Cache::PlatformIssueCountService < ApplicationService + attr_reader :increment_count + + def initialize(increment_count=0) + @increment_count = increment_count + end + + def call + set_platform_issue_count + + platform_issue_count + end + + def reset + reset_platform_issue_count + + platform_issue_count + end + + private + + def platform_issue_count_key + "platform-issue-count" + end + + def platform_issue_count + $redis_cache.get(platform_issue_count_key).to_i + end + + def set_platform_issue_count + if $redis_cache.exists(platform_issue_count_key) + $redis_cache.incrby(platform_issue_count_key, increment_count) + else + reset_platform_issue_count + end + end + + def reset_platform_issue_count + $redis_cache.set(platform_issue_count_key, Issue.count) + end +end \ No newline at end of file diff --git a/app/services/cache/platform_project_count_service.rb b/app/services/cache/platform_project_count_service.rb new file mode 100644 index 00000000..d807682f --- /dev/null +++ b/app/services/cache/platform_project_count_service.rb @@ -0,0 +1,41 @@ +class Cache::PlatformProjectCountService < ApplicationService + attr_reader :increment_count + + def initialize(increment_count=0) + @increment_count = increment_count + end + + def call + set_platform_project_count + + platform_project_count + end + + def reset + reset_platform_project_count + + platform_project_count + end + + private + + def platform_project_count_key + "platform-project-count" + end + + def platform_project_count + $redis_cache.get(platform_project_count_key).to_i + end + + def set_platform_project_count + if $redis_cache.exists(platform_project_count_key) + $redis_cache.incrby(platform_project_count_key, increment_count) + else + reset_platform_project_count + end + end + + def reset_platform_project_count + $redis_cache.set(platform_project_count_key, Project.count) + end +end \ No newline at end of file diff --git a/app/services/cache/platform_project_fork_count_service.rb b/app/services/cache/platform_project_fork_count_service.rb new file mode 100644 index 00000000..21d6c063 --- /dev/null +++ b/app/services/cache/platform_project_fork_count_service.rb @@ -0,0 +1,41 @@ +class Cache::PlatformProjectForkCountService < ApplicationService + attr_reader :increment_count + + def initialize(increment_count=0) + @increment_count = increment_count + end + + def call + set_platform_project_fork_count + + platform_project_fork_count + end + + def reset + reset_platform_project_fork_count + + platform_project_fork_count + end + + private + + def platform_project_fork_count_key + "platform-project-fork-count" + end + + def platform_project_fork_count + $redis_cache.get(platform_project_fork_count_key).to_i + end + + def set_platform_project_fork_count + if $redis_cache.exists(platform_project_fork_count_key) + $redis_cache.incrby(platform_project_fork_count_key, increment_count) + else + reset_platform_project_fork_count + end + end + + def reset_platform_project_fork_count + $redis_cache.set(platform_project_fork_count_key, ForkUser.count) + end +end \ No newline at end of file diff --git a/app/services/cache/platform_project_languages_count_service.rb b/app/services/cache/platform_project_languages_count_service.rb new file mode 100644 index 00000000..2b4f0fae --- /dev/null +++ b/app/services/cache/platform_project_languages_count_service.rb @@ -0,0 +1,57 @@ +class Cache::PlatformProjectLanguagesCountService < ApplicationService + attr_reader :key, :increment_count + + def initialize(key=nil, increment_count=0) + @key = key + @increment_count = increment_count + end + + def call + set_platform_project_language_count + + platform_project_language_count + end + + def reset_by_key + reset_platform_project_language_count_by_key + + platform_project_language_count + end + + def reset + reset_platform_project_language_count + + platform_project_language_count + end + + private + + def platform_project_language_count_key + "platform-project-language-count" + end + + def platform_project_language_count + $redis_cache.hgetall(platform_project_language_count_key).transform_values(&:to_i) + end + + def set_platform_project_language_count + if $redis_cache.hlen(platform_project_language_count_key) == 0 + reset_platform_project_language_count + elsif $redis_cache.hget(platform_project_language_count_key, key).nil? + reset_platform_project_language_count_by_key + else + $redis_cache.hincrby(platform_project_language_count_key, key, increment_count) + end + end + + def reset_platform_project_language_count_by_key + return if key.nil? + $redis_cache.hset(platform_project_language_count_key, key, Project.joins(:project_language).where(project_languages: {name: key}).count) + end + + def reset_platform_project_language_count + Project.joins(:project_language).group("project_languages.name").count.each do |k, v| + $redis_cache.hset(platform_project_language_count_key, k, v) + end + end +end \ No newline at end of file diff --git a/app/services/cache/platform_project_praises_count_service.rb b/app/services/cache/platform_project_praises_count_service.rb new file mode 100644 index 00000000..6c78b802 --- /dev/null +++ b/app/services/cache/platform_project_praises_count_service.rb @@ -0,0 +1,41 @@ +class Cache::PlatformProjectPraisesCountService < ApplicationService + attr_reader :increment_count + + def initialize(increment_count=0) + @increment_count = increment_count + end + + def call + set_platform_project_praises_count + + platform_project_praises_count + end + + def reset + reset_platform_project_praises_count + + platform_project_praises_count + end + + private + + def platform_project_praises_count_key + "platform-project-praises-count" + end + + def platform_project_praises_count + $redis_cache.get(platform_project_praises_count_key).to_i + end + + def set_platform_project_praises_count + if $redis_cache.exists(platform_project_praises_count_key) + $redis_cache.incrby(platform_project_praises_count_key, increment_count) + else + reset_platform_project_praises_count + end + end + + def reset_platform_project_praises_count + $redis_cache.set(platform_project_praises_count_key, PraiseTread.where(praise_tread_object_type: "Project").count) + end +end \ No newline at end of file diff --git a/app/services/cache/platform_project_watchers_count_service.rb b/app/services/cache/platform_project_watchers_count_service.rb new file mode 100644 index 00000000..70c834d2 --- /dev/null +++ b/app/services/cache/platform_project_watchers_count_service.rb @@ -0,0 +1,41 @@ +class Cache::PlatformProjectWatchersCountService < ApplicationService + attr_reader :increment_count + + def initialize(increment_count=0) + @increment_count = increment_count + end + + def call + set_platform_project_watchers_count + + platform_project_watchers_count + end + + def reset + reset_platform_project_watchers_count + + platform_project_watchers_count + end + + private + + def platform_project_watchers_count_key + "platform-project-watchers-count" + end + + def platform_project_watchers_count + $redis_cache.get(platform_project_watchers_count_key).to_i + end + + def set_platform_project_watchers_count + if $redis_cache.exists(platform_project_watchers_count_key) + $redis_cache.incrby(platform_project_watchers_count_key, increment_count) + else + reset_platform_project_watchers_count + end + end + + def reset_platform_project_watchers_count + $redis_cache.set(platform_project_watchers_count_key, Watcher.where(watchable_type: 'Project').count) + end +end \ No newline at end of file diff --git a/app/services/cache/platform_pullrequest_count_service.rb b/app/services/cache/platform_pullrequest_count_service.rb new file mode 100644 index 00000000..c497c488 --- /dev/null +++ b/app/services/cache/platform_pullrequest_count_service.rb @@ -0,0 +1,41 @@ +class Cache::PlatformPullrequestCountService < ApplicationService + attr_reader :increment_count + + def initialize(increment_count=0) + @increment_count = increment_count + end + + def call + set_platform_pullrequest_count + + platform_pullrequest_count + end + + def reset + reset_platform_pullrequest_count + + platform_pullrequest_count + end + + private + + def platform_pullrequest_count_key + "platform-pullrequest-count" + end + + def platform_pullrequest_count + $redis_cache.get(platform_pullrequest_count_key).to_i + end + + def set_platform_pullrequest_count + if $redis_cache.exists(platform_pullrequest_count_key) + $redis_cache.incrby(platform_pullrequest_count_key, increment_count) + else + reset_platform_pullrequest_count + end + end + + def reset_platform_pullrequest_count + $redis_cache.set(platform_pullrequest_count_key, PullRequest.count) + end +end \ No newline at end of file diff --git a/app/services/cache/user_follow_count_service.rb b/app/services/cache/user_follow_count_service.rb new file mode 100644 index 00000000..c583c32b --- /dev/null +++ b/app/services/cache/user_follow_count_service.rb @@ -0,0 +1,43 @@ +class Cache::UserFollowCountService < ApplicationService + attr_reader :user, :increment_count + + def initialize(user, increment_count=0) + @user = user + @increment_count = increment_count + end + + def call + set_user_follow_count + + user_follow_count + end + + def reset + reset_user_follow_count + + user_follow_count + end + + private + + def user_follow_count_key + "user-follow-count-#{user.id}" + end + + def user_follow_count + $redis_cache.get(user_follow_count_key).to_i + end + + def set_user_follow_count + if $redis_cache.exists(user_follow_count_key) + $redis_cache.incrby(user_follow_count_key, increment_count) + else + reset_user_follow_count + end + end + + def reset_user_follow_count + return if user.nil? + $redis_cache.set(user_follow_count_key, Watcher.where(watchable: user).count) + end +end \ No newline at end of file diff --git a/app/services/cache/user_issue_count_service.rb b/app/services/cache/user_issue_count_service.rb new file mode 100644 index 00000000..9e5f2d49 --- /dev/null +++ b/app/services/cache/user_issue_count_service.rb @@ -0,0 +1,43 @@ +class Cache::UserIssueCountService < ApplicationService + attr_reader :user, :increment_count + + def initialize(user, increment_count=0) + @user = user + @increment_count = increment_count + end + + def call + set_user_issue_count + + user_issue_count + end + + def reset + reset_user_issue_count + + user_issue_count + end + + private + + def user_issue_count_key + "user-issue-count-#{user.id}" + end + + def user_issue_count + $redis_cache.get(user_issue_count_key).to_i + end + + def set_user_issue_count + if $redis_cache.exists(user_issue_count_key) + $redis_cache.incrby(user_issue_count_key, increment_count) + else + reset_user_issue_count + end + end + + def reset_user_issue_count + return if user.nil? + $redis_cache.set(user_issue_count_key, Issue.where(author_id: user.id).count) + end +end \ No newline at end of file diff --git a/app/services/cache/user_project_count_service.rb b/app/services/cache/user_project_count_service.rb new file mode 100644 index 00000000..67718416 --- /dev/null +++ b/app/services/cache/user_project_count_service.rb @@ -0,0 +1,43 @@ +class Cache::UserProjectCountService < ApplicationService + attr_reader :user, :increment_count + + def initialize(user, increment_count=0) + @user = user + @increment_count = increment_count + end + + def call + set_user_project_count + + user_project_count + end + + def reset + reset_user_project_count + + user_project_count + end + + private + + def user_project_count_key + "user-project-count-#{user.id}" + end + + def user_project_count + $redis_cache.get(user_project_count_key).to_i + end + + def set_user_project_count + if $redis_cache.exists(user_project_count_key) + $redis_cache.incrby(user_project_count_key, increment_count) + else + reset_user_project_count + end + end + + def reset_user_project_count + return if user.nil? + $redis_cache.set(user_project_count_key, user.projects.count) + end +end \ No newline at end of file diff --git a/app/services/cache/user_project_fork_count_service.rb b/app/services/cache/user_project_fork_count_service.rb new file mode 100644 index 00000000..134e4ed6 --- /dev/null +++ b/app/services/cache/user_project_fork_count_service.rb @@ -0,0 +1,43 @@ +class Cache::UserProjectForkCountService < ApplicationService + attr_reader :user, :increment_count + + def initialize(user, increment_count=0) + @user = user + @increment_count = increment_count + end + + def call + set_user_project_fork_count + + user_project_fork_count + end + + def reset + reset_user_project_fork_count + + user_project_fork_count + end + + private + + def user_project_fork_count_key + "user-project-fork-count-#{user.id}" + end + + def user_project_fork_count + $redis_cache.get(user_project_fork_count_key).to_i + end + + def set_user_project_fork_count + if $redis_cache.exists(user_project_fork_count_key) + $redis_cache.incrby(user_project_fork_count_key, increment_count) + else + reset_user_project_fork_count + end + end + + def reset_user_project_fork_count + return if user.nil? + $redis_cache.set(user_project_fork_count_key, ForkUser.joins(:project).where(projects: {user_id: user.id}).count) + end +end \ No newline at end of file diff --git a/app/services/cache/user_project_languages_count_service.rb b/app/services/cache/user_project_languages_count_service.rb new file mode 100644 index 00000000..35b8a418 --- /dev/null +++ b/app/services/cache/user_project_languages_count_service.rb @@ -0,0 +1,60 @@ +class Cache::UserProjectLanguagesCountService < ApplicationService + attr_reader :user, :key, :increment_count + + def initialize(user, key=nil, increment_count=0) + @user = user + @key = key + @increment_count = increment_count + end + + def call + set_user_project_language_count + + user_project_language_count + end + + def reset_by_key + reset_user_project_language_count_by_key + + user_project_language_count + end + + def reset + reset_user_project_language_count + + user_project_language_count + end + + private + + def user_project_language_count_key + "user-project-language-count-#{user.id}" + end + + def user_project_language_count + $redis_cache.hgetall(user_project_language_count_key).transform_values(&:to_i) + end + + def set_user_project_language_count + if $redis_cache.hlen(user_project_language_count_key) == 0 + reset_user_project_language_count + elsif $redis_cache.hget(user_project_language_count_key, key).nil? + reset_user_project_language_count_by_key + else + $redis_cache.hincrby(user_project_language_count_key, key, increment_count) + end + end + + def reset_user_project_language_count_by_key + return if user.nil? + return if key.nil? + $redis_cache.hset(user_project_language_count_key, key, user.projects.joins(:project_language).where(project_languages: {name: key}).count) + end + + def reset_user_project_language_count + return if user.nil? + user.projects.joins(:project_language).group("project_languages.name").count.each do |k, v| + $redis_cache.hset(user_project_language_count_key, k, v) + end + end +end \ No newline at end of file diff --git a/app/services/cache/user_project_praises_count_service.rb b/app/services/cache/user_project_praises_count_service.rb new file mode 100644 index 00000000..0c7d49e3 --- /dev/null +++ b/app/services/cache/user_project_praises_count_service.rb @@ -0,0 +1,43 @@ +class Cache::UserProjectPraisesCountService < ApplicationService + attr_reader :user, :increment_count + + def initialize(user, increment_count=0) + @user = user + @increment_count = increment_count + end + + def call + set_user_project_praises_count + + user_project_praises_count + end + + def reset + reset_user_project_praises_count + + user_project_praises_count + end + + private + + def user_project_praises_count_key + "user-project-praises-count-#{user.id}" + end + + def user_project_praises_count + $redis_cache.get(user_project_praises_count_key).to_i + end + + def set_user_project_praises_count + if $redis_cache.exists(user_project_praises_count_key) + $redis_cache.incrby(user_project_praises_count_key, increment_count) + else + reset_user_project_praises_count + end + end + + def reset_user_project_praises_count + return if user.nil? + $redis_cache.set(user_project_praises_count_key, PraiseTread.where(praise_tread_object_type: 'Project', praise_tread_object_id: user.projects).count) + end +end \ No newline at end of file diff --git a/app/services/cache/user_project_watchers_count_service.rb b/app/services/cache/user_project_watchers_count_service.rb new file mode 100644 index 00000000..50733cad --- /dev/null +++ b/app/services/cache/user_project_watchers_count_service.rb @@ -0,0 +1,43 @@ +class Cache::UserProjectWatchersCountService < ApplicationService + attr_reader :user, :increment_count + + def initialize(user, increment_count=0) + @user = user + @increment_count = increment_count + end + + def call + set_user_project_watchers_count + + user_project_watchers_count + end + + def reset + reset_user_project_watchers_count + + user_project_watchers_count + end + + private + + def user_project_watchers_count_key + "user-project-watchers-count-#{user.id}" + end + + def user_project_watchers_count + $redis_cache.get(user_project_watchers_count_key).to_i + end + + def set_user_project_watchers_count + if $redis_cache.exists(user_project_watchers_count_key) + $redis_cache.incrby(user_project_watchers_count_key, increment_count) + else + reset_user_project_watchers_count + end + end + + def reset_user_project_watchers_count + return if user.nil? + $redis_cache.set(user_project_watchers_count_key, Watcher.where(watchable_type: 'Project', watchable_id: user.projects).count) + end +end \ No newline at end of file diff --git a/app/services/cache/user_pullrequest_count_service.rb b/app/services/cache/user_pullrequest_count_service.rb new file mode 100644 index 00000000..da478b2a --- /dev/null +++ b/app/services/cache/user_pullrequest_count_service.rb @@ -0,0 +1,43 @@ +class Cache::UserPullrequestCountService < ApplicationService + attr_reader :user, :increment_count + + def initialize(user, increment_count=0) + @user = user + @increment_count = increment_count + end + + def call + set_user_pullrequest_count + + user_pullrequest_count + end + + def reset + reset_user_pullrequest_count + + user_pullrequest_count + end + + private + + def user_pullrequest_count_key + "user-pullrequest-count-#{user.id}" + end + + def user_pullrequest_count + $redis_cache.get(user_pullrequest_count_key).to_i + end + + def set_user_pullrequest_count + if $redis_cache.exists(user_pullrequest_count_key) + $redis_cache.incrby(user_pullrequest_count_key, increment_count) + else + reset_user_pullrequest_count + end + end + + def reset_user_pullrequest_count + return if user.nil? + $redis_cache.set(user_pullrequest_count_key, PullRequest.where(user_id: user.id).count) + end +end \ No newline at end of file diff --git a/app/services/gitea/accelerator/base_service.rb b/app/services/gitea/accelerator/base_service.rb new file mode 100644 index 00000000..e63d77aa --- /dev/null +++ b/app/services/gitea/accelerator/base_service.rb @@ -0,0 +1,96 @@ +class Gitea::Accelerator::BaseService < ApplicationService + + def post(url, params) + puts "[gitea] request params: #{params}" + puts "[gitea] access_username: #{access_username}" + puts "[gitea] access_password: #{access_password}" + conn.post do |req| + req.url full_url(url) + req.body = params.to_json + end + end + + private + def conn + @client ||= begin + Faraday.new(url: domain) do |req| + req.request :url_encoded + req.headers['Content-Type'] = 'application/json' + req.response :logger # 显示日志 + req.adapter Faraday.default_adapter + req.basic_auth(access_username, access_password) + end + end + @client + end + + def base_url + accelerator["base_url"] + end + + def domain + accelerator["domain"] + end + + def api_url + [domain, base_url].join('') + end + + def full_url(api_rest, action='post') + url = [api_url, api_rest].join('').freeze + url = action === 'get' ? url : URI.escape(url) + puts "[gitea] request url: #{url}" + url + end + + def access_username + accelerator["access_key_id"] + end + + def access_password + accelerator["access_key_secret"] + end + + def access_uid + accelerator["access_admin_uid"] + end + + def accelerator + Gitea.gitea_config[:accelerator] + end + + def render_status(response) + puts "[gitea] response status: #{response.status}" + puts "[gitea] response body: #{response.body}" + case response.status + when 201 + success + when 403 + error('APIForbiddenError') + when 422 + error('APIValidationError') + else + error("MigrateError") + end + end + + def error(message) + { + status: :error, + message: message, + data: nil + } + end + + def success(data=nil) + { + status: :success, + message: nil, + data: data + } + end + + def check_accelerator! + accelerator.blank? || access_username.blank? || access_password.blank? || domain.blank? + end +end \ No newline at end of file diff --git a/app/services/gitea/accelerator/migrate_service.rb b/app/services/gitea/accelerator/migrate_service.rb index 015a09b1..26541b48 100644 --- a/app/services/gitea/accelerator/migrate_service.rb +++ b/app/services/gitea/accelerator/migrate_service.rb @@ -1,4 +1,4 @@ -class Gitea::Accelerator::MigrateService < ApplicationService +class Gitea::Accelerator::MigrateService < Gitea::Accelerator::BaseService attr_reader :params # params description: @@ -36,8 +36,8 @@ class Gitea::Accelerator::MigrateService < ApplicationService render_status(response) end - private + private def request_params { uid: access_uid, @@ -52,97 +52,4 @@ class Gitea::Accelerator::MigrateService < ApplicationService def url "/repos/migrate".freeze end - - def post(url, params) - puts "[gitea] request params: #{params}" - puts "[gitea] access_username: #{access_username}" - puts "[gitea] access_password: #{access_password}" - conn.post do |req| - req.url full_url(url) - req.body = params.to_json - end - end - - def conn - @client ||= begin - Faraday.new(url: domain) do |req| - req.request :url_encoded - req.headers['Content-Type'] = 'application/json' - req.response :logger # 显示日志 - req.adapter Faraday.default_adapter - req.basic_auth(access_username, access_password) - end - end - @client - end - - def base_url - accelerator["base_url"] - end - - def domain - accelerator["domain"] - end - - def api_url - [domain, base_url].join('') - end - - def full_url(api_rest, action='post') - url = [api_url, api_rest].join('').freeze - url = action === 'get' ? url : URI.escape(url) - puts "[gitea] request url: #{url}" - url - end - - def access_username - accelerator["access_key_id"] - end - - def access_password - accelerator["access_key_secret"] - end - - def access_uid - accelerator["access_admin_uid"] - end - - def accelerator - Gitea.gitea_config[:accelerator] - end - - def render_status(response) - puts "[gitea] response status: #{response.status}" - puts "[gitea] response body: #{response.body}" - case response.status - when 201 - success - when 403 - error('APIForbiddenError') - when 422 - error('APIValidationError') - else - error("MigrateError") - end - end - - def error(message) - { - status: :error, - message: message, - data: nil - } - end - - def success(data=nil) - { - status: :success, - message: nil, - data: data - } - end - - def check_accelerator! - accelerator.blank? || access_username.blank? || access_password.blank? || domain.blank? - end end \ No newline at end of file diff --git a/app/services/gitea/accelerator/sync_mirrored_service.rb b/app/services/gitea/accelerator/sync_mirrored_service.rb new file mode 100644 index 00000000..0e0a7ca9 --- /dev/null +++ b/app/services/gitea/accelerator/sync_mirrored_service.rb @@ -0,0 +1,31 @@ +# Sync a mirrored repository +class Gitea::Accelerator::SyncMirroredService < Gitea::Accelerator::BaseService + attr_reader :repo, :token + + # repo * + # name of the repo to sync + # example: + # Gitea::Accelerator::SyncMirroredService.call(repo.identifier) + def initialize(repo, token=nil) + @repo = repo + @token = token + end + + def call + return error('[gitea:] accelerator config missing') if check_accelerator! + + response = post(url, request_params) + + {status: response.status} + end + + private + + def request_params + Hash.new.merge(token: token).compact + end + + def url + "/repos/#{access_username}/#{repo}/mirror-sync".freeze + end +end diff --git a/app/services/gitea/user/headmap_service.rb b/app/services/gitea/user/headmap_service.rb new file mode 100644 index 00000000..611a8b9d --- /dev/null +++ b/app/services/gitea/user/headmap_service.rb @@ -0,0 +1,23 @@ +class Gitea::User::HeadmapService < Gitea::ClientService + attr_reader :start_time, :end_time, :username + + def initialize(username, start_time, end_time) + @username = username + @start_time = start_time + @end_time = end_time + end + + def call + response = get(url, params) + render_response(response) + end + + private + def params + Hash.new.merge(start: start_time, end: end_time) + end + + def url + "/users/#{username}/heatmap".freeze + end +end \ No newline at end of file diff --git a/app/services/projects/accept_join_service.rb b/app/services/projects/accept_join_service.rb new file mode 100644 index 00000000..69cb9760 --- /dev/null +++ b/app/services/projects/accept_join_service.rb @@ -0,0 +1,61 @@ +class Projects::AcceptJoinService < ApplicationService + attr_accessor :applied_project, :owner + attr_reader :user, :project + + def initialize(user, applied_project) + @user = user + @project = applied_project.project + @applied_project = applied_project + end + + def call + Rails.logger.info("###### Project accept_join_service begin ######") + ActiveRecord::Base.transaction do + validate! + update_apply + operate_project_member + send_apply_message + end + + Rails.logger.info("##### Project accept_join_service end ######") + + + return @applied_project + end + + private + def permission + case @applied_project.role + when 'manager' + 'admin' + when 'developer' + 'write' + when 'reporter' + 'read' + else + 'read' + end + end + + def validate! + raise Error, '该申请已经被接受' if @applied_project.accepted? + raise Error, '该申请不存在' unless @applied_project.present? + raise Error, '未拥有接受申请权限' unless is_permit_operator + end + + def is_permit_operator + return @user.admin? || @project.manager?(@user) + end + + def update_apply + @applied_project.update!(status: 'accepted') + end + + def operate_project_member + Projects::AddMemberInteractor.call(@project.owner, @project, @applied_project.user, permission) + end + + def send_apply_message + SendJoinProjectAppliedMessageJob.perform_now(@applied_project, @user, 'successed') + end +end \ No newline at end of file diff --git a/app/services/projects/apply_join_service.rb b/app/services/projects/apply_join_service.rb index 0b57712d..2366a26d 100644 --- a/app/services/projects/apply_join_service.rb +++ b/app/services/projects/apply_join_service.rb @@ -9,32 +9,31 @@ class Projects::ApplyJoinService < ApplicationService end def call - validate! # 项目报告人员直接加入项目 - if params[:role] == 'reporter' - # Projects::JoinService.call(project, user, role: 'reporter') - return project - end + # if params[:role] == 'reporter' + # # Projects::JoinService.call(project, user, role: 'reporter') + # return project + # end ActiveRecord::Base.transaction do + validate! apply = user.applied_projects.create!(project: project, role: role_value) + apply + # apply.forge_activities.find_or_create_by!(user: user, project: project) - apply.forge_activities.find_or_create_by!(user: user, project: project) - - notify_project_manager!(apply) + # notify_project_manager!(apply) end # notify_project_owner - ApplyJoinProjectNotifyJob.perform_later(user.id, project.id, role_value) + # ApplyJoinProjectNotifyJob.perform_later(user.id, project.id, role_value) - project end private def project - @_project ||= Project.find_by(invite_code: params[:code].to_s.strip) + @_project ||= Project.find_by('binary(invite_code) = ? ',"#{params[:code].to_s.strip}") end def role_value @@ -43,7 +42,8 @@ class Projects::ApplyJoinService < ApplicationService when 'manager' then 3 when 'developer' then 4 when 'reporter' then 5 - else raise Error, '角色无效' + else + 5 end end @@ -74,12 +74,18 @@ class Projects::ApplyJoinService < ApplicationService def validate! # params check raise Error, '邀请码不能为空' if params[:code].blank? - raise Error, '角色不能为空' if params[:role].blank? - raise Error, '角色无效' unless %w(manager developer reporter).include?(params[:role]) + raise Error, '请输入6位项目邀请码' unless valid_invite_code( params[:code]) # logical check raise Error, '邀请码无效' if project.blank? - raise Error, '您已在该项目中' if project.member?(user) - raise Error, '您已经提交过申请' if user.applied_projects.pending.exists?(project: project) + raise Error, '您已是项目成员' if project.member?(user) + raise Error, '您已经提交过申请' if user.applied_projects.common.exists?(project: project) + end + + def valid_invite_code(str) + if (str =~ /^[A-Za-z0-9]{6}+$/) + return true + end + return false end end \ No newline at end of file diff --git a/app/services/projects/refuse_join_service.rb b/app/services/projects/refuse_join_service.rb new file mode 100644 index 00000000..f9452586 --- /dev/null +++ b/app/services/projects/refuse_join_service.rb @@ -0,0 +1,39 @@ +class Projects::RefuseJoinService < ApplicationService + attr_accessor :applied_project, :owner + attr_reader :user, :project + + def initialize(user, applied_project) + @user = user + @project = applied_project.project + @applied_project = applied_project + end + + def call + Rails.logger.info("###### Project refuse_join_service begin ######") + validate! + update_apply + send_apply_message + Rails.logger.info("###### Project refuse_join_service end ######") + + return @applied_project + end + + private + def validate! + raise Error, '该申请已被拒绝' if @applied_project.refused? + raise Error, '该申请不存在' unless @applied_project.present? + raise Error, '未拥有接受申请权限' unless is_permit_operator + end + + def is_permit_operator + return @user.admin? || @project.manager?(@user) + end + + def update_apply + @applied_project.update!(status: 'refused') + end + + def send_apply_message + SendJoinProjectAppliedMessageJob.perform_now(@applied_project, @user, 'failure') + end +end \ No newline at end of file diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb index a2da34f0..0b4f1d99 100644 --- a/app/services/projects/transfer_service.rb +++ b/app/services/projects/transfer_service.rb @@ -34,7 +34,7 @@ class Projects::TransferService < ApplicationService def update_visit_teams if new_owner.is_a?(Organization) # 为包含组织所有项目的团队创建项目访问权限 - new_owner.build_permit_team_projects(project.id) + new_owner.build_permit_team_projects!(project.id) else project.team_projects.each(&:destroy!) end diff --git a/app/views/admins/shared/_sidebar.html.erb b/app/views/admins/shared/_sidebar.html.erb index ad53c661..82553d9a 100644 --- a/app/views/admins/shared/_sidebar.html.erb +++ b/app/views/admins/shared/_sidebar.html.erb @@ -42,8 +42,11 @@ <% end %>
  • - <%= sidebar_item('/admins/sidekiq', '定时任务', icon: 'bell', controller: 'root') %> + <%= sidebar_item('/admins/sidekiq', '定时任务', icon: 'bell', controller: 'root') %>
  • + + <%= render_admin_statistics_item %> +
  • <%= sidebar_item('/', '返回主站', icon: 'sign-out', controller: 'root') %>
  • diff --git a/app/views/applied_projects/_detail.json.jbuilder b/app/views/applied_projects/_detail.json.jbuilder new file mode 100644 index 00000000..e76875dc --- /dev/null +++ b/app/views/applied_projects/_detail.json.jbuilder @@ -0,0 +1,19 @@ +project = object.project +json.project do + json.id project.id + json.identifier project.identifier + json.name project.name + json.description project.description + json.is_public project.is_public + json.owner do + json.partial! "/users/user_simple", locals: {user: project.owner} + end +end +json.user do + json.partial! "/users/user_simple", locals: {user: object.user} +end +json.id object.id +json.status object.status +json.role object.role +json.created_at format_time(object.created_at) +json.time_ago time_from_now(object.created_at) diff --git a/app/views/applied_projects/create.json.jbuilder b/app/views/applied_projects/create.json.jbuilder new file mode 100644 index 00000000..e2512880 --- /dev/null +++ b/app/views/applied_projects/create.json.jbuilder @@ -0,0 +1 @@ +json.partial! "detail", locals: {object: @applied_project} diff --git a/app/views/issues/_simple_issue_item.json.jbuilder b/app/views/issues/_simple_issue_item.json.jbuilder index f711253a..d21c9fca 100644 --- a/app/views/issues/_simple_issue_item.json.jbuilder +++ b/app/views/issues/_simple_issue_item.json.jbuilder @@ -1,4 +1,10 @@ json.name issue.try(:subject) +json.issue_type issue.issue_type == "1" ? "普通" : "悬赏" +json.status_id issue.try(:status_id) +json.issue_status issue.issue_status.try(:name) +json.priority issue.priority.try(:name) +json.priority_id issue.try(:priority_id) +json.version issue.version.try(:name) json.created_at format_time(issue.try(:created_on)) json.updated_at format_time(issue.try(:updated_on)) json.assign_user_name issue&.get_assign_user.try(:show_real_name) diff --git a/app/views/project_trends/_detail.json.jbuilder b/app/views/project_trends/_detail.json.jbuilder new file mode 100644 index 00000000..75bcf223 --- /dev/null +++ b/app/views/project_trends/_detail.json.jbuilder @@ -0,0 +1,17 @@ +json.id trend.id +json.trend_type trend.trend_type +json.action_type l("trend.#{trend.action_type}") + l("trend.#{trend.trend_type}") +json.trend_id trend.trend_id +json.user_name trend.user.try(:show_real_name) +json.user_login trend.user.login +json.user_avatar url_to_avatar(trend.user) +json.action_time time_from_now(trend.created_at) + +if trend.trend_type == "Issue" + json.partial! "issues/simple_issue_item", locals: {issue: trend.trend} +elsif trend.trend_type == "VersionRelease" + json.partial! "version_releases/simple_version_release", locals: {version: trend.trend} +else + json.name trend.trend&.title + json.created_at format_time(trend.trend&.created_at) +end diff --git a/app/views/project_trends/index.json.jbuilder b/app/views/project_trends/index.json.jbuilder index 159a3bdb..6dca7bdb 100644 --- a/app/views/project_trends/index.json.jbuilder +++ b/app/views/project_trends/index.json.jbuilder @@ -9,25 +9,9 @@ json.limit @limit json.project_trends_size @project_trends_size json.project_trends do json.array! @project_trends.to_a.each do |trend| - json.id trend.id - json.trend_type trend.trend_type - json.action_type l("trend.#{trend.action_type}") + l("trend.#{trend.trend_type}") - json.trend_id trend.trend_id - json.user_name trend.user.try(:show_real_name) - json.user_login trend.user.login - json.user_avatar url_to_avatar(trend.user) - - if trend.trend_type == "Issue" - json.partial! "issues/simple_issue_item", locals: {issue: trend.trend} - elsif trend.trend_type == "VersionRelease" - json.partial! "version_releases/simple_version_release", locals: {version: trend.trend} - else - json.name trend.trend.title - json.created_at format_time(trend.trend.created_at) - end - + #后续需要天际pullrequest 和 版本的内容 - + json.partial! "detail", trend: trend end end diff --git a/app/views/projects/_project_detail.json.jbuilder b/app/views/projects/_project_detail.json.jbuilder index d0b62aaa..c9e03fa2 100644 --- a/app/views/projects/_project_detail.json.jbuilder +++ b/app/views/projects/_project_detail.json.jbuilder @@ -5,6 +5,9 @@ json.name project.name json.description Nokogiri::HTML(project.description).text json.visits project.visits json.praises_count project.praises_count.to_i +json.watchers_count project.watchers_count.to_i +json.issues_count project.issues_count.to_i +json.pull_requests_count project.pull_requests_count.to_i json.forked_count project.forked_count.to_i json.is_public project.is_public json.mirror_url project.repository&.mirror_url @@ -14,6 +17,7 @@ json.time_ago time_from_now(project.updated_on) json.forked_from_project_id project.forked_from_project_id json.open_devops project.open_devops? json.platform project.platform +json.is_pinned project.has_pinned_users.include?(current_user) json.author do if project.educoder? project_educoder = project.project_educoder diff --git a/app/views/repositories/detail.json.jbuilder b/app/views/repositories/detail.json.jbuilder index 39f2563a..d51b19fd 100644 --- a/app/views/repositories/detail.json.jbuilder +++ b/app/views/repositories/detail.json.jbuilder @@ -7,12 +7,13 @@ else json.readme @result[:readme].merge(content: readme_render_decode64_content(@result[:readme]["content"], nil)) end json.identifier render_identifier(@project) +json.invite_code @project.invite_code json.name @project.name json.description @project.description json.project_id @project.id json.repo_id @repository.id json.issues_count @project.issues_count.to_i - @project.pull_requests_count.to_i -json.pull_requests_count @project.pull_requests_count +json.pull_requests_count @project.pull_requests_count json.project_identifier render_identifier(@project) json.praises_count @project.praises_count.to_i json.forked_count @project.forked_count.to_i @@ -48,7 +49,7 @@ if @result[:repo] json.size replace_bytes_to_b(number_to_human_size(@result[:repo]['size'].to_i*1024)) json.ssh_url @result[:repo]['ssh_url'] json.clone_url @result[:repo]['clone_url'] - json.default_branch @result[:repo]['default_branch'] + json.default_branch @project.educoder? ? "master" : @result[:repo]['default_branch'] json.empty @result[:repo]['empty'] json.full_name @result[:repo]['full_name'] json.private @result[:repo]['private'] diff --git a/app/views/repositories/edit.json.jbuilder b/app/views/repositories/edit.json.jbuilder index 7a11411f..e0b601f6 100644 --- a/app/views/repositories/edit.json.jbuilder +++ b/app/views/repositories/edit.json.jbuilder @@ -12,4 +12,5 @@ json.permission render_permission(current_user, @project) json.is_transfering @project.is_transfering json.transfer do json.partial! "/users/user_simple", locals: {user: @project&.applied_transfer_project&.owner} -end \ No newline at end of file +end +json.is_pinned @project.has_pinned_users.include?(current_user) \ No newline at end of file diff --git a/app/views/users/_user.json.jbuilder b/app/views/users/_user.json.jbuilder index 96299c7e..dc43d6bc 100644 --- a/app/views/users/_user.json.jbuilder +++ b/app/views/users/_user.json.jbuilder @@ -1,7 +1,20 @@ json.user_id user.id -json.login user.login json.name user.full_name +json.username @user.full_name +json.real_name @user.real_name json.grade user.grade -json.identity user&.user_extension&.identity -# json.email user.mail # 邮箱原则上不暴露的,如果实在需要的话只能对某些具体的接口公开 -json.image_url url_to_avatar(user) +json.gender @user.gender +json.login @user.login +json.user_id @user.id +json.image_url url_to_avatar(@user) +json.admin @user.admin? +json.user_identity @user.identity +json.is_watch current_user&.watched?(@user) +json.watched_count @user.fan_count #粉丝 +json.watching_count @user.follow_count #关注数 +json.created_time format_time(@user.created_on) +json.email @user.show_email ? @user.mail : nil +json.province @user.show_location ? @user.province : nil +json.city @user.show_location ? @user.city : nil +json.custom_department @user.show_department ? @user.custom_department : nil +json.description @user.description \ No newline at end of file diff --git a/app/views/users/_watch_user_detail.json.jbuilder b/app/views/users/_watch_user_detail.json.jbuilder index 80a71162..8c4881bc 100644 --- a/app/views/users/_watch_user_detail.json.jbuilder +++ b/app/views/users/_watch_user_detail.json.jbuilder @@ -3,7 +3,7 @@ json.format_time target.created_at.strftime("%Y-%m-%d") json.name user.try(:show_real_name) json.login user.try(:login) json.image_url url_to_avatar(user) -json.is_current_user current_user.try(:id) == target.user_id +json.is_current_user current_user.try(:id) == user.id json.is_watch current_user&.watched?(user) diff --git a/app/views/users/applied_messages/_detail.json.jbuilder b/app/views/users/applied_messages/_detail.json.jbuilder index cca202c1..796d0387 100644 --- a/app/views/users/applied_messages/_detail.json.jbuilder +++ b/app/views/users/applied_messages/_detail.json.jbuilder @@ -13,7 +13,12 @@ # json.partial! "/users/user_simple", locals: {user: object.user} # end json.applied do - json.partial! "/projects/applied_transfer_projects/detail", locals: {object: object.applied} + case object.applied_type + when 'AppliedTransferProject' + json.partial! "/projects/applied_transfer_projects/detail", locals: {object: object.applied} + when 'AppliedProject' + json.partial! "/applied_projects/detail", locals: {object: object.applied} + end end json.applied_user do json.partial! "/users/user_simple", locals: {user: object.applied_user} diff --git a/app/views/users/applied_projects/accept.json.jbuilder b/app/views/users/applied_projects/accept.json.jbuilder new file mode 100644 index 00000000..d13d24be --- /dev/null +++ b/app/views/users/applied_projects/accept.json.jbuilder @@ -0,0 +1 @@ +json.partial! "/applied_projects/detail", locals: {object: @applied_project} diff --git a/app/views/users/applied_projects/index.json.jbuilder b/app/views/users/applied_projects/index.json.jbuilder new file mode 100644 index 00000000..6e1a1a02 --- /dev/null +++ b/app/views/users/applied_projects/index.json.jbuilder @@ -0,0 +1,4 @@ +json.total_count @applied_projects.total_count +json.applied_projects @applied_projects do |apply| + json.partial! "/applied_projects/detail", locals: {object: apply} +end diff --git a/app/views/users/applied_projects/refuse.json.jbuilder b/app/views/users/applied_projects/refuse.json.jbuilder new file mode 100644 index 00000000..d13d24be --- /dev/null +++ b/app/views/users/applied_projects/refuse.json.jbuilder @@ -0,0 +1 @@ +json.partial! "/applied_projects/detail", locals: {object: @applied_project} diff --git a/app/views/users/get_user_info.json.jbuilder b/app/views/users/get_user_info.json.jbuilder index 4e6b284b..b4ffd2af 100644 --- a/app/views/users/get_user_info.json.jbuilder +++ b/app/views/users/get_user_info.json.jbuilder @@ -1,5 +1,6 @@ json.username @user.full_name json.real_name @user.real_name +json.gender @user.gender json.login @user.login json.user_id @user.id json.image_url url_to_avatar(@user) @@ -16,3 +17,9 @@ json.profile_completed @user.profile_completed? json.professional_certification @user.professional_certification json.devops_step @user.devops_step json.ci_certification @user.ci_certification? +json.email @user.mail +json.province @user.province +json.city @user.city +json.custom_department @user.custom_department +json.description @user.description +json.(@user, :show_email, :show_department, :show_location) \ No newline at end of file diff --git a/app/views/users/headmaps/index.json.jbuilder b/app/views/users/headmaps/index.json.jbuilder new file mode 100644 index 00000000..0e6a540b --- /dev/null +++ b/app/views/users/headmaps/index.json.jbuilder @@ -0,0 +1,5 @@ +json.total_contributions @headmaps.collect{|map| map["contributions"]}.reduce(0, :+) +json.headmaps @headmaps.each do |map| + json.date Time.at(map["timestamp"].to_i).strftime("%Y-%m-%d") + json.contributions map["contributions"] +end diff --git a/app/views/users/is_pinned_projects/index.json.jbuilder b/app/views/users/is_pinned_projects/index.json.jbuilder new file mode 100644 index 00000000..7790607d --- /dev/null +++ b/app/views/users/is_pinned_projects/index.json.jbuilder @@ -0,0 +1,7 @@ +json.total_count @is_pinned_projects.total_count +json.projects @is_pinned_projects.each do |project| + json.partial! "projects/project_detail", project: project&.project + json.id project.id + json.position project.position + json.project_id project.project_id +end \ No newline at end of file diff --git a/app/views/users/project_trends/index.json.jbuilder b/app/views/users/project_trends/index.json.jbuilder new file mode 100644 index 00000000..d1aab139 --- /dev/null +++ b/app/views/users/project_trends/index.json.jbuilder @@ -0,0 +1,4 @@ +json.total_count @project_trends.total_count +json.project_trends @project_trends.each do |trend| + json.partial! "project_trends/detail", trend: trend +end \ No newline at end of file diff --git a/app/views/users/show.json.jbuilder b/app/views/users/show.json.jbuilder index e80ac749..1c9e7793 100644 --- a/app/views/users/show.json.jbuilder +++ b/app/views/users/show.json.jbuilder @@ -1,20 +1,16 @@ -# json.partial! 'users/user', locals: { user: @user } - -json.username @user.full_name -json.real_name @user.real_name -json.login @user.login -json.user_id @user.id -json.image_url url_to_avatar(@user) -json.admin @user.admin? -json.user_identity @user.identity -json.is_watch current_user&.watched?(@user) -json.watched_count @user.fan_count #粉丝 -json.watching_count @user.follow_count #关注数 +json.partial! 'users/user', locals: { user: @user } json.undo_messages @waiting_applied_messages.size json.undo_transfer_projects @common_applied_transfer_projects.size +json.undo_join_projects @common_applied_projects.size json.undo_events @undo_events json.user_composes_count @user_composes_count json.user_org_count @user_org_count json.common_projects_count @projects_common_count json.mirror_projects_count @projects_mirrior_count -json.sync_mirror_projects_count @projects_sync_mirrior_count \ No newline at end of file +json.sync_mirror_projects_count @projects_sync_mirrior_count +json.created_time format_time(@user.created_on) +json.email @user.show_email ? @user.mail : nil +json.province @user.show_location ? @user.province : nil +json.city @user.show_location ? @user.city : nil +json.custom_department @user.show_department ? @user.custom_department : nil +json.description @user.description \ No newline at end of file diff --git a/app/views/users/statistics/develop.json.jbuilder b/app/views/users/statistics/develop.json.jbuilder new file mode 100644 index 00000000..85f66f5c --- /dev/null +++ b/app/views/users/statistics/develop.json.jbuilder @@ -0,0 +1,19 @@ +json.platform do + json.influence @platform_influence + json.contribution @platform_contribution + json.activity @platform_activity + json.experience @platform_experience + json.language @platform_language + # json.languages_percent @platform_languages_percent + # json.each_language_score @platform_each_language_score +end + +json.user do + json.influence @influence + json.contribution @contribution + json.activity @activity + json.experience @experience + json.language @language + json.languages_percent @languages_percent + json.each_language_score @each_language_score +end \ No newline at end of file diff --git a/app/views/users/statistics/role.json.jbuilder b/app/views/users/statistics/role.json.jbuilder new file mode 100644 index 00000000..5ca29058 --- /dev/null +++ b/app/views/users/statistics/role.json.jbuilder @@ -0,0 +1,19 @@ +json.total_projects_count @full_member_projects_count +json.role do + json.owner do + json.count @owner_projects_count + json.percent (@owner_projects_count.to_f/@full_member_projects_count).round(2) + end + json.manager do + json.count @manager_projects_count + json.percent (@manager_projects_count.to_f/@full_member_projects_count).round(2) + end + json.developer do + json.count @developer_projects_count + json.percent (@developer_projects_count.to_f/@full_member_projects_count).round(2) + end + json.reporter do + json.count @reporter_projects_count + json.percent (@reporter_projects_count.to_f/@full_member_projects_count).round(2) + end +end \ No newline at end of file diff --git a/app/views/users/update.json.jbuilder b/app/views/users/update.json.jbuilder new file mode 100644 index 00000000..2b31e182 --- /dev/null +++ b/app/views/users/update.json.jbuilder @@ -0,0 +1 @@ +json.partial! 'users/user', locals: { user: @user } diff --git a/app/views/users/watch_users.json.jbuilder b/app/views/users/watch_users.json.jbuilder index b265e2e0..ed2697f0 100644 --- a/app/views/users/watch_users.json.jbuilder +++ b/app/views/users/watch_users.json.jbuilder @@ -1,7 +1,7 @@ json.count @watchers_count json.users do json.array! @watchers do |watcher| - json.partial! "/users/watch_user_detail", locals: {target: watcher, user: watcher.watchable} + json.partial! "/users/watch_user_detail", target: watcher, user: watcher.watchable end # json.partial! "/users/watch_user_detail", collection: @watchers, as: :target end \ No newline at end of file diff --git a/config/initializers/redis_cache.rb b/config/initializers/redis_cache.rb new file mode 100644 index 00000000..67f52ec7 --- /dev/null +++ b/config/initializers/redis_cache.rb @@ -0,0 +1,3 @@ +redis_config = Rails.application.config_for(:redis) +cache_url = redis_config["url"] || 'redis://localhost:6379' +$redis_cache = Redis.new(url: cache_url, db: 2) \ No newline at end of file diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index c040f9bd..db103016 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -15,7 +15,7 @@ zh-CN: 'refused': '已拒绝' 'agreed': '已同意' trend: - Issue: 工单 + Issue: 易修(Issue) PullRequest: 合并请求 VersionRelease: 版本发布 create: 创建了 diff --git a/config/routes.rb b/config/routes.rb index 951472eb..78745320 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -148,6 +148,8 @@ Rails.application.routes.draw do resources :issue_depends, only: [:create, :destroy] end + resources :applied_projects, only: [:create] + resources :project_categories, only: [:index, :show] do get :group_list, on: :collection end @@ -191,6 +193,7 @@ Rails.application.routes.draw do post :remote_update post :remote_login post :remote_password + post :change_password end end @@ -267,6 +270,27 @@ Rails.application.routes.draw do post :refuse end end + resources :applied_projects, only: [:index] do + member do + post :accept + post :refuse + end + end + resources :headmaps, only: [:index] + resources :is_pinned_projects, only: [:index, :update] do + collection do + post :pin + end + end + resources :statistics, only: [:index] do + collection do + get :activity + get :develop + get :role + get :major + end + end + resources :project_trends, only: [:index] resources :organizations, only: [:index] # resources :projects, only: [:index] # resources :subjects, only: [:index] diff --git a/config/sidekiq.yml b/config/sidekiq.yml index dda6a32e..a50c1c1a 100644 --- a/config/sidekiq.yml +++ b/config/sidekiq.yml @@ -7,3 +7,4 @@ - [searchkick, 10] - [notify, 100] - [mailers, 101] + - [cache, 10] diff --git a/db/init_data.sql b/db/init_data.sql new file mode 100644 index 00000000..33288736 --- /dev/null +++ b/db/init_data.sql @@ -0,0 +1,95 @@ + +-- ---------------------------- +-- Records of roles +-- ---------------------------- +BEGIN; +INSERT INTO `roles` (`id`, `name`, `position`, `assignable`, `builtin`, `permissions`, `issues_visibility`) VALUES +(1, 'Non member', 1, 1, 1, '---\n- :upload_attachments\n- :memos_attachments_download\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :course_attachments_download\n- :view_course_files\n- :add_messages\n- :delete_own_messages\n- :view_calendar\n- :view_documents\n- :view_files\n- :view_gantt\n- :view_issues\n- :save_queries\n- :comment_news\n- :browse_repository\n- :view_changesets\n- :view_time_entries\n- :view_wiki_pages\n- :view_wiki_edits\n', 'default'), +(2, 'Anonymous', 2, 1, 2, '---\n- :memos_attachments_download\n- :view_course_files\n- :view_calendar\n- :view_documents\n- :view_files\n- :view_gantt\n- :view_issues\n- :browse_repository\n- :view_changesets\n- :view_time_entries\n- :view_wiki_pages\n- :view_wiki_edits\n', 'default'), +(3, 'Manager', 3, 1, 0, '---\n- :add_project\n- :edit_project\n- :close_project\n- :select_project_modules\n- :manage_members\n- :manage_versions\n- :add_subprojects\n- :is_manager\n- :projects_attachments_download\n- :as_teacher\n- :add_course\n- :edit_course\n- :close_course\n- :select_course_modules\n- :view_course_journals_for_messages\n- :course_attachments_download\n- :view_course_files\n- :view_homework_attaches\n- :quote_project\n- :manage_boards\n- :add_messages\n- :edit_messages\n- :edit_own_messages\n- :delete_messages\n- :delete_own_messages\n- :view_calendar\n- :view_code_review\n- :add_code_review\n- :edit_code_review\n- :delete_code_review\n- :assign_code_review\n- :code_review_setting\n- :add_documents\n- :edit_documents\n- :delete_documents\n- :view_documents\n- :manage_files\n- :view_files\n- :view_gantt\n- :manage_categories\n- :view_issues\n- :add_issues\n- :edit_issues\n- :manage_issue_relations\n- :manage_subtasks\n- :set_issues_private\n- :set_own_issues_private\n- :add_issue_notes\n- :edit_issue_notes\n- :edit_own_issue_notes\n- :view_private_notes\n- :set_notes_private\n- :move_issues\n- :delete_issues\n- :manage_public_queries\n- :save_queries\n- :view_issue_watchers\n- :add_issue_watchers\n- :delete_issue_watchers\n- :manage_news\n- :comment_news\n- :manage_repository\n- :browse_repository\n- :view_changesets\n- :commit_access\n- :manage_related_issues\n- :log_time\n- :view_time_entries\n- :edit_time_entries\n- :edit_own_time_entries\n- :manage_project_activities\n- :manage_wiki\n- :rename_wiki_pages\n- :delete_wiki_pages\n- :view_wiki_pages\n- :export_wiki_pages\n- :view_wiki_edits\n- :edit_wiki_pages\n- :delete_wiki_pages_attachments\n- :protect_wiki_pages\n', 'all'), +(4, 'Developer', 5, 1, 0, '---\n- :add_project\n- :manage_versions\n- :projects_attachments_download\n- :add_course\n- :edit_course\n- :close_course\n- :select_course_modules\n- :view_course_journals_for_messages\n- :course_attachments_download\n- :view_course_files\n- :view_homework_attaches\n- :paret_in_homework\n- :select_contest_modules\n- :quote_project\n- :contest_attachments_download\n- :manage_contestnotifications\n- :notificationcomment_contestnotifications\n- :manage_boards\n- :add_messages\n- :edit_own_messages\n- :delete_own_messages\n- :view_calendar\n- :manage_files\n- :view_files\n- :view_gantt\n- :manage_categories\n- :view_issues\n- :add_issues\n- :edit_issues\n- :manage_issue_relations\n- :manage_subtasks\n- :set_issues_private\n- :set_own_issues_private\n- :add_issue_notes\n- :edit_issue_notes\n- :edit_own_issue_notes\n- :view_private_notes\n- :set_notes_private\n- :move_issues\n- :delete_issues\n- :manage_public_queries\n- :save_queries\n- :view_issue_watchers\n- :add_issue_watchers\n- :delete_issue_watchers\n- :manage_repository\n- :browse_repository\n- :view_changesets\n- :commit_access\n- :manage_related_issues\n', 'all'), +(5, 'Reporter', 4, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :edit_course\n- :close_course\n- :select_course_modules\n- :view_course_journals_for_messages\n- :course_attachments_download\n- :view_course_files\n- :view_homework_attaches\n- :manage_boards\n- :add_messages\n- :edit_own_messages\n- :delete_own_messages\n- :view_calendar\n- :view_code_review\n- :manage_files\n- :view_files\n- :view_gantt\n- :view_issues\n- :add_issues\n- :edit_issues\n- :add_issue_notes\n- :edit_own_issue_notes\n- :save_queries\n- :comment_news\n- :browse_repository\n- :view_wiki_pages\n- :export_wiki_pages\n- :view_wiki_edits\n- :edit_wiki_pages\n- :delete_wiki_pages_attachments\n', 'all'), +(7, 'TeachingAsistant', 6, 1, 0, '---\n- :add_project\n- :edit_project\n- :manage_members\n- :projects_attachments_download\n- :as_teacher\n- :add_course\n- :edit_course\n- :close_course\n- :select_course_modules\n- :view_course_journals_for_messages\n- :course_attachments_download\n- :view_course_files\n- :view_homework_attaches\n- :manage_boards\n- :add_messages\n- :edit_own_messages\n- :delete_messages\n- :delete_own_messages\n- :view_calendar\n- :view_documents\n- :manage_files\n- :view_files\n- :view_gantt\n- :view_issues\n- :add_issues\n- :add_issue_notes\n- :save_queries\n- :manage_news\n- :comment_news\n- :browse_repository\n- :view_changesets\n- :view_time_entries\n- :view_wiki_pages\n- :export_wiki_pages\n- :view_wiki_edits\n- :edit_wiki_pages\n- :delete_wiki_pages_attachments\n', 'default'), +(9, 'Teacher', 7, 1, 0, '---\n- :upload_attachments\n- :memos_attachments_download\n- :add_project\n- :edit_project\n- :close_project\n- :select_project_modules\n- :manage_members\n- :manage_versions\n- :add_subprojects\n- :projects_attachments_download\n- :as_teacher\n- :add_course\n- :edit_course\n- :close_course\n- :select_course_modules\n- :view_course_journals_for_messages\n- :course_attachments_download\n- :view_course_files\n- :view_homework_attaches\n- :manage_boards\n- :add_messages\n- :edit_messages\n- :edit_own_messages\n- :delete_messages\n- :delete_own_messages\n- :view_calendar\n- :add_documents\n- :edit_documents\n- :delete_documents\n- :view_documents\n- :manage_files\n- :view_files\n- :view_gantt\n- :manage_categories\n- :view_issues\n- :add_issues\n- :edit_issues\n- :manage_issue_relations\n- :manage_subtasks\n- :set_issues_private\n- :set_own_issues_private\n- :add_issue_notes\n- :edit_own_issue_notes\n- :view_private_notes\n- :set_notes_private\n- :move_issues\n- :delete_issues\n- :manage_public_queries\n- :save_queries\n- :view_issue_watchers\n- :add_issue_watchers\n- :delete_issue_watchers\n- :manage_news\n- :comment_news\n- :manage_repository\n- :browse_repository\n- :view_changesets\n- :commit_access\n- :manage_related_issues\n- :log_time\n- :view_time_entries\n- :edit_time_entries\n- :edit_own_time_entries\n- :manage_project_activities\n- :manage_wiki\n- :rename_wiki_pages\n- :delete_wiki_pages\n- :view_wiki_pages\n- :export_wiki_pages\n- :view_wiki_edits\n- :edit_wiki_pages\n- :delete_wiki_pages_attachments\n- :protect_wiki_pages\n', 'default'), +(10, 'Student', 9, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :as_student\n- :add_course\n- :edit_course\n- :close_course\n- :select_course_modules\n- :view_course_journals_for_messages\n- :course_attachments_download\n- :view_course_files\n- :view_homework_attaches\n- :paret_in_homework\n- :manage_boards\n- :add_messages\n- :edit_own_messages\n- :delete_own_messages\n- :view_calendar\n- :view_documents\n- :manage_files\n- :view_files\n- :view_gantt\n- :view_issues\n- :add_issues\n- :add_issue_notes\n- :save_queries\n- :comment_news\n- :browse_repository\n- :view_changesets\n- :view_time_entries\n- :view_wiki_pages\n- :view_wiki_edits\n', 'default'), +(11, 'orgManager', 8, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :course_attachments_download\n- :view_course_files\n- :add_messages\n- :delete_own_messages\n- :view_calendar\n- :view_documents\n- :view_files\n- :view_gantt\n- :view_issues\n- :save_queries\n- :comment_news\n- :browse_repository\n- :view_changesets\n- :view_time_entries\n- :view_wiki_pages\n- :view_wiki_edits\n', 'default'), +(12, 'orgMember', 10, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :course_attachments_download\n- :view_course_files\n- :add_messages\n- :delete_own_messages\n- :view_calendar\n- :view_documents\n- :view_files\n- :view_gantt\n- :view_issues\n- :save_queries\n- :comment_news\n- :browse_repository\n- :view_changesets\n- :view_time_entries\n- :view_wiki_pages\n- :view_wiki_edits\n', 'default'), +(13, 'ContestManager', 11, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :course_attachments_download\n- :view_course_files\n- :select_contest_modules\n- :quote_project\n- :contest_attachments_download\n- :manage_contestnotifications\n- :notificationcomment_contestnotifications\n- :manage_boards\n- :add_messages\n- :edit_messages\n- :edit_own_messages\n- :delete_messages\n- :delete_own_messages\n- :view_calendar\n- :view_files\n- :view_gantt\n- :view_issues\n- :save_queries\n- :browse_repository\n- :view_changesets\n', 'default'), +(14, 'Judge', 12, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :course_attachments_download\n- :view_course_files\n- :select_contest_modules\n- :quote_project\n- :contest_attachments_download\n- :manage_contestnotifications\n- :notificationcomment_contestnotifications\n- :manage_boards\n- :add_messages\n- :edit_messages\n- :edit_own_messages\n- :delete_own_messages\n- :view_calendar\n- :manage_files\n- :view_files\n- :view_gantt\n- :view_issues\n- :save_queries\n- :browse_repository\n- :view_changesets\n', 'default'), +(15, 'Contestant', 13, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :course_attachments_download\n- :view_course_files\n- :select_contest_modules\n- :quote_project\n- :contest_attachments_download\n- :notificationcomment_contestnotifications\n- :add_messages\n- :edit_own_messages\n- :delete_own_messages\n- :view_calendar\n- :manage_files\n- :view_files\n- :view_gantt\n- :view_issues\n- :save_queries\n- :browse_repository\n- :view_changesets\n', 'default'); +COMMIT; + + +-- ---------------------------- +-- Records of ci_languages +-- ---------------------------- +BEGIN; +INSERT INTO `ci_languages` (`id`, `name`, `content`, `usage_amount`, `created_at`, `updated_at`, `cover_id`) VALUES +(1, 'C', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGdjYwogIGNvbW1hbmRzOgogIC0gLi9jb25maWd1cmUKICAtIG1h\na2UKICAtIG1ha2UgdGVzdA==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(2, 'C++', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGdjYwogIGNvbW1hbmRzOgogIC0gLi9jb25maWd1cmUKICAtIG1h\na2UKICAtIG1ha2UgdGVzdA==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(3, 'Docker', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGRvY2tlcjpkaW5kCiAgdm9sdW1lczoKICAtIG5hbWU6IGRvY2tl\ncnNvY2sKICAgIHBhdGg6IC92YXIvcnVuL2RvY2tlci5zb2NrCiAgICBjb21t\nYW5kczoKICAgIC0gZG9ja2VyIHBzIC1hCgp2b2x1bWVzOgotIG5hbWU6IGRv\nY2tlcnNvY2sKICBob3N0OgogICAgcGF0aDogL3Zhci9ydW4vZG9ja2VyLnNv\nY2s=\n', 0, '2020-10-21 10:14:22', '2020-11-26 01:35:20', 351688), +(4, 'Java', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IG1hdmVuOjMtamRrLTEwCiAgY29tbWFuZHM6CiAgLSBtdm4gaW5z\ndGFsbCAtRHNraXBUZXN0cz10cnVlIC1EbWF2ZW4uamF2YWRvYy5za2lwPXRy\ndWUgLUIgLVYKICAtIG12biB0ZXN0IC1C\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(5, 'R', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHItYmFzZQogIGNvbW1hbmRzOgogIC0gUiAtZSAnaW5zdGFsbC5w\nYWNrYWdlcyhjKCdwYWNrYWdlMScsJ3BhY2thZ2UyJykpJwogIC0gUiBDTUQg\nYnVpbGQgLg==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(6, 'Ruby', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHJ1YnkKICBjb21tYW5kczoKICAtIGJ1bmRsZSBpbnN0YWxsIC0t\nam9icz0zIC0tcmV0cnk9MwogIC0gcmFrZQ==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(7, 'PHP', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiBpbnN0YWxs\nCiAgaW1hZ2U6IGNvbXBvc2VyCiAgY29tbWFuZHM6CiAgLSBjb21wb3NlciBp\nbnN0YWxsCgotIG5hbWU6IHRlc3QKICBpbWFnZTogcGhwOjcKICBjb21tYW5k\nczoKICAtIHZlbmRvci9iaW4vcGhwdW5pdCAtLWNvbmZpZ3VyYXRpb24gY29u\nZmlnLnhtbA==\n', 0, '2020-10-21 10:14:22', '2020-11-26 01:37:04', 351690), +(8, 'Python', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHB5dGhvbgogIGNvbW1hbmRzOgogIC0gcGlwIGluc3RhbGwgLXIg\ncmVxdWlyZW1lbnRzLnR4dAogIC0gcHl0ZXN0\n', 0, '2020-10-21 10:14:22', '2020-11-26 01:40:00', 351693), +(9, 'MySQL', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IG15c3FsCiAgY29tbWFuZHM6CiAgLSBzbGVlcCAxNQogIC0gbXlz\ncWwgLXUgcm9vdCAtaCBkYXRhYmFzZSAtLWV4ZWN1dGU9J1NFTEVDVCBWRVJT\nSU9OKCk7JwoKc2VydmljZXM6Ci0gbmFtZTogZGF0YWJhc2UKICBpbWFnZTog\nbXlzcWwKICBlbnZpcm9ubWVudDoKICAgIE1ZU1FMX0FMTE9XX0VNUFRZX1BB\nU1NXT1JEOiAneWVzJwogICAgTVlTUUxfREFUQUJBU0U6IHRlc3Q=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(10, 'MongoDB', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiBwaW5nCiAg\naW1hZ2U6IG1vbmdvOjQKICBjb21tYW5kczoKICAtIHNsZWVwIDUKICAtIG1v\nbmdvIC0taG9zdCBtb25nbyAtLWV2YWwgJ2RiLnZlcnNpb24oKScKCnNlcnZp\nY2VzOgotIG5hbWU6IG1vbmdvCiAgaW1hZ2U6IG1vbmdvOjQKICBjb21tYW5k\nOiBbIC0tc21hbGxmaWxlcyBd\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(11, 'Clojure', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGNsb2p1cmUKICBjb21tYW5kczoKICAtIGxlaW4gdGVzdA==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(12, 'CouchDB', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGNvdWNoZGI6Mi4yCiAgY29tbWFuZHM6CiAgLSBzbGVlcCAxNQog\nIC0gY3VybCBodHRwOi8vZGF0YWJhc2U6NTk4NAoKc2VydmljZXM6Ci0gbmFt\nZTogZGF0YWJhc2UKICBpbWFnZTogY291Y2hkYjoyLjI=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(13, 'Crystal', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGNyeXN0YWxsYW5nL2NyeXN0YWwKICBjb21tYW5kczoKICAtIHNo\nYXJkcyBpbnN0YWxsCiAgLSBjcnlzdGFsIHNwZWMuMg==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(14, 'D', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGRsYW5ndWFnZS9kbWQKICBjb21tYW5kczoKICAtIGR1YiB0ZXN0\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(15, 'Dart', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGdvb2dsZS9kYXJ0CiAgY29tbWFuZHM6CiAgLSBwdWIgZ2V0CiAg\nLSBwdWIgcnVuIHRlc3Q=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(16, 'Docker (dind)', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGRvY2tlcjpkaW5kCiAgdm9sdW1lczoKICAtIG5hbWU6IGRvY2tl\ncnNvY2sKICAgIHBhdGg6IC92YXIvcnVuCiAgICBjb21tYW5kczoKICAgIC0g\nc2xlZXAgNSAjIGdpdmUgZG9ja2VyIGVub3VnaCB0aW1lIHRvIHN0YXJ0CiAg\nICAtIGRvY2tlciBwcyAtYQoKc2VydmljZXM6Ci0gbmFtZTogZG9ja2VyCiAg\naW1hZ2U6IGRvY2tlcjpkaW5kCiAgcHJpdmlsZWdlZDogdHJ1ZQogIHZvbHVt\nZXM6CiAgLSBuYW1lOiBkb2NrZXJzb2NrCiAgICBwYXRoOiAvdmFyL3J1bgoK\ndm9sdW1lczoKLSBuYW1lOiBkb2NrZXJzb2NrCiAgdGVtcDoge30=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(17, 'Elasticsearch', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGFscGluZTozLjgKICBjb21tYW5kczoKICAtIGFwayBhZGQgY3Vy\nbAogIC0gc2xlZXAgNDUKICAtIGN1cmwgaHR0cDovL2RhdGFiYXNlOjkyMDAK\nCnNlcnZpY2VzOgotIG5hbWU6IGRhdGFiYXNlCiAgaW1hZ2U6IGVsYXN0aWNz\nZWFyY2g6NS1hbHBpbmU=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(18, 'Elixir', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGVsaXhpcjoxLjUKICBjb21tYW5kczoKICAtIG1peCBsb2NhbC5y\nZWJhciAtLWZvcmNlCiAgLSBtaXggbG9jYWwuaGV4IC0tZm9yY2UKICAtIG1p\neCBkZXBzLmdldAogIC0gbWl4IHRlc3Q=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(19, 'Erlang', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGVybGFuZzoyMQogIGNvbW1hbmRzOgogIC0gcmViYXIgZ2V0LWRl\ncHMKICAtIHJlYmFyIGNvbXBpbGUKICAtIHJlYmFyIHNraXBfZGVwcz10cnVl\nIGV1bml0\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(20, '20.Go (with Gopath)', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0Cgp3b3Jrc3BhY2U6CiAgYmFzZTogL2dv\nCiAgcGF0aDogc3JjL2hlbGxvLXdvcmxkCgpzdGVwczoKLSBuYW1lOiB0ZXN0\nCiAgaW1hZ2U6IGdvbGFuZwogIGNvbW1hbmRzOgogIC0gZ28gZ2V0CiAgLSBn\nbyB0ZXN0\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(21, '21.Go (with Modules)', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGdvbGFuZwogIGNvbW1hbmRzOgogIC0gZ28gdGVzdAogIC0gZ28g\nYnVpbGQ=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(22, 'Gradle', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGdyYWRsZTpqZGsxMAogIGNvbW1hbmRzOgogIC0gZ3JhZGxlIGFz\nc2VtYmxlCiAgLSBncmFkbGUgY2hlY2s=\n', 0, '2020-10-21 10:14:22', '2020-11-26 01:36:17', 351689), +(23, 'Groovy', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGdyYWRsZToyLjUtamRrOAogIGNvbW1hbmRzOgogIC0gLi9ncmFk\nbGV3IGFzc2VtYmxlCiAgLSAuL2dyYWRsZXcgY2hlY2s=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(24, 'Haskell', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGhhc2tlbGwKICBjb21tYW5kczoKICAtIGNhYmFsIGluc3RhbGwg\nLS1vbmx5LWRlcGVuZGVuY2llcyAtLWVuYWJsZS10ZXN0cwogIC0gY2FiYWwg\nY29uZmlndXJlIC0tZW5hYmxlLXRlc3RzCiAgLSBjYWJhbCBidWlsZAogIC0g\nY2FiYWwgdGVzdA==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(25, 'Haxe', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGhheGUKICBjb21tYW5kczoKICAtIGhheGVsaWIgaW5zdGFsbCBi\ndWlsZC5oeG1sCiAgLSBoYXhlIGJ1aWxkLmh4bWw=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(26, 'MariaDB', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IG1hcmlhZGIKICBjb21tYW5kczoKICAtIHNsZWVwIDE1CiAgLSBt\neXNxbCAtdSByb290IC1oIGRhdGFiYXNlIC0tZXhlY3V0ZT0nU0VMRUNUIFZF\nUlNJT04oKTsnCgpzZXJ2aWNlczoKLSBuYW1lOiBkYXRhYmFzZQogIGltYWdl\nOiBtYXJpYWRiCiAgZW52aXJvbm1lbnQ6CiAgICBNWVNRTF9BTExPV19FTVBU\nWV9QQVNTV09SRDogJ3llcycKICAgIE1ZU1FMX0RBVEFCQVNFOiB0ZXN0\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(27, 'Maven', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IG1hdmVuOjMtamRrLTEwCiAgY29tbWFuZHM6CiAgLSBtdm4gaW5z\ndGFsbCAtRHNraXBUZXN0cz10cnVlIC1EbWF2ZW4uamF2YWRvYy5za2lwPXRy\ndWUgLUIgLVYKICAtIG12biB0ZXN0IC1C\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(28, 'Memcached', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHVidW50dQogIGNvbW1hbmRzOgogIC0gYXB0LWdldCB1cGRhdGUg\nLXFxCiAgLSBhcHQtZ2V0IGluc3RhbGwgLXkgLXFxIHRlbG5ldCA+IC9kZXYv\nbnVsbAogIC0gKHNsZWVwIDE7IGVjaG8gJ3N0YXRzJzsgc2xlZXAgMjsgZWNo\nbyAncXVpdCc7KSB8IHRlbG5ldCBjYWNoZSAxMTIxMSB8fCB0cnVlCgpzZXJ2\naWNlczoKLSBuYW1lOiBjYWNoZQogIGltYWdlOiBtZW1jYWNoZWQ6YWxwaW5l\nCiAgY29tbWFuZDogWyAtdnYgXQ==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(29, 'Nats', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHJ1Ynk6MgogIGNvbW1hbmRzOgogIC0gZ2VtIGluc3RhbGwgbmF0\ncwogIC0gbmF0cy1wdWIgLXMgdGNwOi8vbmF0czo0MjIyIGdyZWV0aW5nICdo\nZWxsbycKICAtIG5hdHMtcHViIC1zIHRjcDovL25hdHM6NDIyMiBncmVldGlu\nZyAnd29ybGQnCgpzZXJ2aWNlczoKLSBuYW1lOiBuYXRzCiAgaW1hZ2U6IG5h\ndHM6MS4zLjA=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(30, 'Node', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IG5vZGUKICBjb21tYW5kczoKICAtIG5wbSBpbnN0YWxsCiAgLSBu\ncG0gdGVzdA==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(31, 'Perl', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHBlcmwKICBjb21tYW5kczoKICAtIGNwYW5tIC0tcXVpZXQgLS1p\nbnN0YWxsZGVwcyAtLW5vdGVzdCAuCiAgLSBwZXJsIEJ1aWxkLlBMCiAgLSAu\nL0J1aWxkIHRlc3Q=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(32, 'Postgres', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHBvc3RncmVzOjktYWxwaW5lCiAgY29tbWFuZHM6CiAgLSBwc3Fs\nIC1VIHBvc3RncmVzIC1kIHRlc3QgLWggZGF0YWJhc2UKCnNlcnZpY2VzOgot\nIG5hbWU6IGRhdGFiYXNlCiAgaW1hZ2U6IHBvc3RncmVzOjktYWxwaW5lCiAg\nZW52aXJvbm1lbnQ6CiAgICBQT1NUR1JFU19VU0VSOiBwb3N0Z3JlcwogICAg\nUE9TVEdSRVNfREI6IHRlc3Q=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(33, 'Redis', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHJlZGlzCiAgY29tbWFuZHM6CiAgLSBzbGVlcCA1CiAgLSByZWRp\ncy1jbGkgLWggcmVkaXMgcGluZwogIC0gcmVkaXMtY2xpIC1oIHJlZGlzIHNl\ndCBGT08gYmFyCiAgLSByZWRpcy1jbGkgLWggcmVkaXMgZ2V0IEZPTwoKc2Vy\ndmljZXM6Ci0gbmFtZTogcmVkaXMKICBpbWFnZTogcmVkaXM=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(34, 'RethinkDB', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IG5vZGU6OQogIGNvbW1hbmRzOgogIC0gbnBtIGluc3RhbGwgLXMg\nLWcgcmVjbGkKICAtIHJlY2xpIC1oIGRhdGFiYXNlIC1qICdyLmRiKCdyZXRo\naW5rZGInKS50YWJsZSgnc3RhdHMnKScKCnNlcnZpY2VzOgotIG5hbWU6IGRh\ndGFiYXNlCiAgaW1hZ2U6IHJldGhpbmtkYjoyCiAgY29tbWFuZDogWyByZXRo\naW5rZGIsIC0tYmluZCwgYWxsIF0=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(35, 'Rust', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHJ1c3Q6MS4zMAogIGNvbW1hbmRzOgogIC0gY2FyZ28gYnVpbGQg\nLS12ZXJib3NlIC0tYWxsCiAgLSBjYXJnbyB0ZXN0IC0tdmVyYm9zZSAtLWFs\nbA==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(36, 'Swift', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHN3aWZ0OjQKICBjb21tYW5kczoKICAtIHN3aWZ0IGJ1aWxkCiAg\nLSBzd2lmdCB0ZXN0\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(37, 'Vault', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHZhdWx0OjEuMC4wLWJldGEyCiAgZW52aXJvbm1lbnQ6CiAgICBW\nQVVMVF9BRERSOiBodHRwOi8vdmF1bHQ6ODIwMAogICAgVkFVTFRfVE9LRU46\nIGR1bW15CiBjb21tYW5kczoKIC0gc2xlZXAgNQogLSB2YXVsdCBrdiBwdXQg\nc2VjcmV0L215LXNlY3JldCBteS12YWx1ZT1zM2NyM3QKIC0gdmF1bHQga3Yg\nZ2V0IHNlY3JldC9teS1zZWNyZXQKCnNlcnZpY2VzOgotIG5hbWU6IHZhdWx0\nCiAgaW1hZ2U6IHZhdWx0OjEuMC4wLWJldGEyCiAgZW52aXJvbm1lbnQ6CiAg\nICBWQVVMVF9ERVZfUk9PVF9UT0tFTl9JRDogZHVtbXk=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL); +COMMIT; + +-- ---------------------------- +-- Records of ci_templates +-- ---------------------------- +BEGIN; +INSERT INTO `ci_templates` (`id`, `template_name`, `stage_type`, `category`, `content`, `created_at`, `updated_at`, `parent_category`, `login`) VALUES +(2, 'linux/amd64', 'init', '初始化', 'kind: pipeline\r\ntype: docker\r\nname: {name}\r\nplatform:\r\n os: linux\r\n arch: amd64', '2021-01-12 02:44:23', '2021-02-02 10:51:36', '初始化', 'admin'), +(3, 'linux/arm64', 'init', '初始化', 'kind: pipeline\r\ntype: docker\r\nname: {name}\r\nplatform:\r\n os: linux\r\n arch: arm64', '2021-01-12 02:45:17', '2021-02-02 10:51:47', '初始化', 'admin'), +(4, 'maven', 'build', 'Java', '- name: maven\r\n image: maven:3-jdk-10\r\n commands:\r\n - mvn install -DskipTests=true', '2021-01-12 02:53:29', '2021-01-12 02:53:29', '编译构建', 'admin'), +(5, 'maven单元测试', 'customize', 'Java', '- name: maven\r\n image: maven:3-jdk-10\r\n commands:\r\n - mvn test', '2021-01-12 02:53:29', '2021-01-12 02:53:29', '单元测试', 'admin'), +(6, 'golang单元测试', 'customize', 'Golang', '- name: golang单元测试\r\n image: golang\r\n commands:\r\n - go test', '2021-01-12 03:03:35', '2021-01-12 03:03:35', '单元测试', 'admin'), +(8, 'gradle', 'build', 'Java', '- name: gradle\r\n image: gradle:jdk10\r\n commands:\r\n - gradle build -x test', '2021-01-12 03:05:33', '2021-01-12 03:05:33', '编译构建', 'admin'), +(9, 'gradle单元测试', 'customize', 'Java', '- name: gradle\r\n image: gradle:jdk10\r\n commands:\r\n - gradle test', '2021-01-12 03:05:33', '2021-01-12 03:05:33', '单元测试', 'admin'), +(10, '远程主机部署', 'deploy', '部署', '# 需要将软件包与部署脚本提前上传到远程主机(见文件上传模板)\r\n# host、username、password可在参数管理中配置\r\n- name: 远程主机部署\r\n image: appleboy/drone-ssh\r\n settings:\r\n host: \r\n from_secret: ip\r\n username: \r\n from_secret: name\r\n password: \r\n from_secret: pwd\r\n port: 22\r\n script:\r\n - chmod +x /home/deploy.sh\r\n - ./home/deploy.sh', '2021-01-12 03:32:46', '2021-03-05 06:22:02', '部署', 'admin'), +(11, '远程命令', 'customize', '其他', '# host、username、password可在参数管理中配置\r\n- name: 远程命令\r\n image: appleboy/drone-ssh\r\n settings:\r\n host: \r\n from_secret: ip\r\n username: \r\n from_secret: name\r\n password: \r\n from_secret: pwd\r\n port: 22\r\n script:\r\n - echo ''hello world!''', '2021-01-12 03:40:38', '2021-03-05 06:19:44', '其他', 'admin'), +(12, '上传文件', 'customize', '其他', '# 本模板示例为上传软件包和部署脚本到home目录\r\n# host、username、password可在参数管理中配置\r\n- name: 上传文件\r\n image: appleboy/drone-scp\r\n settings:\r\n host: \r\n from_secret: ip\r\n username: \r\n from_secret: name\r\n password: \r\n from_secret: pwd\r\n port: 22\r\n target: /home\r\n source: \r\n - target/*.jar\r\n - deploy.sh', '2021-01-12 03:40:55', '2021-03-05 06:22:22', '其他', 'admin'), +(17, 'make-c', 'build', 'C', '- name: 编译\r\n image: gcc\r\n commands:\r\n - ./configure\r\n - make', '2021-01-15 01:19:38', '2021-02-02 10:52:15', '编译构建', 'admin'), +(19, 'make-c++', 'build', 'C++', '- name: 编译构建\r\n image: gcc\r\n commands:\r\n - ./configure\r\n - make', '2021-01-15 01:21:05', '2021-01-15 01:21:05', '编译构建', 'admin'), +(20, 'python', 'build', 'Python', '- name: 编译构建\r\n image: python\r\n commands:\r\n - pip install -r requirements.txt', '2021-01-15 01:22:36', '2021-01-15 01:22:36', '编译构建', 'admin'), +(21, 'Docker', 'build', 'Docker', '# 构建Docker镜像并推送到仓库\r\n# 定义镜像Hub路径以及账号密码\r\n- name: Docker镜像构建\r\n image: plugins/docker\r\n settings:\r\n username: username\r\n password: pwd\r\n repo: repoUrl\r\n tags: latest', '2021-01-15 01:23:16', '2021-02-03 03:40:49', '编译构建', 'admin'), +(22, '空白模板', 'customize', 'customize', '', '2021-01-15 02:53:02', '2021-01-15 02:53:02', '其他', 'admin'), +(25, 'Go (with Gopath)', 'build', 'Go', '- name: golang\r\n image: golang\r\n commands:\r\n - go get\r\n - go test', '2021-02-03 00:57:32', '2021-02-03 03:36:15', '编译构建', 'admin'), +(26, 'PHP', 'build', 'PHP', '- name: install\r\n image: composer\r\n commands:\r\n - composer install', '2021-02-03 00:59:15', '2021-02-03 00:59:15', '编译构建', 'admin'), +(27, 'Ruby', 'build', 'Ruby', '- name: ruby\r\n image: ruby\r\n commands:\r\n - bundle install --jobs=3 --retry=3\r\n - rake', '2021-02-03 00:59:52', '2021-02-03 00:59:52', '编译构建', 'admin'), +(29, 'Go (with Modules)', 'build', 'Go', '- name: test\r\n image: golang\r\n commands:\r\n - go test\r\n - go build', '2021-02-03 03:35:45', '2021-02-03 03:35:45', '编译构建', 'admin'), +(30, 'Node', 'build', 'Node', '- name: Node编译\r\n image: node\r\n commands:\r\n - npm install\r\n - npm test', '2021-02-03 03:37:31', '2021-02-03 03:37:31', '编译构建', 'admin'), +(31, 'Perl ', 'build', 'Perl', '- name: perl\r\n image: perl\r\n commands:\r\n - cpanm --quiet --installdeps --notest .\r\n - perl Build.PL\r\n - ./Build test', '2021-02-03 03:38:06', '2021-02-03 03:38:06', '编译构建', 'admin'), +(32, 'Rust ', 'build', 'Rust', '- name: rust\r\n image: rust:1.30\r\n commands:\r\n - cargo build --verbose --all\r\n - cargo test --verbose --all', '2021-02-03 03:38:37', '2021-02-03 03:38:37', '编译构建', 'admin'), +(33, 'test', 'init', '初始化', 'qqqq', '2021-02-04 09:02:42', '2021-02-04 09:02:42', '初始化', 'admin'); +COMMIT; diff --git a/db/migrate/20210527024043_create_pinned_projects.rb b/db/migrate/20210527024043_create_pinned_projects.rb new file mode 100644 index 00000000..50345ceb --- /dev/null +++ b/db/migrate/20210527024043_create_pinned_projects.rb @@ -0,0 +1,11 @@ +class CreatePinnedProjects < ActiveRecord::Migration[5.2] + def change + create_table :pinned_projects do |t| + t.references :user + t.references :project + t.integer :position, default: 0 + + t.timestamps + end + end +end diff --git a/db/migrate/20210531100250_add_fields_to_user_extensions.rb b/db/migrate/20210531100250_add_fields_to_user_extensions.rb new file mode 100644 index 00000000..890cd35a --- /dev/null +++ b/db/migrate/20210531100250_add_fields_to_user_extensions.rb @@ -0,0 +1,8 @@ +class AddFieldsToUserExtensions < ActiveRecord::Migration[5.2] + def change + add_column :user_extensions, :province, :string # 省份 + add_column :user_extensions, :city, :string # 城市 + add_column :user_extensions, :custom_department, :string #自己填写的单位名称 + # remove_column :users, :description + end +end diff --git a/db/migrate/20210603020327_add_show_condition_to_user_extensions.rb b/db/migrate/20210603020327_add_show_condition_to_user_extensions.rb new file mode 100644 index 00000000..e64da0b7 --- /dev/null +++ b/db/migrate/20210603020327_add_show_condition_to_user_extensions.rb @@ -0,0 +1,7 @@ +class AddShowConditionToUserExtensions < ActiveRecord::Migration[5.2] + def change + add_column :user_extensions, :show_email, :boolean, default: false + add_column :user_extensions, :show_location, :boolean, default: false + add_column :user_extensions, :show_department, :boolean, default: false + end +end diff --git a/db/migrate/20210609072904_add_timestamp_to_applied_projects.rb b/db/migrate/20210609072904_add_timestamp_to_applied_projects.rb new file mode 100644 index 00000000..d5d4067a --- /dev/null +++ b/db/migrate/20210609072904_add_timestamp_to_applied_projects.rb @@ -0,0 +1,5 @@ +class AddTimestampToAppliedProjects < ActiveRecord::Migration[5.2] + def change + add_timestamps(:applied_projects, null: true) + end +end diff --git a/db/structure.sql b/db/structure.sql index 26208e57..3b1b437e 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -3424,98 +3424,3 @@ COMMIT; BEGIN; INSERT INTO `laboratory_settings` VALUES (1, 1, '{\"name\":\"EduCoder\",\"navbar\":[{\"name\":\"实践课程\",\"link\":\"/paths\",\"hidden\":false},{\"name\":\"翻转课堂\",\"link\":\"/courses\",\"hidden\":false},{\"name\":\"实现项目\",\"link\":\"/shixuns\",\"hidden\":false},{\"name\":\"在线竞赛\",\"link\":\"/competitions\",\"hidden\":false},{\"name\":\"教学案例\",\"link\":\"/moop_cases\",\"hidden\":false},{\"name\":\"交流问答\",\"link\":\"/forums\",\"hidden\":false}],\"footer\":\"\\n\\u003cp class=\\\"footer_con-p inline lineh-30 font-14\\\"\\u003e\\n \\u003cspan class=\\\"font-18 fl\\\"\\u003e©\\u003c/span\\u003e\\u0026nbsp;2019\\u0026nbsp;EduCoder\\n \\u003ca target=\\\"_blank\\\" href=\\\"http://beian.miit.gov.cn/\\\" class=\\\"ml15 mr15\\\" style=\\\"color: rgb(136, 136, 136);\\\"\\u003e湘ICP备17009477号\\u003c/a\\u003e\\n \\u003ca target=\\\"_blank\\\" href=\\\"http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=43019002000962\\\" class=\\\"mr15\\\" style=\\\"color: rgb(136, 136, 136);\\\"\\u003e\\n \\u003cimg class=\\\"vertical4\\\" src=\\\"https://ali-cdn.educoder.net/react/build/static/media/beian.d0289dc0.png\\\"\\u003e湘公网安备43019002000962号\\n \\u003c/a\\u003e\\n \\u003ca href=\\\"https://team.trustie.net\\\" target=\\\"_blank\\\" style=\\\"color: rgb(136, 136, 136);\\\"\\u003eTrustie\\u003c/a\\u003e\\n \\u0026nbsp;\\u0026nbsp;\\u0026nbsp;\\u0026amp;\\u0026nbsp;\\u0026nbsp;\\u0026nbsp;IntelliDE inside.\\n \\u003cspan class=\\\"mr15\\\"\\u003e版权所有 湖南智擎科技有限公司\\u003c/span\\u003e\\u003c/p\\u003e\\n \"}'); COMMIT; - --- ---------------------------- --- Records of roles --- ---------------------------- -BEGIN; -INSERT INTO `roles` (`id`, `name`, `position`, `assignable`, `builtin`, `permissions`, `issues_visibility`) VALUES -(1, 'Non member', 1, 1, 1, '---\n- :upload_attachments\n- :memos_attachments_download\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :course_attachments_download\n- :view_course_files\n- :add_messages\n- :delete_own_messages\n- :view_calendar\n- :view_documents\n- :view_files\n- :view_gantt\n- :view_issues\n- :save_queries\n- :comment_news\n- :browse_repository\n- :view_changesets\n- :view_time_entries\n- :view_wiki_pages\n- :view_wiki_edits\n', 'default'), -(2, 'Anonymous', 2, 1, 2, '---\n- :memos_attachments_download\n- :view_course_files\n- :view_calendar\n- :view_documents\n- :view_files\n- :view_gantt\n- :view_issues\n- :browse_repository\n- :view_changesets\n- :view_time_entries\n- :view_wiki_pages\n- :view_wiki_edits\n', 'default'), -(3, 'Manager', 3, 1, 0, '---\n- :add_project\n- :edit_project\n- :close_project\n- :select_project_modules\n- :manage_members\n- :manage_versions\n- :add_subprojects\n- :is_manager\n- :projects_attachments_download\n- :as_teacher\n- :add_course\n- :edit_course\n- :close_course\n- :select_course_modules\n- :view_course_journals_for_messages\n- :course_attachments_download\n- :view_course_files\n- :view_homework_attaches\n- :quote_project\n- :manage_boards\n- :add_messages\n- :edit_messages\n- :edit_own_messages\n- :delete_messages\n- :delete_own_messages\n- :view_calendar\n- :view_code_review\n- :add_code_review\n- :edit_code_review\n- :delete_code_review\n- :assign_code_review\n- :code_review_setting\n- :add_documents\n- :edit_documents\n- :delete_documents\n- :view_documents\n- :manage_files\n- :view_files\n- :view_gantt\n- :manage_categories\n- :view_issues\n- :add_issues\n- :edit_issues\n- :manage_issue_relations\n- :manage_subtasks\n- :set_issues_private\n- :set_own_issues_private\n- :add_issue_notes\n- :edit_issue_notes\n- :edit_own_issue_notes\n- :view_private_notes\n- :set_notes_private\n- :move_issues\n- :delete_issues\n- :manage_public_queries\n- :save_queries\n- :view_issue_watchers\n- :add_issue_watchers\n- :delete_issue_watchers\n- :manage_news\n- :comment_news\n- :manage_repository\n- :browse_repository\n- :view_changesets\n- :commit_access\n- :manage_related_issues\n- :log_time\n- :view_time_entries\n- :edit_time_entries\n- :edit_own_time_entries\n- :manage_project_activities\n- :manage_wiki\n- :rename_wiki_pages\n- :delete_wiki_pages\n- :view_wiki_pages\n- :export_wiki_pages\n- :view_wiki_edits\n- :edit_wiki_pages\n- :delete_wiki_pages_attachments\n- :protect_wiki_pages\n', 'all'), -(4, 'Developer', 5, 1, 0, '---\n- :add_project\n- :manage_versions\n- :projects_attachments_download\n- :add_course\n- :edit_course\n- :close_course\n- :select_course_modules\n- :view_course_journals_for_messages\n- :course_attachments_download\n- :view_course_files\n- :view_homework_attaches\n- :paret_in_homework\n- :select_contest_modules\n- :quote_project\n- :contest_attachments_download\n- :manage_contestnotifications\n- :notificationcomment_contestnotifications\n- :manage_boards\n- :add_messages\n- :edit_own_messages\n- :delete_own_messages\n- :view_calendar\n- :manage_files\n- :view_files\n- :view_gantt\n- :manage_categories\n- :view_issues\n- :add_issues\n- :edit_issues\n- :manage_issue_relations\n- :manage_subtasks\n- :set_issues_private\n- :set_own_issues_private\n- :add_issue_notes\n- :edit_issue_notes\n- :edit_own_issue_notes\n- :view_private_notes\n- :set_notes_private\n- :move_issues\n- :delete_issues\n- :manage_public_queries\n- :save_queries\n- :view_issue_watchers\n- :add_issue_watchers\n- :delete_issue_watchers\n- :manage_repository\n- :browse_repository\n- :view_changesets\n- :commit_access\n- :manage_related_issues\n', 'all'), -(5, 'Reporter', 4, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :edit_course\n- :close_course\n- :select_course_modules\n- :view_course_journals_for_messages\n- :course_attachments_download\n- :view_course_files\n- :view_homework_attaches\n- :manage_boards\n- :add_messages\n- :edit_own_messages\n- :delete_own_messages\n- :view_calendar\n- :view_code_review\n- :manage_files\n- :view_files\n- :view_gantt\n- :view_issues\n- :add_issues\n- :edit_issues\n- :add_issue_notes\n- :edit_own_issue_notes\n- :save_queries\n- :comment_news\n- :browse_repository\n- :view_wiki_pages\n- :export_wiki_pages\n- :view_wiki_edits\n- :edit_wiki_pages\n- :delete_wiki_pages_attachments\n', 'all'), -(7, 'TeachingAsistant', 6, 1, 0, '---\n- :add_project\n- :edit_project\n- :manage_members\n- :projects_attachments_download\n- :as_teacher\n- :add_course\n- :edit_course\n- :close_course\n- :select_course_modules\n- :view_course_journals_for_messages\n- :course_attachments_download\n- :view_course_files\n- :view_homework_attaches\n- :manage_boards\n- :add_messages\n- :edit_own_messages\n- :delete_messages\n- :delete_own_messages\n- :view_calendar\n- :view_documents\n- :manage_files\n- :view_files\n- :view_gantt\n- :view_issues\n- :add_issues\n- :add_issue_notes\n- :save_queries\n- :manage_news\n- :comment_news\n- :browse_repository\n- :view_changesets\n- :view_time_entries\n- :view_wiki_pages\n- :export_wiki_pages\n- :view_wiki_edits\n- :edit_wiki_pages\n- :delete_wiki_pages_attachments\n', 'default'), -(9, 'Teacher', 7, 1, 0, '---\n- :upload_attachments\n- :memos_attachments_download\n- :add_project\n- :edit_project\n- :close_project\n- :select_project_modules\n- :manage_members\n- :manage_versions\n- :add_subprojects\n- :projects_attachments_download\n- :as_teacher\n- :add_course\n- :edit_course\n- :close_course\n- :select_course_modules\n- :view_course_journals_for_messages\n- :course_attachments_download\n- :view_course_files\n- :view_homework_attaches\n- :manage_boards\n- :add_messages\n- :edit_messages\n- :edit_own_messages\n- :delete_messages\n- :delete_own_messages\n- :view_calendar\n- :add_documents\n- :edit_documents\n- :delete_documents\n- :view_documents\n- :manage_files\n- :view_files\n- :view_gantt\n- :manage_categories\n- :view_issues\n- :add_issues\n- :edit_issues\n- :manage_issue_relations\n- :manage_subtasks\n- :set_issues_private\n- :set_own_issues_private\n- :add_issue_notes\n- :edit_own_issue_notes\n- :view_private_notes\n- :set_notes_private\n- :move_issues\n- :delete_issues\n- :manage_public_queries\n- :save_queries\n- :view_issue_watchers\n- :add_issue_watchers\n- :delete_issue_watchers\n- :manage_news\n- :comment_news\n- :manage_repository\n- :browse_repository\n- :view_changesets\n- :commit_access\n- :manage_related_issues\n- :log_time\n- :view_time_entries\n- :edit_time_entries\n- :edit_own_time_entries\n- :manage_project_activities\n- :manage_wiki\n- :rename_wiki_pages\n- :delete_wiki_pages\n- :view_wiki_pages\n- :export_wiki_pages\n- :view_wiki_edits\n- :edit_wiki_pages\n- :delete_wiki_pages_attachments\n- :protect_wiki_pages\n', 'default'), -(10, 'Student', 9, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :as_student\n- :add_course\n- :edit_course\n- :close_course\n- :select_course_modules\n- :view_course_journals_for_messages\n- :course_attachments_download\n- :view_course_files\n- :view_homework_attaches\n- :paret_in_homework\n- :manage_boards\n- :add_messages\n- :edit_own_messages\n- :delete_own_messages\n- :view_calendar\n- :view_documents\n- :manage_files\n- :view_files\n- :view_gantt\n- :view_issues\n- :add_issues\n- :add_issue_notes\n- :save_queries\n- :comment_news\n- :browse_repository\n- :view_changesets\n- :view_time_entries\n- :view_wiki_pages\n- :view_wiki_edits\n', 'default'), -(11, 'orgManager', 8, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :course_attachments_download\n- :view_course_files\n- :add_messages\n- :delete_own_messages\n- :view_calendar\n- :view_documents\n- :view_files\n- :view_gantt\n- :view_issues\n- :save_queries\n- :comment_news\n- :browse_repository\n- :view_changesets\n- :view_time_entries\n- :view_wiki_pages\n- :view_wiki_edits\n', 'default'), -(12, 'orgMember', 10, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :course_attachments_download\n- :view_course_files\n- :add_messages\n- :delete_own_messages\n- :view_calendar\n- :view_documents\n- :view_files\n- :view_gantt\n- :view_issues\n- :save_queries\n- :comment_news\n- :browse_repository\n- :view_changesets\n- :view_time_entries\n- :view_wiki_pages\n- :view_wiki_edits\n', 'default'), -(13, 'ContestManager', 11, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :course_attachments_download\n- :view_course_files\n- :select_contest_modules\n- :quote_project\n- :contest_attachments_download\n- :manage_contestnotifications\n- :notificationcomment_contestnotifications\n- :manage_boards\n- :add_messages\n- :edit_messages\n- :edit_own_messages\n- :delete_messages\n- :delete_own_messages\n- :view_calendar\n- :view_files\n- :view_gantt\n- :view_issues\n- :save_queries\n- :browse_repository\n- :view_changesets\n', 'default'), -(14, 'Judge', 12, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :course_attachments_download\n- :view_course_files\n- :select_contest_modules\n- :quote_project\n- :contest_attachments_download\n- :manage_contestnotifications\n- :notificationcomment_contestnotifications\n- :manage_boards\n- :add_messages\n- :edit_messages\n- :edit_own_messages\n- :delete_own_messages\n- :view_calendar\n- :manage_files\n- :view_files\n- :view_gantt\n- :view_issues\n- :save_queries\n- :browse_repository\n- :view_changesets\n', 'default'), -(15, 'Contestant', 13, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :course_attachments_download\n- :view_course_files\n- :select_contest_modules\n- :quote_project\n- :contest_attachments_download\n- :notificationcomment_contestnotifications\n- :add_messages\n- :edit_own_messages\n- :delete_own_messages\n- :view_calendar\n- :manage_files\n- :view_files\n- :view_gantt\n- :view_issues\n- :save_queries\n- :browse_repository\n- :view_changesets\n', 'default'); -COMMIT; - - --- ---------------------------- --- Records of ci_languages --- ---------------------------- -BEGIN; -INSERT INTO `ci_languages` (`id`, `name`, `content`, `usage_amount`, `created_at`, `updated_at`, `cover_id`) VALUES -(1, 'C', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGdjYwogIGNvbW1hbmRzOgogIC0gLi9jb25maWd1cmUKICAtIG1h\na2UKICAtIG1ha2UgdGVzdA==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(2, 'C++', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGdjYwogIGNvbW1hbmRzOgogIC0gLi9jb25maWd1cmUKICAtIG1h\na2UKICAtIG1ha2UgdGVzdA==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(3, 'Docker', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGRvY2tlcjpkaW5kCiAgdm9sdW1lczoKICAtIG5hbWU6IGRvY2tl\ncnNvY2sKICAgIHBhdGg6IC92YXIvcnVuL2RvY2tlci5zb2NrCiAgICBjb21t\nYW5kczoKICAgIC0gZG9ja2VyIHBzIC1hCgp2b2x1bWVzOgotIG5hbWU6IGRv\nY2tlcnNvY2sKICBob3N0OgogICAgcGF0aDogL3Zhci9ydW4vZG9ja2VyLnNv\nY2s=\n', 0, '2020-10-21 10:14:22', '2020-11-26 01:35:20', 351688), -(4, 'Java', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IG1hdmVuOjMtamRrLTEwCiAgY29tbWFuZHM6CiAgLSBtdm4gaW5z\ndGFsbCAtRHNraXBUZXN0cz10cnVlIC1EbWF2ZW4uamF2YWRvYy5za2lwPXRy\ndWUgLUIgLVYKICAtIG12biB0ZXN0IC1C\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(5, 'R', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHItYmFzZQogIGNvbW1hbmRzOgogIC0gUiAtZSAnaW5zdGFsbC5w\nYWNrYWdlcyhjKCdwYWNrYWdlMScsJ3BhY2thZ2UyJykpJwogIC0gUiBDTUQg\nYnVpbGQgLg==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(6, 'Ruby', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHJ1YnkKICBjb21tYW5kczoKICAtIGJ1bmRsZSBpbnN0YWxsIC0t\nam9icz0zIC0tcmV0cnk9MwogIC0gcmFrZQ==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(7, 'PHP', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiBpbnN0YWxs\nCiAgaW1hZ2U6IGNvbXBvc2VyCiAgY29tbWFuZHM6CiAgLSBjb21wb3NlciBp\nbnN0YWxsCgotIG5hbWU6IHRlc3QKICBpbWFnZTogcGhwOjcKICBjb21tYW5k\nczoKICAtIHZlbmRvci9iaW4vcGhwdW5pdCAtLWNvbmZpZ3VyYXRpb24gY29u\nZmlnLnhtbA==\n', 0, '2020-10-21 10:14:22', '2020-11-26 01:37:04', 351690), -(8, 'Python', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHB5dGhvbgogIGNvbW1hbmRzOgogIC0gcGlwIGluc3RhbGwgLXIg\ncmVxdWlyZW1lbnRzLnR4dAogIC0gcHl0ZXN0\n', 0, '2020-10-21 10:14:22', '2020-11-26 01:40:00', 351693), -(9, 'MySQL', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IG15c3FsCiAgY29tbWFuZHM6CiAgLSBzbGVlcCAxNQogIC0gbXlz\ncWwgLXUgcm9vdCAtaCBkYXRhYmFzZSAtLWV4ZWN1dGU9J1NFTEVDVCBWRVJT\nSU9OKCk7JwoKc2VydmljZXM6Ci0gbmFtZTogZGF0YWJhc2UKICBpbWFnZTog\nbXlzcWwKICBlbnZpcm9ubWVudDoKICAgIE1ZU1FMX0FMTE9XX0VNUFRZX1BB\nU1NXT1JEOiAneWVzJwogICAgTVlTUUxfREFUQUJBU0U6IHRlc3Q=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(10, 'MongoDB', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiBwaW5nCiAg\naW1hZ2U6IG1vbmdvOjQKICBjb21tYW5kczoKICAtIHNsZWVwIDUKICAtIG1v\nbmdvIC0taG9zdCBtb25nbyAtLWV2YWwgJ2RiLnZlcnNpb24oKScKCnNlcnZp\nY2VzOgotIG5hbWU6IG1vbmdvCiAgaW1hZ2U6IG1vbmdvOjQKICBjb21tYW5k\nOiBbIC0tc21hbGxmaWxlcyBd\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(11, 'Clojure', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGNsb2p1cmUKICBjb21tYW5kczoKICAtIGxlaW4gdGVzdA==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(12, 'CouchDB', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGNvdWNoZGI6Mi4yCiAgY29tbWFuZHM6CiAgLSBzbGVlcCAxNQog\nIC0gY3VybCBodHRwOi8vZGF0YWJhc2U6NTk4NAoKc2VydmljZXM6Ci0gbmFt\nZTogZGF0YWJhc2UKICBpbWFnZTogY291Y2hkYjoyLjI=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(13, 'Crystal', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGNyeXN0YWxsYW5nL2NyeXN0YWwKICBjb21tYW5kczoKICAtIHNo\nYXJkcyBpbnN0YWxsCiAgLSBjcnlzdGFsIHNwZWMuMg==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(14, 'D', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGRsYW5ndWFnZS9kbWQKICBjb21tYW5kczoKICAtIGR1YiB0ZXN0\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(15, 'Dart', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGdvb2dsZS9kYXJ0CiAgY29tbWFuZHM6CiAgLSBwdWIgZ2V0CiAg\nLSBwdWIgcnVuIHRlc3Q=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(16, 'Docker (dind)', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGRvY2tlcjpkaW5kCiAgdm9sdW1lczoKICAtIG5hbWU6IGRvY2tl\ncnNvY2sKICAgIHBhdGg6IC92YXIvcnVuCiAgICBjb21tYW5kczoKICAgIC0g\nc2xlZXAgNSAjIGdpdmUgZG9ja2VyIGVub3VnaCB0aW1lIHRvIHN0YXJ0CiAg\nICAtIGRvY2tlciBwcyAtYQoKc2VydmljZXM6Ci0gbmFtZTogZG9ja2VyCiAg\naW1hZ2U6IGRvY2tlcjpkaW5kCiAgcHJpdmlsZWdlZDogdHJ1ZQogIHZvbHVt\nZXM6CiAgLSBuYW1lOiBkb2NrZXJzb2NrCiAgICBwYXRoOiAvdmFyL3J1bgoK\ndm9sdW1lczoKLSBuYW1lOiBkb2NrZXJzb2NrCiAgdGVtcDoge30=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(17, 'Elasticsearch', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGFscGluZTozLjgKICBjb21tYW5kczoKICAtIGFwayBhZGQgY3Vy\nbAogIC0gc2xlZXAgNDUKICAtIGN1cmwgaHR0cDovL2RhdGFiYXNlOjkyMDAK\nCnNlcnZpY2VzOgotIG5hbWU6IGRhdGFiYXNlCiAgaW1hZ2U6IGVsYXN0aWNz\nZWFyY2g6NS1hbHBpbmU=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(18, 'Elixir', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGVsaXhpcjoxLjUKICBjb21tYW5kczoKICAtIG1peCBsb2NhbC5y\nZWJhciAtLWZvcmNlCiAgLSBtaXggbG9jYWwuaGV4IC0tZm9yY2UKICAtIG1p\neCBkZXBzLmdldAogIC0gbWl4IHRlc3Q=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(19, 'Erlang', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGVybGFuZzoyMQogIGNvbW1hbmRzOgogIC0gcmViYXIgZ2V0LWRl\ncHMKICAtIHJlYmFyIGNvbXBpbGUKICAtIHJlYmFyIHNraXBfZGVwcz10cnVl\nIGV1bml0\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(20, '20.Go (with Gopath)', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0Cgp3b3Jrc3BhY2U6CiAgYmFzZTogL2dv\nCiAgcGF0aDogc3JjL2hlbGxvLXdvcmxkCgpzdGVwczoKLSBuYW1lOiB0ZXN0\nCiAgaW1hZ2U6IGdvbGFuZwogIGNvbW1hbmRzOgogIC0gZ28gZ2V0CiAgLSBn\nbyB0ZXN0\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(21, '21.Go (with Modules)', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGdvbGFuZwogIGNvbW1hbmRzOgogIC0gZ28gdGVzdAogIC0gZ28g\nYnVpbGQ=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(22, 'Gradle', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGdyYWRsZTpqZGsxMAogIGNvbW1hbmRzOgogIC0gZ3JhZGxlIGFz\nc2VtYmxlCiAgLSBncmFkbGUgY2hlY2s=\n', 0, '2020-10-21 10:14:22', '2020-11-26 01:36:17', 351689), -(23, 'Groovy', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGdyYWRsZToyLjUtamRrOAogIGNvbW1hbmRzOgogIC0gLi9ncmFk\nbGV3IGFzc2VtYmxlCiAgLSAuL2dyYWRsZXcgY2hlY2s=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(24, 'Haskell', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGhhc2tlbGwKICBjb21tYW5kczoKICAtIGNhYmFsIGluc3RhbGwg\nLS1vbmx5LWRlcGVuZGVuY2llcyAtLWVuYWJsZS10ZXN0cwogIC0gY2FiYWwg\nY29uZmlndXJlIC0tZW5hYmxlLXRlc3RzCiAgLSBjYWJhbCBidWlsZAogIC0g\nY2FiYWwgdGVzdA==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(25, 'Haxe', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGhheGUKICBjb21tYW5kczoKICAtIGhheGVsaWIgaW5zdGFsbCBi\ndWlsZC5oeG1sCiAgLSBoYXhlIGJ1aWxkLmh4bWw=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(26, 'MariaDB', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IG1hcmlhZGIKICBjb21tYW5kczoKICAtIHNsZWVwIDE1CiAgLSBt\neXNxbCAtdSByb290IC1oIGRhdGFiYXNlIC0tZXhlY3V0ZT0nU0VMRUNUIFZF\nUlNJT04oKTsnCgpzZXJ2aWNlczoKLSBuYW1lOiBkYXRhYmFzZQogIGltYWdl\nOiBtYXJpYWRiCiAgZW52aXJvbm1lbnQ6CiAgICBNWVNRTF9BTExPV19FTVBU\nWV9QQVNTV09SRDogJ3llcycKICAgIE1ZU1FMX0RBVEFCQVNFOiB0ZXN0\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(27, 'Maven', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IG1hdmVuOjMtamRrLTEwCiAgY29tbWFuZHM6CiAgLSBtdm4gaW5z\ndGFsbCAtRHNraXBUZXN0cz10cnVlIC1EbWF2ZW4uamF2YWRvYy5za2lwPXRy\ndWUgLUIgLVYKICAtIG12biB0ZXN0IC1C\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(28, 'Memcached', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHVidW50dQogIGNvbW1hbmRzOgogIC0gYXB0LWdldCB1cGRhdGUg\nLXFxCiAgLSBhcHQtZ2V0IGluc3RhbGwgLXkgLXFxIHRlbG5ldCA+IC9kZXYv\nbnVsbAogIC0gKHNsZWVwIDE7IGVjaG8gJ3N0YXRzJzsgc2xlZXAgMjsgZWNo\nbyAncXVpdCc7KSB8IHRlbG5ldCBjYWNoZSAxMTIxMSB8fCB0cnVlCgpzZXJ2\naWNlczoKLSBuYW1lOiBjYWNoZQogIGltYWdlOiBtZW1jYWNoZWQ6YWxwaW5l\nCiAgY29tbWFuZDogWyAtdnYgXQ==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(29, 'Nats', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHJ1Ynk6MgogIGNvbW1hbmRzOgogIC0gZ2VtIGluc3RhbGwgbmF0\ncwogIC0gbmF0cy1wdWIgLXMgdGNwOi8vbmF0czo0MjIyIGdyZWV0aW5nICdo\nZWxsbycKICAtIG5hdHMtcHViIC1zIHRjcDovL25hdHM6NDIyMiBncmVldGlu\nZyAnd29ybGQnCgpzZXJ2aWNlczoKLSBuYW1lOiBuYXRzCiAgaW1hZ2U6IG5h\ndHM6MS4zLjA=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(30, 'Node', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IG5vZGUKICBjb21tYW5kczoKICAtIG5wbSBpbnN0YWxsCiAgLSBu\ncG0gdGVzdA==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(31, 'Perl', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHBlcmwKICBjb21tYW5kczoKICAtIGNwYW5tIC0tcXVpZXQgLS1p\nbnN0YWxsZGVwcyAtLW5vdGVzdCAuCiAgLSBwZXJsIEJ1aWxkLlBMCiAgLSAu\nL0J1aWxkIHRlc3Q=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(32, 'Postgres', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHBvc3RncmVzOjktYWxwaW5lCiAgY29tbWFuZHM6CiAgLSBwc3Fs\nIC1VIHBvc3RncmVzIC1kIHRlc3QgLWggZGF0YWJhc2UKCnNlcnZpY2VzOgot\nIG5hbWU6IGRhdGFiYXNlCiAgaW1hZ2U6IHBvc3RncmVzOjktYWxwaW5lCiAg\nZW52aXJvbm1lbnQ6CiAgICBQT1NUR1JFU19VU0VSOiBwb3N0Z3JlcwogICAg\nUE9TVEdSRVNfREI6IHRlc3Q=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(33, 'Redis', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHJlZGlzCiAgY29tbWFuZHM6CiAgLSBzbGVlcCA1CiAgLSByZWRp\ncy1jbGkgLWggcmVkaXMgcGluZwogIC0gcmVkaXMtY2xpIC1oIHJlZGlzIHNl\ndCBGT08gYmFyCiAgLSByZWRpcy1jbGkgLWggcmVkaXMgZ2V0IEZPTwoKc2Vy\ndmljZXM6Ci0gbmFtZTogcmVkaXMKICBpbWFnZTogcmVkaXM=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(34, 'RethinkDB', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IG5vZGU6OQogIGNvbW1hbmRzOgogIC0gbnBtIGluc3RhbGwgLXMg\nLWcgcmVjbGkKICAtIHJlY2xpIC1oIGRhdGFiYXNlIC1qICdyLmRiKCdyZXRo\naW5rZGInKS50YWJsZSgnc3RhdHMnKScKCnNlcnZpY2VzOgotIG5hbWU6IGRh\ndGFiYXNlCiAgaW1hZ2U6IHJldGhpbmtkYjoyCiAgY29tbWFuZDogWyByZXRo\naW5rZGIsIC0tYmluZCwgYWxsIF0=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(35, 'Rust', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHJ1c3Q6MS4zMAogIGNvbW1hbmRzOgogIC0gY2FyZ28gYnVpbGQg\nLS12ZXJib3NlIC0tYWxsCiAgLSBjYXJnbyB0ZXN0IC0tdmVyYm9zZSAtLWFs\nbA==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(36, 'Swift', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHN3aWZ0OjQKICBjb21tYW5kczoKICAtIHN3aWZ0IGJ1aWxkCiAg\nLSBzd2lmdCB0ZXN0\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(37, 'Vault', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHZhdWx0OjEuMC4wLWJldGEyCiAgZW52aXJvbm1lbnQ6CiAgICBW\nQVVMVF9BRERSOiBodHRwOi8vdmF1bHQ6ODIwMAogICAgVkFVTFRfVE9LRU46\nIGR1bW15CiBjb21tYW5kczoKIC0gc2xlZXAgNQogLSB2YXVsdCBrdiBwdXQg\nc2VjcmV0L215LXNlY3JldCBteS12YWx1ZT1zM2NyM3QKIC0gdmF1bHQga3Yg\nZ2V0IHNlY3JldC9teS1zZWNyZXQKCnNlcnZpY2VzOgotIG5hbWU6IHZhdWx0\nCiAgaW1hZ2U6IHZhdWx0OjEuMC4wLWJldGEyCiAgZW52aXJvbm1lbnQ6CiAg\nICBWQVVMVF9ERVZfUk9PVF9UT0tFTl9JRDogZHVtbXk=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL); -COMMIT; - --- ---------------------------- --- Records of ci_templates --- ---------------------------- -BEGIN; -INSERT INTO `ci_templates` (`id`, `template_name`, `stage_type`, `category`, `content`, `created_at`, `updated_at`, `parent_category`, `login`) VALUES -(2, 'linux/amd64', 'init', '初始化', 'kind: pipeline\r\ntype: docker\r\nname: {name}\r\nplatform:\r\n os: linux\r\n arch: amd64', '2021-01-12 02:44:23', '2021-02-02 10:51:36', '初始化', 'admin'), -(3, 'linux/arm64', 'init', '初始化', 'kind: pipeline\r\ntype: docker\r\nname: {name}\r\nplatform:\r\n os: linux\r\n arch: arm64', '2021-01-12 02:45:17', '2021-02-02 10:51:47', '初始化', 'admin'), -(4, 'maven', 'build', 'Java', '- name: maven\r\n image: maven:3-jdk-10\r\n commands:\r\n - mvn install -DskipTests=true', '2021-01-12 02:53:29', '2021-01-12 02:53:29', '编译构建', 'admin'), -(5, 'maven单元测试', 'customize', 'Java', '- name: maven\r\n image: maven:3-jdk-10\r\n commands:\r\n - mvn test', '2021-01-12 02:53:29', '2021-01-12 02:53:29', '单元测试', 'admin'), -(6, 'golang单元测试', 'customize', 'Golang', '- name: golang单元测试\r\n image: golang\r\n commands:\r\n - go test', '2021-01-12 03:03:35', '2021-01-12 03:03:35', '单元测试', 'admin'), -(8, 'gradle', 'build', 'Java', '- name: gradle\r\n image: gradle:jdk10\r\n commands:\r\n - gradle build -x test', '2021-01-12 03:05:33', '2021-01-12 03:05:33', '编译构建', 'admin'), -(9, 'gradle单元测试', 'customize', 'Java', '- name: gradle\r\n image: gradle:jdk10\r\n commands:\r\n - gradle test', '2021-01-12 03:05:33', '2021-01-12 03:05:33', '单元测试', 'admin'), -(10, '远程主机部署', 'deploy', '部署', '# 需要将软件包与部署脚本提前上传到远程主机(见文件上传模板)\r\n# host、username、password可在参数管理中配置\r\n- name: 远程主机部署\r\n image: appleboy/drone-ssh\r\n settings:\r\n host: \r\n from_secret: ip\r\n username: \r\n from_secret: name\r\n password: \r\n from_secret: pwd\r\n port: 22\r\n script:\r\n - chmod +x /home/deploy.sh\r\n - ./home/deploy.sh', '2021-01-12 03:32:46', '2021-03-05 06:22:02', '部署', 'admin'), -(11, '远程命令', 'customize', '其他', '# host、username、password可在参数管理中配置\r\n- name: 远程命令\r\n image: appleboy/drone-ssh\r\n settings:\r\n host: \r\n from_secret: ip\r\n username: \r\n from_secret: name\r\n password: \r\n from_secret: pwd\r\n port: 22\r\n script:\r\n - echo ''hello world!''', '2021-01-12 03:40:38', '2021-03-05 06:19:44', '其他', 'admin'), -(12, '上传文件', 'customize', '其他', '# 本模板示例为上传软件包和部署脚本到home目录\r\n# host、username、password可在参数管理中配置\r\n- name: 上传文件\r\n image: appleboy/drone-scp\r\n settings:\r\n host: \r\n from_secret: ip\r\n username: \r\n from_secret: name\r\n password: \r\n from_secret: pwd\r\n port: 22\r\n target: /home\r\n source: \r\n - target/*.jar\r\n - deploy.sh', '2021-01-12 03:40:55', '2021-03-05 06:22:22', '其他', 'admin'), -(17, 'make-c', 'build', 'C', '- name: 编译\r\n image: gcc\r\n commands:\r\n - ./configure\r\n - make', '2021-01-15 01:19:38', '2021-02-02 10:52:15', '编译构建', 'admin'), -(19, 'make-c++', 'build', 'C++', '- name: 编译构建\r\n image: gcc\r\n commands:\r\n - ./configure\r\n - make', '2021-01-15 01:21:05', '2021-01-15 01:21:05', '编译构建', 'admin'), -(20, 'python', 'build', 'Python', '- name: 编译构建\r\n image: python\r\n commands:\r\n - pip install -r requirements.txt', '2021-01-15 01:22:36', '2021-01-15 01:22:36', '编译构建', 'admin'), -(21, 'Docker', 'build', 'Docker', '# 构建Docker镜像并推送到仓库\r\n# 定义镜像Hub路径以及账号密码\r\n- name: Docker镜像构建\r\n image: plugins/docker\r\n settings:\r\n username: username\r\n password: pwd\r\n repo: repoUrl\r\n tags: latest', '2021-01-15 01:23:16', '2021-02-03 03:40:49', '编译构建', 'admin'), -(22, '空白模板', 'customize', 'customize', '', '2021-01-15 02:53:02', '2021-01-15 02:53:02', '其他', 'admin'), -(25, 'Go (with Gopath)', 'build', 'Go', '- name: golang\r\n image: golang\r\n commands:\r\n - go get\r\n - go test', '2021-02-03 00:57:32', '2021-02-03 03:36:15', '编译构建', 'admin'), -(26, 'PHP', 'build', 'PHP', '- name: install\r\n image: composer\r\n commands:\r\n - composer install', '2021-02-03 00:59:15', '2021-02-03 00:59:15', '编译构建', 'admin'), -(27, 'Ruby', 'build', 'Ruby', '- name: ruby\r\n image: ruby\r\n commands:\r\n - bundle install --jobs=3 --retry=3\r\n - rake', '2021-02-03 00:59:52', '2021-02-03 00:59:52', '编译构建', 'admin'), -(29, 'Go (with Modules)', 'build', 'Go', '- name: test\r\n image: golang\r\n commands:\r\n - go test\r\n - go build', '2021-02-03 03:35:45', '2021-02-03 03:35:45', '编译构建', 'admin'), -(30, 'Node', 'build', 'Node', '- name: Node编译\r\n image: node\r\n commands:\r\n - npm install\r\n - npm test', '2021-02-03 03:37:31', '2021-02-03 03:37:31', '编译构建', 'admin'), -(31, 'Perl ', 'build', 'Perl', '- name: perl\r\n image: perl\r\n commands:\r\n - cpanm --quiet --installdeps --notest .\r\n - perl Build.PL\r\n - ./Build test', '2021-02-03 03:38:06', '2021-02-03 03:38:06', '编译构建', 'admin'), -(32, 'Rust ', 'build', 'Rust', '- name: rust\r\n image: rust:1.30\r\n commands:\r\n - cargo build --verbose --all\r\n - cargo test --verbose --all', '2021-02-03 03:38:37', '2021-02-03 03:38:37', '编译构建', 'admin'), -(33, 'test', 'init', '初始化', 'qqqq', '2021-02-04 09:02:42', '2021-02-04 09:02:42', '初始化', 'admin'); -COMMIT; diff --git a/lib/tasks/sync_table_structure.rake b/lib/tasks/sync_table_structure.rake index 026d5214..4cf5f891 100644 --- a/lib/tasks/sync_table_structure.rake +++ b/lib/tasks/sync_table_structure.rake @@ -18,4 +18,22 @@ namespace :sync_table_structure do puts "init success" end + + task data: :environment do + puts "init table data......." + + database_config = Rails.configuration.database_configuration + + database = database_config[Rails.env]["database"] + database_username = database_config[Rails.env]["username"] + database_password = database_config[Rails.env]["password"] + database_host = database_config[Rails.env]["host"] + database_port = database_config[Rails.env]["port"] || 3306 + + puts "bash: mysql -u#{database_username} -p#{database_password} -P#{database_port} -h#{database_host} #{database}" + + system "mysql -u#{database_username} -p#{database_password} -P#{database_port} -h#{database_host} #{database} < #{Rails.root}/db/init_data.sql" + + puts "init success" + end end diff --git a/public/docs/api.html b/public/docs/api.html index f970ea84..5061a1ac 100644 --- a/public/docs/api.html +++ b/public/docs/api.html @@ -331,6 +331,36 @@
  • 获取当前登陆用户信息
  • +
  • + 更改用户信息 +
  • +
  • + 获取用户星标项目 +
  • +
  • + 用户添加星标项目 +
  • +
  • + 星标项目展示排序 +
  • +
  • + 用户近期活动统计 +
  • +
  • + 获取用户贡献度 +
  • +
  • + 获取用户动态 +
  • +
  • + 用户开发能力 +
  • +
  • + 用户角色定位 +
  • +
  • + 用户专业定位 +
  • 待办事项-用户通知信息
  • @@ -343,11 +373,23 @@
  • 用户拒绝迁移
  • +
  • + 待办事项-项目申请 +
  • +
  • + 用户接受申请 +
  • +
  • + 用户拒绝申请 +
  • Projects