| @@ -1,5 +1,22 @@ | |||||
| # Changelog | # Changelog | ||||
| ## [v3.0.3](https://forgeplus.trustie.net/projects/jasder/forgeplus/releases) - 2021-05-08 | |||||
| * BUGFIXES | |||||
| * Fix 解决易修标题过长导致的排版问题(45469) | |||||
| * Fix 解决合并请求详情页面排版错误的问题(45457) | |||||
| * FIX 解决转移仓库界面专有名词描述错误的问题(45455) | |||||
| * Fix 解决markdown格式文件自动生成数字排序的问题(45454) | |||||
| * Fix 解决镜像项目源地址不显示的问题(45403) | |||||
| * Fix 解决镜像项目导航显示错误问题(45398) | |||||
| * Fix 解决其他相关bug | |||||
| * ENHANCEMENTS | |||||
| * UPDATE 用户注册时,账号和密码正则匹配调整(45336) (45318) (45290) | |||||
| * ADD 创建组织各属性添加规则匹配功能(45313) (45289) | |||||
| * ADD 创建团建各属性添加规则匹配功能(45334) (45325) (45287) | |||||
| * ADD 仓库转移功能(45017) (45015) | |||||
| ## [v3.0.2](https://forgeplus.trustie.net/projects/jasder/forgeplus/releases) - 2021-04-23 | ## [v3.0.2](https://forgeplus.trustie.net/projects/jasder/forgeplus/releases) - 2021-04-23 | ||||
| * BUGFIXES | * BUGFIXES | ||||
| @@ -169,6 +169,7 @@ class AccountsController < ApplicationController | |||||
| # 用户登录 | # 用户登录 | ||||
| def login | def login | ||||
| Users::LoginForm.new(account_params).validate! | |||||
| @user = User.try_to_login(params[:login], params[:password]) | @user = User.try_to_login(params[:login], params[:password]) | ||||
| return normal_status(-2, "错误的账号或密码") if @user.blank? | return normal_status(-2, "错误的账号或密码") if @user.blank? | ||||
| @@ -345,4 +346,7 @@ class AccountsController < ApplicationController | |||||
| params.require(:user).permit(:login, :email, :phone) | params.require(:user).permit(:login, :email, :phone) | ||||
| end | end | ||||
| def account_params | |||||
| params.require(:account).permit(:login, :password) | |||||
| end | |||||
| end | end | ||||
| @@ -101,51 +101,46 @@ class IssuesController < ApplicationController | |||||
| end | end | ||||
| def create | def create | ||||
| if params[:subject].blank? | |||||
| normal_status(-1, "标题不能为空") | |||||
| elsif params[:subject].to_s.size > 255 | |||||
| normal_status(-1, "标题不能超过255个字符") | |||||
| else | |||||
| issue_params = issue_send_params(params) | |||||
| @issue = Issue.new(issue_params) | |||||
| if @issue.save! | |||||
| if params[:attachment_ids].present? | |||||
| params[:attachment_ids].each do |id| | |||||
| attachment = Attachment.select(:id, :container_id, :container_type)&.find_by_id(id) | |||||
| unless attachment.blank? | |||||
| attachment.container = @issue | |||||
| attachment.author_id = current_user.id | |||||
| attachment.description = "" | |||||
| attachment.save | |||||
| end | |||||
| end | |||||
| end | |||||
| if params[:issue_tag_ids].present? | |||||
| params[:issue_tag_ids].each do |tag| | |||||
| IssueTagsRelate.create!(issue_id: @issue.id, issue_tag_id: tag) | |||||
| issue_params = issue_send_params(params) | |||||
| Issues::CreateForm.new({subject:issue_params[:subject]}).validate! | |||||
| @issue = Issue.new(issue_params) | |||||
| if @issue.save! | |||||
| if params[:attachment_ids].present? | |||||
| params[:attachment_ids].each do |id| | |||||
| attachment = Attachment.select(:id, :container_id, :container_type)&.find_by_id(id) | |||||
| unless attachment.blank? | |||||
| attachment.container = @issue | |||||
| attachment.author_id = current_user.id | |||||
| attachment.description = "" | |||||
| attachment.save | |||||
| end | end | ||||
| end | end | ||||
| if params[:assigned_to_id].present? | |||||
| Tiding.create!(user_id: params[:assigned_to_id], trigger_user_id: current_user.id, | |||||
| container_id: @issue.id, container_type: 'Issue', | |||||
| parent_container_id: @project.id, parent_container_type: "Project", | |||||
| tiding_type: 'issue', status: 0) | |||||
| end | |||||
| #为悬赏任务时, 扣除当前用户的积分 | |||||
| if params[:issue_type].to_s == "2" | |||||
| post_to_chain("minus", params[:token].to_i, current_user.try(:login)) | |||||
| end | |||||
| if params[:issue_tag_ids].present? | |||||
| params[:issue_tag_ids].each do |tag| | |||||
| IssueTagsRelate.create!(issue_id: @issue.id, issue_tag_id: tag) | |||||
| end | end | ||||
| end | |||||
| if params[:assigned_to_id].present? | |||||
| Tiding.create!(user_id: params[:assigned_to_id], trigger_user_id: current_user.id, | |||||
| container_id: @issue.id, container_type: 'Issue', | |||||
| parent_container_id: @project.id, parent_container_type: "Project", | |||||
| tiding_type: 'issue', status: 0) | |||||
| end | |||||
| @issue.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create") | |||||
| render json: {status: 0, message: "创建成", id: @issue.id} | |||||
| else | |||||
| normal_status(-1, "创建失败") | |||||
| #为悬赏任务时, 扣除当前用户的积分 | |||||
| if params[:issue_type].to_s == "2" | |||||
| post_to_chain("minus", params[:token].to_i, current_user.try(:login)) | |||||
| end | end | ||||
| @issue.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create") | |||||
| render json: {status: 0, message: "创建成", id: @issue.id} | |||||
| else | |||||
| normal_status(-1, "创建失败") | |||||
| end | end | ||||
| rescue Exception => exception | |||||
| puts exception.message | |||||
| normal_status(-1, exception.message) | |||||
| end | end | ||||
| def edit | def edit | ||||
| @@ -199,7 +194,7 @@ class IssuesController < ApplicationController | |||||
| normal_status(-1, "不允许修改为关闭状态") | normal_status(-1, "不允许修改为关闭状态") | ||||
| else | else | ||||
| issue_params = issue_send_params(params).except(:issue_classify, :author_id, :project_id) | issue_params = issue_send_params(params).except(:issue_classify, :author_id, :project_id) | ||||
| Issues::UpdateForm.new({subject:issue_params[:subject]}).validate! | |||||
| if @issue.update_attributes(issue_params) | if @issue.update_attributes(issue_params) | ||||
| if params[:status_id].to_i == 5 #任务由非关闭状态到关闭状态时 | if params[:status_id].to_i == 5 #任务由非关闭状态到关闭状态时 | ||||
| @issue.issue_times.update_all(end_time: Time.now) | @issue.issue_times.update_all(end_time: Time.now) | ||||
| @@ -225,6 +220,9 @@ class IssuesController < ApplicationController | |||||
| normal_status(-1, "更新失败") | normal_status(-1, "更新失败") | ||||
| end | end | ||||
| end | end | ||||
| rescue Exception => exception | |||||
| puts exception.message | |||||
| normal_status(-1, exception.message) | |||||
| end | end | ||||
| def show | def show | ||||
| @@ -36,6 +36,7 @@ class Organizations::OrganizationsController < Organizations::BaseController | |||||
| def update | def update | ||||
| ActiveRecord::Base.transaction do | ActiveRecord::Base.transaction do | ||||
| Organizations::CreateForm.new(organization_params).validate! | |||||
| login = @organization.login | login = @organization.login | ||||
| @organization.login = organization_params[:name] if organization_params[:name].present? | @organization.login = organization_params[:name] if organization_params[:name].present? | ||||
| @organization.nickname = organization_params[:nickname] if organization_params[:nickname].present? | @organization.nickname = organization_params[:nickname] if organization_params[:nickname].present? | ||||
| @@ -43,6 +43,7 @@ class Organizations::TeamsController < Organizations::BaseController | |||||
| end | end | ||||
| def update | def update | ||||
| Organizations::CreateTeamForm.new(team_params).validate! | |||||
| @team = Organizations::Teams::UpdateService.call(current_user, @team, team_params) | @team = Organizations::Teams::UpdateService.call(current_user, @team, team_params) | ||||
| rescue Exception => e | rescue Exception => e | ||||
| uid_logger_error(e.message) | uid_logger_error(e.message) | ||||
| @@ -106,7 +106,7 @@ class ProjectsController < ApplicationController | |||||
| def update | def update | ||||
| ActiveRecord::Base.transaction do | ActiveRecord::Base.transaction do | ||||
| # Projects::CreateForm.new(project_params).validate! | |||||
| Projects::UpdateForm.new(project_params).validate! | |||||
| private = params[:private] || false | private = params[:private] || false | ||||
| new_project_params = project_params.except(:private).merge(is_public: !private) | new_project_params = project_params.except(:private).merge(is_public: !private) | ||||
| @@ -167,7 +167,7 @@ class ProjectsController < ApplicationController | |||||
| end | end | ||||
| def recommend | def recommend | ||||
| @projects = Project.recommend.includes(:repository, :project_category, :owner).limit(5) | |||||
| @projects = Project.recommend.includes(:repository, :project_category, :owner).order(id: :desc).limit(5) | |||||
| end | end | ||||
| def about | def about | ||||
| @@ -0,0 +1,11 @@ | |||||
| class Issues::CreateForm | |||||
| include ActiveModel::Model | |||||
| attr_accessor :subject | |||||
| validates :subject, presence: { message: "不能为空" } | |||||
| validates :subject, length: { maximum: 80, too_long: "不能超过80个字符" } | |||||
| end | |||||
| @@ -0,0 +1,10 @@ | |||||
| class Issues::UpdateForm | |||||
| include ActiveModel::Model | |||||
| attr_accessor :subject | |||||
| validates :subject, presence: { message: "不能为空" } | |||||
| validates :subject, length: { maximum: 80, too_long: "不能超过80个字符" } | |||||
| end | |||||
| @@ -3,6 +3,9 @@ class Organizations::CreateForm < BaseForm | |||||
| attr_accessor :name, :description, :website, :location, :repo_admin_change_team_access, :visibility, :max_repo_creation, :nickname | attr_accessor :name, :description, :website, :location, :repo_admin_change_team_access, :visibility, :max_repo_creation, :nickname | ||||
| validates :name, :nickname, :visibility, presence: true | validates :name, :nickname, :visibility, presence: true | ||||
| validates :name, :nickname, length: { maximum: 100 } | |||||
| validates :location, length: { maximum: 50 } | |||||
| validates :description, length: { maximum: 200 } | |||||
| validates :name, format: { with: NAME_REGEX, multiline: true, message: "只能含有数字、字母、下划线且不能以下划线开头和结尾" } | validates :name, format: { with: NAME_REGEX, multiline: true, message: "只能含有数字、字母、下划线且不能以下划线开头和结尾" } | ||||
| end | end | ||||
| @@ -2,7 +2,9 @@ class Organizations::CreateTeamForm < BaseForm | |||||
| NAME_REGEX = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]+$/ #只含有数字、字母、下划线不能以下划线开头和结尾 | NAME_REGEX = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]+$/ #只含有数字、字母、下划线不能以下划线开头和结尾 | ||||
| attr_accessor :name, :nickname, :description, :authorize, :includes_all_project, :can_create_org_project, :unit_types | attr_accessor :name, :nickname, :description, :authorize, :includes_all_project, :can_create_org_project, :unit_types | ||||
| validates :name, :nickname, :authorize, presence: true | |||||
| validates :name, :nickname, presence: true | |||||
| validates :name, :nickname, length: { maximum: 100 } | |||||
| validates :description, length: { maximum: 200 } | |||||
| validates :name, format: { with: NAME_REGEX, multiline: true, message: "只能含有数字、字母、下划线且不能以下划线开头和结尾" } | validates :name, format: { with: NAME_REGEX, multiline: true, message: "只能含有数字、字母、下划线且不能以下划线开头和结尾" } | ||||
| end | end | ||||
| @@ -2,11 +2,15 @@ class Projects::CreateForm < BaseForm | |||||
| REPOSITORY_NAME_REGEX = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]+$/ #只含有数字、字母、下划线不能以下划线开头和结尾 | REPOSITORY_NAME_REGEX = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]+$/ #只含有数字、字母、下划线不能以下划线开头和结尾 | ||||
| attr_accessor :user_id, :name, :description, :repository_name, :project_category_id, | attr_accessor :user_id, :name, :description, :repository_name, :project_category_id, | ||||
| :project_language_id, :ignore_id, :license_id, :private, :owner | :project_language_id, :ignore_id, :license_id, :private, :owner | ||||
| validates :user_id, :name, :description,:repository_name, | validates :user_id, :name, :description,:repository_name, | ||||
| :project_category_id, :project_language_id, presence: true | :project_category_id, :project_language_id, presence: true | ||||
| validates :repository_name, format: { with: REPOSITORY_NAME_REGEX, multiline: true, message: "只能含有数字、字母、下划线且不能以下划线开头和结尾" } | validates :repository_name, format: { with: REPOSITORY_NAME_REGEX, multiline: true, message: "只能含有数字、字母、下划线且不能以下划线开头和结尾" } | ||||
| validates :name, length: { maximum: 50 } | |||||
| validates :repository_name, length: { maximum: 100 } | |||||
| validates :description, length: { maximum: 200 } | |||||
| validate :check_ignore, :check_license, :check_owner, :check_max_repo_creation | validate :check_ignore, :check_license, :check_owner, :check_max_repo_creation | ||||
| validate do | validate do | ||||
| check_project_category(project_category_id) | check_project_category(project_category_id) | ||||
| @@ -1,4 +1,11 @@ | |||||
| class Projects::UpdateForm < BaseForm | class Projects::UpdateForm < BaseForm | ||||
| attr_reader :name, :description, :repository_name, :project_category_id | |||||
| attr_accessor :name, :description, :project_category_id, :project_language_id, :private | |||||
| validates :name, :description, :project_category_id, :project_language_id, presence: true | |||||
| validates :name, length: { maximum: 50 } | |||||
| validates :description, length: { maximum: 200 } | |||||
| validate do | |||||
| check_project_category(project_category_id) | |||||
| check_project_language(project_language_id) | |||||
| end | |||||
| end | end | ||||
| @@ -0,0 +1,8 @@ | |||||
| class Users::LoginForm | |||||
| include ActiveModel::Model | |||||
| attr_accessor :password, :login | |||||
| validates :login, presence: true | |||||
| validates :password, presence: true, length: { minimum: 8, maximum: 16 }, format: { with: CustomRegexp::PASSWORD, message: "8~16位,支持字母数字和符号" } | |||||
| end | |||||
| @@ -41,7 +41,7 @@ module ProjectsHelper | |||||
| tmp_json = tmp_json.merge({ | tmp_json = tmp_json.merge({ | ||||
| mirror_status: repo.mirror_status, | mirror_status: repo.mirror_status, | ||||
| mirror_num: repo.mirror_num, | mirror_num: repo.mirror_num, | ||||
| mirror_url: repo.source_clone_url || repo.mirror_url, | |||||
| mirror_url: repo.remote_mirror_url, | |||||
| first_sync: repo.first_sync? | first_sync: repo.first_sync? | ||||
| }) | }) | ||||
| end | end | ||||
| @@ -20,13 +20,16 @@ class ProjectUnit < ApplicationRecord | |||||
| validates :unit_type, uniqueness: { scope: :project_id} | validates :unit_type, uniqueness: { scope: :project_id} | ||||
| def self.init_types(project_id) | |||||
| ProjectUnit::unit_types.each do |_, v| | |||||
| def self.init_types(project_id, project_type='common') | |||||
| unit_types = project_type == 'sync_mirror' ? ProjectUnit::unit_types.except("pulls") : ProjectUnit::unit_types | |||||
| unit_types.each do |_, v| | |||||
| self.create!(project_id: project_id, unit_type: v) | self.create!(project_id: project_id, unit_type: v) | ||||
| end | end | ||||
| end | end | ||||
| def self.update_by_unit_types!(project, types) | def self.update_by_unit_types!(project, types) | ||||
| # 同步镜像项目不能有合并请求模块 | |||||
| types.delete("pulls") if project.sync_mirror? | |||||
| # 默认code类型自动创建 | # 默认code类型自动创建 | ||||
| types << "code" | types << "code" | ||||
| project.project_units.where.not(unit_type: types).each(&:destroy!) | project.project_units.where.not(unit_type: types).each(&:destroy!) | ||||
| @@ -78,4 +78,9 @@ class Repository < ApplicationRecord | |||||
| end | end | ||||
| end | end | ||||
| def remote_mirror_url | |||||
| source_clone_url.blank? ? mirror_url : source_clone_url | |||||
| end | |||||
| end | end | ||||
| @@ -33,9 +33,10 @@ class Team < ApplicationRecord | |||||
| enum authorize: {common: 0, read: 1, write: 2, admin: 3, owner: 4} | enum authorize: {common: 0, read: 1, write: 2, admin: 3, owner: 4} | ||||
| def self.build(organization_id, name, description, authorize, includes_all_project, can_create_org_project) | |||||
| def self.build(organization_id, name, nickname, description, authorize, includes_all_project, can_create_org_project) | |||||
| self.create!(organization_id: organization_id, | self.create!(organization_id: organization_id, | ||||
| name: name, | name: name, | ||||
| nickname: nickname, | |||||
| description: description, | description: description, | ||||
| authorize: authorize, | authorize: authorize, | ||||
| includes_all_project: includes_all_project, | includes_all_project: includes_all_project, | ||||
| @@ -54,7 +54,7 @@ class Organizations::CreateService < ApplicationService | |||||
| end | end | ||||
| def create_owner_info | def create_owner_info | ||||
| @owner_team = Team.build(organization.id, "Owners", "", 4, true, true) | |||||
| @owner_team = Team.build(organization.id, "Owners", "Owner团队", "", 4, true, true) | |||||
| TeamUnit.unit_types.keys.each do |u_type| | TeamUnit.unit_types.keys.each do |u_type| | ||||
| TeamUnit.build(organization.id, owner_team.id, u_type) | TeamUnit.build(organization.id, owner_team.id, u_type) | ||||
| end | end | ||||
| @@ -28,6 +28,10 @@ class Organizations::Teams::CreateService < ApplicationService | |||||
| params[:name] | params[:name] | ||||
| end | end | ||||
| def nickname | |||||
| params[:nickname] | |||||
| end | |||||
| def description | def description | ||||
| params[:description] | params[:description] | ||||
| end | end | ||||
| @@ -45,7 +49,7 @@ class Organizations::Teams::CreateService < ApplicationService | |||||
| end | end | ||||
| def create_team | def create_team | ||||
| @team = Team.build(org.id, name, description, authorize, | |||||
| @team = Team.build(org.id, name, nickname, description, authorize, | |||||
| includes_all_project, can_create_org_project) | includes_all_project, can_create_org_project) | ||||
| end | end | ||||
| @@ -10,7 +10,7 @@ class Projects::MigrateService < ApplicationService | |||||
| def call | def call | ||||
| @project = Project.new(project_params) | @project = Project.new(project_params) | ||||
| if @project.save! | if @project.save! | ||||
| ProjectUnit.init_types(@project.id) | |||||
| ProjectUnit.init_types(@project.id, project.project_type) | |||||
| Project.update_mirror_projects_count! | Project.update_mirror_projects_count! | ||||
| @project.set_owner_permission(user) | @project.set_owner_permission(user) | ||||
| Repositories::MigrateService.new(user, @project, repository_params).call | Repositories::MigrateService.new(user, @project, repository_params).call | ||||
| @@ -80,7 +80,7 @@ json.contributors do | |||||
| total_count = @result[:contributor].size | total_count = @result[:contributor].size | ||||
| json.list @result[:contributor].each do |contributor| | json.list @result[:contributor].each do |contributor| | ||||
| user = User.find_by(gitea_uid: contributor["id"]) | user = User.find_by(gitea_uid: contributor["id"]) | ||||
| if contributor["login"] == "root" | |||||
| if contributor["login"] == "root" || user.nil? | |||||
| total_count -= 1 | total_count -= 1 | ||||
| next | next | ||||
| end | end | ||||
| @@ -0,0 +1,7 @@ | |||||
| 'zh-CN': | |||||
| activemodel: | |||||
| attributes: | |||||
| issues/create_form: | |||||
| subject: 标题 | |||||
| issues/update_form: | |||||
| subject: 标题 | |||||
| @@ -0,0 +1,9 @@ | |||||
| 'zh-CN': | |||||
| activemodel: | |||||
| attributes: | |||||
| organizations/create_form: | |||||
| name: 组织账号 | |||||
| nickname: 组织名称 | |||||
| location: 组织所在地区 | |||||
| description: 组织简介 | |||||
| visibility: 组织可见性 | |||||
| @@ -0,0 +1,7 @@ | |||||
| 'zh-CN': | |||||
| activemodel: | |||||
| attributes: | |||||
| organizations/create_team_form: | |||||
| name: 团队标识 | |||||
| nickname: 团队名称 | |||||
| description: 团队描述 | |||||
| @@ -0,0 +1,7 @@ | |||||
| 'zh-CN': | |||||
| activemodel: | |||||
| attributes: | |||||
| projects/create_form: | |||||
| name: 项目名称 | |||||
| repository_name: 仓库名称 | |||||
| description: 项目简介 | |||||
| @@ -0,0 +1,8 @@ | |||||
| 'zh-CN': | |||||
| activemodel: | |||||
| attributes: | |||||
| projects/update_form: | |||||
| name: 项目名称 | |||||
| description: 项目简介 | |||||
| project_category_id: 项目类别 | |||||
| project_language_id: 项目语言 | |||||
| @@ -0,0 +1,6 @@ | |||||
| 'zh-CN': | |||||
| activemodel: | |||||
| attributes: | |||||
| users/login_form: | |||||
| login: 用户名 | |||||
| password: 密码 | |||||
| @@ -393,7 +393,6 @@ Rails.application.routes.draw do | |||||
| get :files | get :files | ||||
| get :detail | get :detail | ||||
| get :archive | get :archive | ||||
| get :top_counts | |||||
| get :entries | get :entries | ||||
| match :sub_entries, :via => [:get, :put] | match :sub_entries, :via => [:get, :put] | ||||
| get :commits | get :commits | ||||