diff --git a/README.md b/README.md index 9c50ad421..5ed0d3abf 100644 --- a/README.md +++ b/README.md @@ -809,6 +809,132 @@ curl -X GET http://localhost:3000/api/projects/mirror_demo/branches | jq ``` --- +### 获取版本列表 +``` +GET /api/:login/:repo_identifier/tags +``` +*示例* +``` +curl -X GET http://localhost:3000/api/18816895620/mirror_demo/tags | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +-|-|-|- +|identifier |是|string |项目标识 | + + +*返回参数说明:* + +|参数名|类型|说明| +-|-|- +|name |string|分支名称| +|user_can_push |boolean|用户是否可push| +|user_can_merge |boolean|用户是否客merge| +|protected |boolean|是否为保护分支| +|http_url |boolean|http链接| +|zip_url |boolean|zip包下载链接| +|tar_url |boolean|tar.gz下载链接| +|last_commit |object|最后提交记录| +|-- id |string|提交记录id| +|-- message |string|提交的说明信息| +|-- timestamp |int|提交时间,为UNIX时间戳| +|-- time_from_now|string|转换后的时间| +|author |object|提交用户| +|-- login |string|用户名称| +|-- image_url |string|用户头像| + + +返回值 +``` +[ + { + "name": "develop", + "user_can_push": true, + "user_can_merge": true, + "protected": false, + "http_url": "http://localhost:3003/18816895620/mirror_demo.git", + "zip_url": "http://localhost:3003/18816895620/mirror_demo/develop.zip", + "tar_url": "http://localhost:3003/18816895620/mirror_demo/develop.tar.gz", + "last_commit": { + "id": "735674d6696bddbafa993db9c67b40c41246c77f", + "message": "FIX test branch content\n", + "timestamp": 1577694074, + "time_from_now": "1天前" + }, + "author": { + "login": "18816895620", + "image_url": "avatars/User/b" + } + }, + { + "name": "master", + "user_can_push": true, + "user_can_merge": true, + "protected": false, + "http_url": "http://localhost:3003/18816895620/mirror_demo.git", + "zip_url": "http://localhost:3003/18816895620/mirror_demo/master.zip", + "tar_url": "http://localhost:3003/18816895620/mirror_demo/master.tar.gz", + "last_commit": { + "id": "19ac3bc45f62cc87a94b8ecce61101d8fd2dafd2", + "message": "合并pull request测试\n\n该功能很不错,感谢你的建议\n", + "timestamp": 1577244567, + "time_from_now": "6天前" + }, + "author": { + "login": "18816895620", + "image_url": "avatars/User/b" + } + } +] +``` +--- + +## 仓库详情 +``` +GET /api/:login/:repo_identifier/ +``` +*示例* +``` +curl -X GET \ +http://localhost:3000/api/18816895620/mirror_demo | jq +``` +*请求参数说明:* + +|参数名|必选|类型|说明| +-|-|-|- +|login |是|string |用户标识 | +|repo_identifier |是|string |仓库标识 | + + +*返回参数说明:* + +|参数名|类型|说明| +-|-|- +|identifier |string|仓库标识| +|praises_count |int|点赞数量| +|forked_count |int|fork数量| +|watchers_count |int|关注数量| +|author |object|提交用户| +|-- login |string|用户名称| +|-- image_url |string|用户头像| + + +返回值 +``` +{ + "identifier": "mirror_demo", + "praises_count": 0, + "forked_count": 0, + "watchers_count": 0, + "author": { + "name": "18816895620", + "image_url": "avatars/User/b" + } +} +``` +--- + ## 获取提交记录列表 ``` GET /api/:login/:repo_identifier/commits @@ -951,10 +1077,11 @@ DELETE /api/:login/:repo_identifier/contents ``` *示例* ``` -curl -X DELETE \ --d 'filepath=1' \ --d 'object_type=project' \ -http://localhost:3000/api/118816895620/mirror_demo/contents | jq +curl -X POST \ +-d 'filepath=test_create_file.rb' \ +-d 'branch=master' \ +-d 'content=ZnNmc2FkZg==' \ +http://localhost:3000/api/18816895620/mirror_demo/contents | jq ``` *请求参数说明:* diff --git a/app/assets/javascripts/issue_depends.js b/app/assets/javascripts/issue_depends.js new file mode 100644 index 000000000..dee720fac --- /dev/null +++ b/app/assets/javascripts/issue_depends.js @@ -0,0 +1,2 @@ +// Place all the behaviors and hooks related to the matching controller here. +// All this logic will automatically be available in application.js. diff --git a/app/assets/javascripts/issue_times.js b/app/assets/javascripts/issue_times.js new file mode 100644 index 000000000..dee720fac --- /dev/null +++ b/app/assets/javascripts/issue_times.js @@ -0,0 +1,2 @@ +// Place all the behaviors and hooks related to the matching controller here. +// All this logic will automatically be available in application.js. diff --git a/app/assets/stylesheets/issue_depends.scss b/app/assets/stylesheets/issue_depends.scss new file mode 100644 index 000000000..47eac0077 --- /dev/null +++ b/app/assets/stylesheets/issue_depends.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the issue_depends controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/issue_times.scss b/app/assets/stylesheets/issue_times.scss new file mode 100644 index 000000000..e9c1fafb5 --- /dev/null +++ b/app/assets/stylesheets/issue_times.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the issue_times controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/issue_depends_controller.rb b/app/controllers/issue_depends_controller.rb new file mode 100644 index 000000000..1a194fbb9 --- /dev/null +++ b/app/controllers/issue_depends_controller.rb @@ -0,0 +1,47 @@ +class IssueDependsController < ApplicationController + before_action :require_login + before_action :set_issue + before_action :check_issue_permission + + def create + issue_depend = { + user_id: current_user.id, + depend_issue_id: params[:depend_issue_id].to_i, + issue_id: @issue.id + } + save_issue_depend = IssueDepend.new(issue_depend) + if save_issue_depend.save + @issue.custom_journal_detail("issue_depend","", @issue.id) + normal_status(0, "添加依赖成功") + else + normal_status(0, "添加依赖失败") + end + end + + + def destroy + depend_issue_params = params[:id] + depend_issue = IssueDepend.find(depend_issue_params) + if depend_issue&.destroy + @issue.custom_journal_detail("destroy_issue_depend","", @issue.id) + normal_status(0, "删除依赖成功") + else + normal_status(-1, "删除依赖失败") + end + end + + private + def set_issue + @issue = Issue.find_by_id(params[:issue_id]) + unless @issue.present? + normal_status(-1, "标签不存在") + end + end + + def check_issue_permission + @project = @issue.project + unless @project.member?(current_user) || current_user.admin? + normal_status(-1, "您没有权限") + end + end +end diff --git a/app/controllers/issue_times_controller.rb b/app/controllers/issue_times_controller.rb new file mode 100644 index 000000000..9574f4ad3 --- /dev/null +++ b/app/controllers/issue_times_controller.rb @@ -0,0 +1,55 @@ +class IssueTimesController < ApplicationController + before_action :require_login + before_action :set_issue + before_action :check_issue_permission + + def create + issue_time = { + user_id: current_user.id, + start_time: params[:start_time].to_s.to_time || Time.now, + issue_id: @issue.id + } + save_issue_time = IssueTime.new(issue_time) + if save_issue_time.save + @issue.custom_journal_detail("work_time",save_issue_time.id, "开始工作") + normal_status(0, "开始成功") + else + normal_status(0, "开始失败") + end + end + + def end_work + end_type = params[:end_type].to_i + end_work_time = end_type == 0 ? "" : Time.now + last_work_time = @issue.issue_times.where(user_id: current_user.id, end_time: nil) + Rails.logger.info("######________last_work_time&.last.try(:id)_____###########{last_work_time&.first.try(:id)}") + + if last_work_time.update_all(end_time: end_work_time) + if end_type == 0 + message = "取消时间跟踪" + @issue.custom_journal_detail("cancel_time",last_work_time&.first.try(:id), "取消时间跟踪") + else + message = "停止工作" + @issue.custom_journal_detail("end_time",last_work_time&.first.try(:id), "停止工作") + end + normal_status(0, message) + else + normal_status(0, "操作失败") + end + end + + private + def set_issue + @issue = Issue.find_by_id(params[:issue_id]) + unless @issue.present? + normal_status(-1, "标签不存在") + end + end + + def check_issue_permission + @project = @issue.project + unless @project.member?(current_user) || current_user.admin? + normal_status(-1, "您没有权限") + end + end +end diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index b7068dc0c..5d515b36e 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -1,13 +1,14 @@ class IssuesController < ApplicationController - before_action :require_login + before_action :require_login, except: [:index, :show] before_action :set_project - before_action :check_project_public, only: [:index ,:show, :copy, :index_chosen] - before_action :check_issue_permission, except: [:index, :show, :copy, :index_chosen] - before_action :set_issue, only: [:edit, :update, :destroy, :show, :copy, :index_chosen] + before_action :check_project_public, only: [:index ,:show, :copy, :index_chosen, :close_issue] + before_action :check_issue_permission, except: [:index, :show, :index_chosen] + before_action :set_issue, only: [:edit, :update, :destroy, :show, :copy, :index_chosen, :close_issue, :lock_issue] + + include ApplicationHelper def index issues = @project.issues.includes(:user,:tracker, :priority, :version, :issue_status, :journals) - issues = issues.where(is_private: false) unless current_user.present? && (current_user.admin? || @project.member?(current_user)) @all_issues_size = issues.size @open_issues_size = issues.where.not(status_id: 5).size @@ -245,6 +246,10 @@ class IssuesController < ApplicationController end end + if params[:status_id].to_i == 5 + @issue.issue_times.update_all(end_time: Time.now) + end + @issue.create_journal_detail(change_files, issue_files, issue_file_ids) normal_status(0, "更新成功") else @@ -254,9 +259,19 @@ class IssuesController < ApplicationController end def show + @user_permission = current_user.present? && (!@issue.is_lock || @project.member?(current_user) || current_user.admin? || @issue.user == current_user) @issue_attachments = @issue.attachments @issue_user = @issue.user @issue_assign_to = @issue.get_assign_user + @join_users = join_users(@issue) + #总耗时 + cost_time(@issue) + + #被依赖 + @be_depended_issues_array = be_depended_issues(@issue) + + #依赖于 + depended_issues(@issue) end def destroy @@ -276,6 +291,43 @@ class IssuesController < ApplicationController end end + def close_issue + type = params[:status_id].to_i || 5 + if type == 5 + message = "关闭" + else + message = "重新开启" + end + if @issue.update_attribute(:status_id, type) + if type == 5 + @issue.issue_times.update_all(end_time: Time.now) + end + @issue.create_journal_detail(false, [], []) + normal_status(0, message) + else + normal_status(-1, "操作失败") + end + end + + def lock_issue + if @issue.user == current_user || current_user.admin? + type = (params[:lock_type].to_i == 1) + if @issue.update_attribute(:is_lock, type) + if type + @issue.custom_journal_detail("lock_issue","", "因为#{params[:lock_reason].present? ? params[:lock_reason].to_s : "某种原因"}而锁定,并将对话限制为协作者") + else + @issue.custom_journal_detail("unlock_issue","", "解除锁定") + end + normal_status(0, "操作成功") + else + normal_status(-1, "操作失败") + end + else + normal_status(-1, "您没有权限") + end + + end + private def set_project @project = Project.find_by_id(params[:project_id]) @@ -292,8 +344,10 @@ class IssuesController < ApplicationController def set_issue @issue = Issue.find_by_id(params[:id]) - unless @issue.present? + if @issue.blank? normal_status(-1, "标签不存在") + elsif @issue.is_lock &&!(@project.member?(current_user) || current_user.admin?) + normal_status(-1, "您没有权限") end end @@ -303,25 +357,104 @@ class IssuesController < ApplicationController end end + def join_users(issue) + #协作者 + issue_comment_users_array = [] + issue_comment_users = issue.journals.select(:user_id).distinct + if issue.present? && issue_comment_users.size > 0 + issue_comment_users.each do |j| + user_avatar = url_to_avatar(j.user) + issue_comment_users_array.push({login: j.user.try(:login), avatar_url: user_avatar}) + end + end + issue_comment_users_array + end + + def cost_time(issue) + #总耗时 + @cost_time_array = [] + @all_cost_time = 0 + all_issue_times = issue.issue_times.includes(:user).where.not(end_time: nil) + if issue.present? && all_issue_times.size > 0 + all_issue_times.each do |time| + cost_time = time.end_time.to_i - time.start_time.to_i + cost_time = cost_time > 0 ? cost_time : 0 + @all_cost_time = @all_cost_time + cost_time + set_cost_time = Time.at(cost_time).utc.strftime('%H h %M min %S s') + @cost_time_array.push({login: time.user.try(:login), avatar_url: url_to_avatar(time.user), cost_time: set_cost_time}) + end + end + end + + def depended_issues(issue) + #依赖于 + @depended_issues_id = [] + @depended_issues_array = [] + depended_issues = issue.issue_depends.pluck(:id,:depend_issue_id).uniq + if issue.present? && depended_issues.size > 0 + depended_issues.each do |de| + @depended_issues_id.push(de[1]) + issues = Issue.select(:id, :subject).where(id: de[1]).as_json + issues = issues.first.merge(depend_id: de[0]) + @depended_issues_array.push(issues) + end + @depended_issues_id.delete(issue.id) + end + end + + def be_depended_issues(issue) + be_depended_issues_array = [] + be_depended_issues = IssueDepend.where(depend_issue_id: issue.id).pluck(:id,:issue_id).uniq + if issue.present? && be_depended_issues.size > 0 + be_depended_issues.each do |de| + d_issues = Issue.select(:id, :subject).where(id: de[1]).as_json + d_issues = d_issues.first.merge(depend_id: de[0]) + be_depended_issues_array.push(d_issues) + end + end + be_depended_issues_array + end + def issue_left_chosen(project,issue_id) issue_info = Array.new(11) use_tags = [] + issue_comment_users_array = [] + cost_time_array = [] + all_cost_time = 0 + be_depended_issues_array = [] + depended_issues_array = [] + all_issues = [] + depended_issues_id = [] if issue_id.present? - use_tags = Issue.find(issue_id).issue_tags.select(:id).pluck(:id) + issue = Issue.find(issue_id) + use_tags = issue.issue_tags.select(:id).pluck(:id) select_arrays = [:assigned_to_id, :tracker_id, :status_id, :priority_id, :fixed_version_id, :start_date, :due_date, :estimated_hours, :done_ratio, :issue_type, :token] issue_info = Issue.select(select_arrays).where(id: issue_id).pluck(select_arrays) issue_info = issue_info[0] + + issue_comment_users_array = join_users(issue) + #总耗时 + cost_time(issue) + cost_time_array = @cost_time_array + all_cost_time = @all_cost_time + + #被依赖 + be_depended_issues_array = be_depended_issues(issue) + + #依赖于 + depended_issues(issue) + depended_issues_array = @depended_issues_array + depended_issues_id = @depended_issues_id + end project_members = project.members_user_infos project_members_info = [] #指派给 project_members.each do |member| - real_name = member[2] + member[3] - unless real_name.present? - real_name = member[1] - end + user = member.user + real_name = user.try(:show_real_name) user_id = member[0] - is_chosen = ((member[0].to_s == issue_info[0].to_s) ? "1" : "0") - member_info = {id: user_id, name: real_name, is_chosen: is_chosen} + is_chosen = ((user.id.to_s == issue_info[0].to_s) ? "1" : "0") + member_info = {id: user_id, name: real_name,avatar_url: url_to_avatar(user),is_chosen: is_chosen} project_members_info.push(member_info) end @@ -335,7 +468,6 @@ class IssuesController < ApplicationController end end - issue_status = IssueStatus&.pluck(:id,:name,:position) new_status_info = [] #缺陷类型 if issue_status.size > 0 @@ -356,7 +488,6 @@ class IssuesController < ApplicationController end end - issue_versions = project.versions&.pluck(:id,:name, :status) new_version_info = [] #issue里程碑 if issue_versions.size > 0 @@ -396,6 +527,16 @@ class IssuesController < ApplicationController new_types_info.push(new_type_info) end + depend_other_issues = project.issues.where.not(id: issue_id)&.pluck(:id, :subject) + if depend_other_issues.size > 0 + depend_other_issues.each do |t| + is_chosen = depended_issues_id.include?(t[0]) ? "1" : "0" + new_issue = {id: t[0], subject: t[1], is_chosen: is_chosen} + all_issues.push(new_issue) + end + end + + { "assign_user": project_members_info, "tracker": new_tracker_info, @@ -404,10 +545,16 @@ class IssuesController < ApplicationController "issue_version": new_version_info, "start_date": issue_info[5], "due_date": issue_info[6], + "joins_users": issue_comment_users_array, + "cost_time_users": cost_time_array, + "total_cost_time": Time.at(all_cost_time).utc.strftime('%H h %M min %S s'), + "be_depended_issues": be_depended_issues_array, + "depended_issues":depended_issues_array, "estimated_hours": issue_info[7], "done_ratio": new_done_info, "issue_tag": new_tags_info, - "issue_type": new_types_info + "issue_type": new_types_info, + "all_issues": all_issues } end diff --git a/app/controllers/journals_controller.rb b/app/controllers/journals_controller.rb index 02096be17..6c3bc49ed 100644 --- a/app/controllers/journals_controller.rb +++ b/app/controllers/journals_controller.rb @@ -2,6 +2,7 @@ class JournalsController < ApplicationController before_action :require_login before_action :set_issue before_action :check_issue_permission + before_action :set_journal, only: [:destroy, :edit, :update] def index @page = params[:page] || 1 @@ -42,16 +43,29 @@ class JournalsController < ApplicationController end def destroy - journal = Journal.find(params[:id]) - if journal.present? - if journal.destroy #如果有子评论,子评论删除吗? - normal_status(0, "评论删除成功") + if @journal.destroy #如果有子评论,子评论删除吗? + normal_status(0, "评论删除成功") + else + normal_status(-1, "评论删除失败") + end + end + + def edit + + end + + def update + content = params[:content] + if content.present? + if @journal.update_attribute(:notes, content) + normal_status(0, "更新成功") else - normal_status(-1, "评论删除失败") + normal_status(-1, "更新失败") end else - normal_status(-1, "评论不存在") + normal_status(-1, "评论的内容不能为空") end + end @@ -66,8 +80,15 @@ class JournalsController < ApplicationController def check_issue_permission @project = @issue.project - unless @project.member?(current_user) || current_user.admin? + unless !@issue.is_lock || @project.member?(current_user) || current_user.admin? normal_status(-1, "您没有权限") end end + + def set_journal + @journal = Journal.find(params[:id]) + unless @journal.present? + normal_status(-1, "评论不存在") + end + end end \ No newline at end of file diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb index d2624eebe..8e9412123 100644 --- a/app/controllers/repositories_controller.rb +++ b/app/controllers/repositories_controller.rb @@ -2,6 +2,9 @@ class RepositoriesController < ApplicationController include ApplicationHelper before_action :find_user, :find_repository, :authorizate! + def show + end + def entries @entries = Gitea::Repository::Entries::ListService.new(@user, @repo.identifier, ref: params[:ref]).call end @@ -23,6 +26,10 @@ class RepositoriesController < ApplicationController @commit = Gitea::Repository::Commits::GetService.new(@user, @repo.identifier, params[:sha]).call end + def tags + @tags = Gitea::Repository::Tags::ListService.new(@user, @repo.identifier).call + end + private def authorizate! if @repo.hidden? && @repo.user != current_user diff --git a/app/helpers/issue_depends_helper.rb b/app/helpers/issue_depends_helper.rb new file mode 100644 index 000000000..ab196dc71 --- /dev/null +++ b/app/helpers/issue_depends_helper.rb @@ -0,0 +1,2 @@ +module IssueDependsHelper +end diff --git a/app/helpers/issue_times_helper.rb b/app/helpers/issue_times_helper.rb new file mode 100644 index 000000000..0e8dedb0c --- /dev/null +++ b/app/helpers/issue_times_helper.rb @@ -0,0 +1,2 @@ +module IssueTimesHelper +end diff --git a/app/models/issue.rb b/app/models/issue.rb index 431334be9..4c995be55 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -14,7 +14,8 @@ class Issue < ApplicationRecord has_many :journal_details, through: :journals has_many :issue_tags_relates, dependent: :destroy has_many :issue_tags, through: :issue_tags_relates - + has_many :issue_times, dependent: :destroy + has_many :issue_depends, dependent: :destroy scope :issue_includes, ->{includes(:user)} @@ -43,6 +44,16 @@ class Issue < ApplicationRecord end end + def custom_journal_detail(prop_key, old_value, value) + journal_params = { + journalized_id: self.id, journalized_type: "Issue", user_id: self.author_id + } + journal = Journal.new journal_params + if journal.save + journal.journal_details.create(property: "attr", prop_key: prop_key, old_value: old_value, value: value) + end + end + def get_journals_size journals.size end diff --git a/app/models/issue_depend.rb b/app/models/issue_depend.rb new file mode 100644 index 000000000..14686e86d --- /dev/null +++ b/app/models/issue_depend.rb @@ -0,0 +1,3 @@ +class IssueDepend < ApplicationRecord + belongs_to :issue +end diff --git a/app/models/issue_time.rb b/app/models/issue_time.rb new file mode 100644 index 000000000..10d7af7b6 --- /dev/null +++ b/app/models/issue_time.rb @@ -0,0 +1,4 @@ +class IssueTime < ApplicationRecord + belongs_to :issue + belongs_to :user +end diff --git a/app/models/journal.rb b/app/models/journal.rb index 2bf12d9be..4eaddde68 100644 --- a/app/models/journal.rb +++ b/app/models/journal.rb @@ -37,27 +37,95 @@ class Journal < ApplicationRecord when "assigned_to_id" u = User.select(:id, :login, :lastname, :firstname) old_value = u.find(de[2]).try(:show_real_name) - value = u.find(de[3]).try(:show_real_name) + assign_user = de[3].present? ? u.find(de[3]) : "" + if assign_user.present? + value = u.find(de[3]).try(:show_real_name) + else + value = "取消了指派" + end + when "tracker_id" t = Tracker.select(:id, :name) old_value = t.find(de[2]).try(:name) - value = t.find(de[3]).try(:name) + tracker_name = de[3].present? ? t.find(de[3]) : "" + if tracker_name + value = t.find(de[3]).try(:name) + else + value = "取消了类型" + end + when "status_id" t = IssueStatus.select(:id, :name) old_value = t.find(de[2]).try(:name) - value = t.find(de[3]).try(:name) + type_name = de[3].present? ? t.find(de[3]) : "" + if type_name + value = t.find(de[3]).try(:name) + else + value = "取消了状态" + end when "priority_id" t = IssuePriority.select(:id, :name) old_value = t.find(de[2]).try(:name) - value = t.find(de[3]).try(:name) + type_name = de[3].present? ? t.find(de[3]) : "" + if type_name + value = t.find(de[3]).try(:name) + else + value = "取消了优先级" + end when "issue_tags_value" t = IssueTag.select(:id, :name) old_value = t.where(id: de[2].split(",")).select(:id,:name,:color).as_json - value = t.where(id: de[3].split(",")).select(:id,:name,:color).as_json + if de[3].present? + value = t.where(id: de[3].split(",")).select(:id,:name,:color).as_json + else + value = "清空了标签" + end when "fixed_version_id" t = Version.select(:id, :title) old_value = t.find(de[2]).try(:title) - value = t.find(de[3]).try(:title) + type_name = de[3].present? ? t.find(de[3]) : "" + if type_name + value = t.find(de[3]).try(:title) + else + value = "取消了版本库" + end + when "end_time" + t = IssueTime.select(:id, :start_time, :end_time) + type_name = de[2].present? ? t.find(de[2]) : "" + if type_name.present? + old_value = "停止工作" + d_value = type_name.end_time.to_i - type_name.start_time.to_i + value = "#{Time.at(d_value).utc.strftime('%H h %M min %S s')}" + else + old_value = "停止工作" + value = "停止工作" + end + when "issue_depend" + t = Issue.select(:id,:subject ) + type_name = de[3].present? ? t&.find_by_id(de[3]) : "" + if type_name.present? + old_value = "增加依赖" + value = { + id: de[3], + name: type_name.try(:subject) + } + else + old_value = "增加依赖" + value = nil + end + when "destroy_issue_depend" + t = Issue.select(:id,:subject ) + type_name = de[3].present? ? t&.find_by_id(de[3]) : "" + if type_name.present? + old_value = "删除依赖" + value = { + id: de[3], + name: type_name.try(:subject) + } + else + old_value = "删除依赖" + value = nil + end else old_value = de[2] value = de[3] diff --git a/app/models/project.rb b/app/models/project.rb index 0b02cd4e2..8ae247f7a 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1,6 +1,7 @@ class Project < ApplicationRecord include Matchable include Publicable + include Watchable enum project_type: { mirror: 1, common: 0 } # common:开源托管项目, mirror:开源镜像项目 @@ -42,8 +43,9 @@ class Project < ApplicationRecord end def members_user_infos - members.joins("left join users on members.user_id = users.id").select("users.id", "users.login","users.firstname","users.lastname") - .pluck("users.id", "users.login","users.lastname", "users.firstname") + members.joins("left join users on members.user_id = users.id").includes(:user) + # members.joins("left join users on members.user_id = users.id").select("users.id", "users.login","users.firstname","users.lastname") + # .pluck("users.id", "users.login","users.lastname", "users.firstname") end def to_param diff --git a/app/models/user.rb b/app/models/user.rb index 0f278a20e..b136db2a8 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -52,6 +52,7 @@ class User < ApplicationRecord has_many :course_messages has_many :courses, foreign_key: 'tea_id', dependent: :destroy has_many :versions + has_many :issue_times, :dependent => :destroy #试卷 has_many :exercise_banks, :dependent => :destroy diff --git a/app/models/watcher.rb b/app/models/watcher.rb index d9426e03c..3b613b9f0 100644 --- a/app/models/watcher.rb +++ b/app/models/watcher.rb @@ -1,4 +1,4 @@ class Watcher < ApplicationRecord belongs_to :user - belongs_to :watchable, polymorphic: true -end \ No newline at end of file + belongs_to :watchable, polymorphic: true, counter_cache: :watchers_count +end diff --git a/app/views/issue_times/create.json.jbuilder b/app/views/issue_times/create.json.jbuilder new file mode 100644 index 000000000..e69de29bb diff --git a/app/views/issues/show.json.jbuilder b/app/views/issues/show.json.jbuilder index a1b928bcd..13812a835 100644 --- a/app/views/issues/show.json.jbuilder +++ b/app/views/issues/show.json.jbuilder @@ -1,5 +1,7 @@ json.partial! "commons/success" -json.extract! @issue, :id,:subject,:description,:is_private, :start_date,:due_date,:estimated_hours +json.extract! @issue, :id,:subject,:is_lock,:description,:is_private, :start_date,:due_date,:estimated_hours + +json.user_permission @user_permission json.closed_on @issue.closed_on.present? ? format_time(@issue.closed_on) : "" json.created_at format_time(@issue.created_on) json.assign_user_name @issue_assign_to.try(:show_real_name) @@ -15,6 +17,11 @@ json.issue_tags @issue.get_issue_tags json.done_ratio @issue.done_ratio.to_s + "%" json.issue_type @issue.issue_type == "1" ? "普通" : "悬赏" json.token @issue.issue_type == "2" ? @issue.token : "" +json.join_users @join_users +json.cost_time @cost_time_array +json.total_cost_time Time.at(@all_cost_time).utc.strftime('%H h %M min %S s') +json.be_depended_issues @be_depended_issues_array +json.depended_issues @depended_issues_array json.attachments do json.array! @issue_attachments do |attachment| json.partial! "attachments/attachment_simple", locals: {attachment: attachment} diff --git a/app/views/journals/edit.json.jbuilder b/app/views/journals/edit.json.jbuilder new file mode 100644 index 000000000..f5460ded4 --- /dev/null +++ b/app/views/journals/edit.json.jbuilder @@ -0,0 +1,2 @@ +json.extract! @journal, :id,:notes +json.issue_id @journal.journalized_id \ No newline at end of file diff --git a/app/views/journals/update.json.jbuilder b/app/views/journals/update.json.jbuilder new file mode 100644 index 000000000..e69de29bb diff --git a/app/views/repositories/show.json.jbuilder b/app/views/repositories/show.json.jbuilder new file mode 100644 index 000000000..a515a9509 --- /dev/null +++ b/app/views/repositories/show.json.jbuilder @@ -0,0 +1,5 @@ +json.identifier @repo.identifier +json.praises_count @repo.project.praises_count +json.forked_count @repo.project.forked_count +json.watchers_count @repo.project.watchers_count +json.partial! 'author', locals: { user: @repo.user } diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index b72db9435..0b1cdf0fe 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -16,6 +16,14 @@ zh-CN: 'agreed': '已同意' journal_detail: + issue_tags_value: 标签 + lock_issue: 锁定工单 + unlock_issue: 解锁工单 + destroy_issue_depend: 删除依赖 + issue_depend: 增加依赖 + work_time: 开始工作 + cancel_time: 取消时间跟踪 + end_time: 停止工作 subject: 主题 description: 描述 is_private: 私有 @@ -26,7 +34,7 @@ zh-CN: fixed_version_id: 里程碑 start_date: 开始日期 due_date: 结束日期 - estimated_hours: 工时 + estimated_hours: 添加耗时 done_ratio: 完成度 t: 是 f: 否 diff --git a/config/routes.rb b/config/routes.rb index 19d41c18b..fa0ea2677 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,5 @@ Rails.application.routes.draw do + require 'sidekiq/web' require 'admin_constraint' mount Sidekiq::Web => '/sidekiq', :constraints => AdminConstraint.new @@ -27,6 +28,16 @@ Rails.application.routes.draw do put 'commons/unhidden', to: 'commons#unhidden' delete 'commons/delete', to: 'commons#delete' + resources :issues, except: [:index, :new,:create, :update, :edit, :destroy] do + resources :journals, only: [:index, :create, :destroy, :edit, :update] + resources :issue_times, only: [:create] do + collection do + post :end_work + end + end + resources :issue_depends, only: [:create, :destroy] + end + resources :project_categories, only: [:index, :show] do get :group_list, on: :collection end @@ -42,6 +53,8 @@ Rails.application.routes.draw do member do post :copy get :index_chosen + post :close_issue + post :lock_issue end end resources :issue_tags, only: [:create, :edit, :update, :destroy, :index] @@ -59,12 +72,22 @@ Rails.application.routes.draw do end end + get '/:login/:repo_identifier', to: 'repositories#show' resources :repositories, path: '/:login/:repo_identifier', only: [:index] do collection do get :entries get :sub_entries get :commits get :single_commit + post :files + get :tags + end + end + + resources :contents, path: '/:login/:repo_identifier/contents', only: [:create] do + collection do + put 'files/update', :action => 'update_file' + delete 'files/delete', :action => 'delete_file' end end diff --git a/db/migrate/20200103062707_create_issue_times.rb b/db/migrate/20200103062707_create_issue_times.rb new file mode 100644 index 000000000..b0f2e0b0e --- /dev/null +++ b/db/migrate/20200103062707_create_issue_times.rb @@ -0,0 +1,13 @@ +class CreateIssueTimes < ActiveRecord::Migration[5.2] + def change + create_table :issue_times do |t| + t.integer :issue_id + t.integer :user_id + t.datetime :start_time + t.datetime :end_time + t.string :cost_time + t.timestamps + end + add_index :issue_times, [:issue_id, :user_id] + end +end diff --git a/db/migrate/20200103062807_create_issue_depends.rb b/db/migrate/20200103062807_create_issue_depends.rb new file mode 100644 index 000000000..44fcf487a --- /dev/null +++ b/db/migrate/20200103062807_create_issue_depends.rb @@ -0,0 +1,12 @@ +class CreateIssueDepends < ActiveRecord::Migration[5.2] + def change + create_table :issue_depends do |t| + t.integer :user_id + t.integer :issue_id + t.integer :depend_issue_id + t.timestamps + end + + add_index :issue_depends, [:user_id, :issue_id, :depend_issue_id] + end +end diff --git a/db/migrate/20200103113839_add_is_lock_to_issue.rb b/db/migrate/20200103113839_add_is_lock_to_issue.rb new file mode 100644 index 000000000..21a2c6592 --- /dev/null +++ b/db/migrate/20200103113839_add_is_lock_to_issue.rb @@ -0,0 +1,5 @@ +class AddIsLockToIssue < ActiveRecord::Migration[5.2] + def change + add_column :issues, :is_lock, :boolean, default: false + end +end diff --git a/db/migrate/20200106022235_add_watchers_count_to_projects.rb b/db/migrate/20200106022235_add_watchers_count_to_projects.rb new file mode 100644 index 000000000..551e9e5b6 --- /dev/null +++ b/db/migrate/20200106022235_add_watchers_count_to_projects.rb @@ -0,0 +1,5 @@ +class AddWatchersCountToProjects < ActiveRecord::Migration[5.2] + def change + add_column :projects, :watchers_count, :integer, :default => 0 + end +end diff --git a/spec/controllers/issue_depends_controller_spec.rb b/spec/controllers/issue_depends_controller_spec.rb new file mode 100644 index 000000000..97e81caaa --- /dev/null +++ b/spec/controllers/issue_depends_controller_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe IssueDependsController, type: :controller do + +end diff --git a/spec/controllers/issue_times_controller_spec.rb b/spec/controllers/issue_times_controller_spec.rb new file mode 100644 index 000000000..a40cc469d --- /dev/null +++ b/spec/controllers/issue_times_controller_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe IssueTimesController, type: :controller do + +end diff --git a/spec/helpers/issue_depends_helper_spec.rb b/spec/helpers/issue_depends_helper_spec.rb new file mode 100644 index 000000000..2ff80ff03 --- /dev/null +++ b/spec/helpers/issue_depends_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the IssueDependsHelper. For example: +# +# describe IssueDependsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe IssueDependsHelper, type: :helper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/helpers/issue_times_helper_spec.rb b/spec/helpers/issue_times_helper_spec.rb new file mode 100644 index 000000000..7132044b3 --- /dev/null +++ b/spec/helpers/issue_times_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the IssueTimesHelper. For example: +# +# describe IssueTimesHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe IssueTimesHelper, type: :helper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/issue_depend_spec.rb b/spec/models/issue_depend_spec.rb new file mode 100644 index 000000000..0f48c1b54 --- /dev/null +++ b/spec/models/issue_depend_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe IssueDepend, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/issue_time_spec.rb b/spec/models/issue_time_spec.rb new file mode 100644 index 000000000..5a3418053 --- /dev/null +++ b/spec/models/issue_time_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe IssueTime, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end