| @@ -0,0 +1,24 @@ | |||||
| class Projects::ProjectUnitsController < Projects::BaseController | |||||
| def index | |||||
| @project_units = @project.project_units | |||||
| end | |||||
| def create | |||||
| if current_user.admin? || @project.owner?(current_user) | |||||
| ActiveRecord::Base.transaction do | |||||
| ProjectUnit.update_by_unit_types!(@project, unit_types) | |||||
| render_ok | |||||
| end | |||||
| else | |||||
| render_forbidden('你没有权限操作') | |||||
| end | |||||
| rescue Exception => e | |||||
| uid_logger_error(e.message) | |||||
| tip_exception(e.message) | |||||
| end | |||||
| private | |||||
| def unit_types | |||||
| params.fetch(:unit_types, []) | |||||
| end | |||||
| end | |||||
| @@ -2,11 +2,26 @@ class ProjectsController < ApplicationController | |||||
| include ApplicationHelper | include ApplicationHelper | ||||
| include OperateProjectAbilityAble | include OperateProjectAbilityAble | ||||
| include ProjectsHelper | include ProjectsHelper | ||||
| before_action :require_login, except: %i[index branches group_type_list simple show fork_users praise_users watch_users recommend about] | |||||
| before_action :require_login, except: %i[index branches group_type_list simple show fork_users praise_users watch_users recommend about menu_list] | |||||
| before_action :load_project, except: %i[index group_type_list migrate create recommend] | before_action :load_project, except: %i[index group_type_list migrate create recommend] | ||||
| before_action :authorizate_user_can_edit_project!, only: %i[update] | before_action :authorizate_user_can_edit_project!, only: %i[update] | ||||
| before_action :project_public?, only: %i[fork_users praise_users watch_users] | before_action :project_public?, only: %i[fork_users praise_users watch_users] | ||||
| def menu_list | |||||
| menu = [] | |||||
| menu.append(menu_hash_by_name("home")) | |||||
| menu.append(menu_hash_by_name("code")) if @project.has_menu_permission("code") | |||||
| menu.append(menu_hash_by_name("issues")) if @project.has_menu_permission("issues") | |||||
| menu.append(menu_hash_by_name("pulls")) if @project.has_menu_permission("pulls") | |||||
| menu.append(menu_hash_by_name("devops")) if @project.has_menu_permission("devops") | |||||
| menu.append(menu_hash_by_name("versions")) if @project.has_menu_permission("versions") | |||||
| menu.append(menu_hash_by_name("activity")) | |||||
| menu.append(menu_hash_by_name("setting")) if current_user.admin? || @project.owner?(current_user) | |||||
| render json: menu | |||||
| end | |||||
| def index | def index | ||||
| scope = Projects::ListQuery.call(params) | scope = Projects::ListQuery.call(params) | ||||
| @@ -73,7 +88,8 @@ class ProjectsController < ApplicationController | |||||
| private = params[:private] | private = params[:private] | ||||
| gitea_params = { | gitea_params = { | ||||
| private: private, | private: private, | ||||
| default_branch: params[:default_branch] | |||||
| default_branch: params[:default_branch], | |||||
| website: params[:website] | |||||
| } | } | ||||
| if [true, false].include? private | if [true, false].include? private | ||||
| new_project_params = project_params.except(:private).merge(is_public: !private) | new_project_params = project_params.except(:private).merge(is_public: !private) | ||||
| @@ -162,7 +178,7 @@ class ProjectsController < ApplicationController | |||||
| private | private | ||||
| def project_params | def project_params | ||||
| params.permit(:user_id, :name, :description, :repository_name, | |||||
| params.permit(:user_id, :name, :description, :repository_name, :website, | |||||
| :project_category_id, :project_language_id, :license_id, :ignore_id, :private) | :project_category_id, :project_language_id, :license_id, :ignore_id, :private) | ||||
| end | end | ||||
| @@ -7,10 +7,29 @@ class RepositoriesController < ApplicationController | |||||
| before_action :load_repository | before_action :load_repository | ||||
| before_action :authorizate!, except: [:sync_mirror, :tags, :commit] | before_action :authorizate!, except: [:sync_mirror, :tags, :commit] | ||||
| before_action :authorizate_user_can_edit_repo!, only: %i[sync_mirror] | before_action :authorizate_user_can_edit_repo!, only: %i[sync_mirror] | ||||
| before_action :get_ref, only: %i[entries sub_entries top_counts] | |||||
| before_action :get_ref, only: %i[entries sub_entries top_counts file] | |||||
| before_action :get_latest_commit, only: %i[entries sub_entries top_counts] | before_action :get_latest_commit, only: %i[entries sub_entries top_counts] | ||||
| before_action :get_statistics, only: %i[top_counts] | before_action :get_statistics, only: %i[top_counts] | ||||
| def files | |||||
| result = @project.educoder? ? nil : Gitea::Repository::Files::GetService.call(@owner, @project.identifier, @ref, params[:search], @owner.gitea_token) | |||||
| render json: result | |||||
| end | |||||
| # 新版项目详情 | |||||
| def detail | |||||
| @user = current_user | |||||
| @result = Repositories::DetailService.call(@owner, @repository, @user) | |||||
| @project_fork_id = @project.try(:forked_from_project_id) | |||||
| if @project_fork_id.present? | |||||
| @fork_project = Project.find_by(id: @project_fork_id) | |||||
| @fork_project_user = @fork_project.owner | |||||
| end | |||||
| rescue Exception => e | |||||
| uid_logger_error(e.message) | |||||
| tip_exception(e.message) | |||||
| end | |||||
| def show | def show | ||||
| @user = current_user | @user = current_user | ||||
| @repo = @project.repository | @repo = @project.repository | ||||
| @@ -87,6 +106,10 @@ class RepositoriesController < ApplicationController | |||||
| @tags = Gitea::Repository::Tags::ListService.call(current_user&.gitea_token, @owner.login, @project.identifier, {page: params[:page], limit: params[:limit]}) | @tags = Gitea::Repository::Tags::ListService.call(current_user&.gitea_token, @owner.login, @project.identifier, {page: params[:page], limit: params[:limit]}) | ||||
| end | end | ||||
| def contributors | |||||
| @contributors = Gitea::Repository::Contributors::GetService.call(@owner, @repository.identifier) | |||||
| end | |||||
| def edit | def edit | ||||
| return render_forbidden if !@project.manager?(current_user) && !current_user.admin? | return render_forbidden if !@project.manager?(current_user) && !current_user.admin? | ||||
| end | end | ||||
| @@ -187,7 +210,7 @@ class RepositoriesController < ApplicationController | |||||
| end | end | ||||
| def get_ref | def get_ref | ||||
| @ref = params[:ref] || "master" | |||||
| @ref = params[:ref] || @project.default_branch | |||||
| end | end | ||||
| def get_latest_commit | def get_latest_commit | ||||
| @@ -168,6 +168,55 @@ Remember — a happy kitten is an authenticated kitten! | |||||
| </aside> | </aside> | ||||
| ## 项目导航 | |||||
| 获取项目导航信息 | |||||
| > 示例: | |||||
| ```shell | |||||
| curl -X GET \ | |||||
| http://localhost:3000/api/yystopf/ceshi/menu_list | jq | |||||
| ``` | |||||
| ```javascript | |||||
| await octokit.request('GET /api/yystopf/ceshi/menu_list') | |||||
| ``` | |||||
| ### HTTP 请求 | |||||
| `GET api/:owner/:repo/menu_list` | |||||
| ### 请求参数 | |||||
| 参数 | 必选 | 默认 | 类型 | 字段说明 | |||||
| --------- | ------- | ------- | -------- | ---------- | |||||
| owner |是| |string |用户登录名 | |||||
| repo |是| |string |项目标识identifier | |||||
| ### 返回字段说明 | |||||
| 参数 | 类型 | 字段说明 | |||||
| --------- | ----------- | ----------- | |||||
| menu_name |string|导航名称, home:主页,code:代码库,issues:易修,pulls:合并请求,devops:工作流,versions:里程碑,activity:动态,setting:仓库设置 | |||||
| > 返回的JSON示例: | |||||
| ```json | |||||
| [ | |||||
| { | |||||
| "menu_name": "home" | |||||
| }, | |||||
| { | |||||
| "menu_name": "code" | |||||
| }, | |||||
| { | |||||
| "menu_name": "pulls" | |||||
| }, | |||||
| { | |||||
| "menu_name": "activity" | |||||
| } | |||||
| ] | |||||
| ``` | |||||
| ## 项目主页 | ## 项目主页 | ||||
| 获取项目主页信息 | 获取项目主页信息 | ||||
| @@ -212,6 +261,84 @@ attachments |array|附件 | |||||
| Remember — a happy kitten is an authenticated kitten! | Remember — a happy kitten is an authenticated kitten! | ||||
| </aside> | </aside> | ||||
| ## 项目模块信息 | |||||
| 项目模块信息 | |||||
| > 示例: | |||||
| ```shell | |||||
| curl -X GET \ | |||||
| http://localhost:3000/api/yystopf/ceshi/project_units.json | |||||
| ``` | |||||
| ```javascript | |||||
| await octokit.request('GET /api/yystopf/ceshi/project_units') | |||||
| ``` | |||||
| ### HTTP 请求 | |||||
| `GET /api/yystopf/ceshi/project_units` | |||||
| ### 返回字段说明: | |||||
| 参数 | 类型 | 字段说明 | |||||
| --------- | ----------- | ----------- | |||||
| |type |string|模块名称 | | |||||
| > 返回的JSON示例: | |||||
| ```json | |||||
| [ | |||||
| { | |||||
| "type": "code" | |||||
| }, | |||||
| { | |||||
| "type": "pulls" | |||||
| }, | |||||
| { | |||||
| "type": "issues" | |||||
| } | |||||
| ] | |||||
| ``` | |||||
| ## 更改项目模块展示 | |||||
| 更改项目模块展示 | |||||
| > 示例: | |||||
| ```shell | |||||
| curl -X POST \ | |||||
| -H "accept: application/json" \ | |||||
| -H "Content-Type: application/json" \ | |||||
| -d "{ \"unit_typs\": [\"code\", \"pulls\"]}" \ | |||||
| http://localhost:3000/api/yystopf/ceshi/project_units.json | |||||
| ``` | |||||
| ```javascript | |||||
| await octokit.request('POST /api/yystopf/ceshi/project_units') | |||||
| ``` | |||||
| ### HTTP 请求 | |||||
| `POST /api/yystopf/ceshi/project_units` | |||||
| ### 请求参数 | |||||
| 参数 | 必选 | 默认 | 类型 | 字段说明 | |||||
| --------- | ------- | ------- | -------- | ---------- | |||||
| |unit_types |是| |array | 项目模块内容, 支持以下参数:code:代码库,issues:易修,pulls:合并请求,devops:工作流,versions:里程碑 | | |||||
| ### 返回字段说明: | |||||
| 参数 | 类型 | 字段说明 | |||||
| --------- | ----------- | ----------- | |||||
| |status |int|返回状态, 0: 表示操作成功 | | |||||
| |message |string|返回信息说明| | |||||
| > 返回的JSON示例: | |||||
| ```json | |||||
| { | |||||
| "status": 0, | |||||
| "message": "success" | |||||
| } | |||||
| ``` | |||||
| ## 创建项目 | ## 创建项目 | ||||
| 创建项目 | 创建项目 | ||||
| @@ -97,6 +97,182 @@ await octokit.request('GET /api/jasder/jasder_test/simple.json') | |||||
| } | } | ||||
| ``` | ``` | ||||
| ## 仓库详情(新版) | |||||
| 仓库详情 | |||||
| > 示例: | |||||
| ```shell | |||||
| curl -X GET http://localhost:3000/api/yystopf/ceshi/detail.json | |||||
| ``` | |||||
| ```javascript | |||||
| await octokit.request('GET /api/yystopf/ceshi/detail.json') | |||||
| ``` | |||||
| ### HTTP 请求 | |||||
| `GET /api/:owner/:repo/detail` | |||||
| ### 请求参数: | |||||
| 参数 | 必选 | 默认 | 类型 | 字段说明 | |||||
| --------- | ------- | ------- | -------- | ---------- | |||||
| |owner |是| |string |用户登录名 | | |||||
| |repo |是| |string |项目标识identifier | | |||||
| ### 返回字段说明: | |||||
| 参数 | 类型 | 字段说明 | |||||
| --------- | ----------- | ----------- | |||||
| |content |string |仓库简介 | | |||||
| |website |string |仓库网址 | | |||||
| |readme |string |readme文件| | |||||
| |identifier |string |项目标识 | | |||||
| |name |string |项目名称 | | |||||
| |issues_count |int |项目issue数量| | |||||
| |pull_requests_count |int |项目合并请求数量| | |||||
| |project_identifier |int |项目标识| | |||||
| |praises_count |int |项目点赞数量| | |||||
| |forked_count |int |项目复刻数量| | |||||
| |watchers_count |int |项目关注数量| | |||||
| |versions_count |int |项目里程碑数量| | |||||
| |version_releases_count |int |项目发行版数量| | |||||
| |version_releasesed_count |int |项目发行版已发行数量| | |||||
| |permission |string |项目权限| | |||||
| |mirror_url |string |镜像地址| | |||||
| |mirror |bool |是否为镜像项目| | |||||
| |type |int |项目类型 0 普通项目 1 普通镜像项目 2 同步镜像项目| | |||||
| |open_devops |int |是否开启devops| | |||||
| |watched |bool |是否关注| | |||||
| |praised |bool |是否点赞| | |||||
| |status |int |项目状态| | |||||
| |forked_from_project_id |int |fork项目id| | |||||
| |fork_info |object |fork项目信息| | |||||
| |size |string |仓库大小| | |||||
| |ssh_url |string |项目ssh地址| | |||||
| |clone_url |string |项目克隆地址| | |||||
| |default_branch |string |仓库默认分支| | |||||
| |empty |bool |仓库是否为空| | |||||
| |full_name |string |仓库全称| | |||||
| |private |bool |仓库是否为私有项目| | |||||
| |license_name |string |许可证名称| | |||||
| |release_versions.list.name |string |项目issue数量| | |||||
| |release_versions.list.tag_name |string |发行版标签名称| | |||||
| |release_versions.list.created_at |string |发行版创建时间| | |||||
| |release_versions.total_count |int |发行版数量| | |||||
| |branches.list.name |string |分支名称| | |||||
| |branches.total_count |int |分支数量| | |||||
| |tags.list.name |string |标签名称| | |||||
| |tags.total_count |int |标签数量| | |||||
| |contributors.list.contributions|int |贡献数量| | |||||
| |contributors.list.login |string |贡献者登录名| | |||||
| |contributors.list.name |string |贡献者用户名称| | |||||
| |contributors.list.image_url |string |贡献者头像| | |||||
| |languages |object |项目语言占比| | |||||
| > 返回的JSON示例: | |||||
| ```json | |||||
| { | |||||
| "content": "仓库简介", | |||||
| "website": "仓库网址", | |||||
| "readme": { | |||||
| "type": "file", | |||||
| "encoding": "base64", | |||||
| "size": 9, | |||||
| "name": "README.md", | |||||
| "path": "README.md", | |||||
| "content": "# ceshi\n\n", | |||||
| "sha": "" | |||||
| }, | |||||
| "identifier": "ceshi", | |||||
| "name": "测试项目", | |||||
| "project_id": 2, | |||||
| "repo_id": 2, | |||||
| "issues_count": 0, | |||||
| "pull_requests_count": 0, | |||||
| "project_identifier": "ceshi", | |||||
| "praises_count": 0, | |||||
| "forked_count": 0, | |||||
| "watchers_count": 0, | |||||
| "versions_count": 0, | |||||
| "version_releases_count": 0, | |||||
| "version_releasesed_count": 0, | |||||
| "permission": "Reporter", | |||||
| "mirror_url": null, | |||||
| "mirror": false, | |||||
| "type": 0, | |||||
| "open_devops": false, | |||||
| "watched": false, | |||||
| "praised": false, | |||||
| "status": 1, | |||||
| "forked_from_project_id": 1, | |||||
| "fork_info": { | |||||
| "fork_form_name": "测试项目", | |||||
| "fork_project_user_login": "ceshi_org", | |||||
| "fork_project_identifier": "ceshi", | |||||
| "fork_project_user_name": "ceshi_org" | |||||
| }, | |||||
| "size": "25.0 KB", | |||||
| "ssh_url": "virus@localhost:yystopf/ceshi.git", | |||||
| "clone_url": "http://localhost:10080/yystopf/ceshi.git", | |||||
| "default_branch": "master", | |||||
| "empty": false, | |||||
| "full_name": "yystopf/ceshi", | |||||
| "private": false, | |||||
| "license_name": "gnu-javamail-exception", | |||||
| "release_versions": { | |||||
| "list": [ | |||||
| { | |||||
| "id": 2, | |||||
| "name": "vvvv", | |||||
| "tag_name": "v1.1", | |||||
| "created_at": "2019-07-18 10:16" | |||||
| } | |||||
| ], | |||||
| "total_count": 1 | |||||
| }, | |||||
| "branches": { | |||||
| "list": [ | |||||
| { | |||||
| "name": "master" | |||||
| } | |||||
| ], | |||||
| "total_count": 1 | |||||
| }, | |||||
| "tags": { | |||||
| "list": [ | |||||
| { | |||||
| "name": "v1.1" | |||||
| }, | |||||
| { | |||||
| "name": "v1.0" | |||||
| } | |||||
| ], | |||||
| "total_count": 2 | |||||
| }, | |||||
| "contributors": { | |||||
| "list": [ | |||||
| { | |||||
| "contributions": 1, | |||||
| "gid": 2, | |||||
| "login": "yystopf", | |||||
| "type": "User", | |||||
| "name": "yystopf", | |||||
| "image_url": "avatars/User/b" | |||||
| } | |||||
| ], | |||||
| "total_count": 1 | |||||
| }, | |||||
| "languages": { | |||||
| "HTML": "50.9%", | |||||
| "Ruby": "25.6%", | |||||
| "JavaScript": "21.4%", | |||||
| "CSS": "1.3%", | |||||
| "CoffeeScript": "0.7%", | |||||
| "Shell": "0.1%" | |||||
| } | |||||
| } | |||||
| ``` | |||||
| ## 编辑仓库信息 | ## 编辑仓库信息 | ||||
| 编辑仓库信息 | 编辑仓库信息 | ||||
| @@ -463,6 +639,78 @@ await octokit.request('GET /api/jasder/jasder_test/collaborators.json') | |||||
| Success Data. | Success Data. | ||||
| </aside> | </aside> | ||||
| ## 获取仓库所有文件 | |||||
| 获取仓库所有文件 | |||||
| > 示例: | |||||
| ```shell | |||||
| curl -X GET \ | |||||
| -d "ref=develop" \ | |||||
| http://localhost:3000/api/yystopf/ceshi/files.json | |||||
| ``` | |||||
| ```javascript | |||||
| await octokit.request('GET /api/yystopf/ceshi/files.json') | |||||
| ``` | |||||
| ### HTTP 请求 | |||||
| `GET /api/:owner/:repo/files` | |||||
| ### 请求参数: | |||||
| 参数 | 必选 | 默认 | 类型 | 字段说明 | |||||
| --------- | ------- | ------- | -------- | ---------- | |||||
| |owner |是| |string |用户登录名 | | |||||
| |repo |是| |string |项目标识identifier | | |||||
| |search |否| |string |文件搜索关键词 | | |||||
| |ref |是| |string |分支名,默认为仓库默认分支 | | |||||
| ### 返回字段说明: | |||||
| 参数 | 类型 | 字段说明 | |||||
| --------- | ----------- | ----------- | |||||
| |name |string |文件名称| | |||||
| |path |string |文件路径| | |||||
| |sha |string |文件标识| | |||||
| |type |string |文件类型| | |||||
| |size |int |文件大小| | |||||
| |url |string |文件地址| | |||||
| > 返回的JSON示例: | |||||
| ```json | |||||
| [ | |||||
| { | |||||
| "name": ".gitignore", | |||||
| "path": ".gitignore", | |||||
| "sha": "f83922d01ae60f6e637a1a2b9f08871b4f87dfc8", | |||||
| "type": "file", | |||||
| "size": 63, | |||||
| "url": "http://localhost:10080/api/v1/repos/yystopf/ceshi/contents/.gitignore?ref=master", | |||||
| "html_url": "http://localhost:10080/yystopf/ceshi/src/branch/master/.gitignore" | |||||
| }, | |||||
| { | |||||
| "name": "LICENSE", | |||||
| "path": "LICENSE", | |||||
| "sha": "8f3b9ab0d08afd3a624d822e3971a2f42b3bc2b9", | |||||
| "type": "file", | |||||
| "size": 341, | |||||
| "url": "http://localhost:10080/api/v1/repos/yystopf/ceshi/contents/LICENSE?ref=master", | |||||
| "html_url": "http://localhost:10080/yystopf/ceshi/src/branch/master/LICENSE" | |||||
| }, | |||||
| { | |||||
| "name": "README.md", | |||||
| "path": "README.md", | |||||
| "sha": "1bc8a60ac6ddc876ebc4b60fc68991435bfad93e", | |||||
| "type": "file", | |||||
| "size": 9, | |||||
| "url": "http://localhost:10080/api/v1/repos/yystopf/ceshi/contents/README.md?ref=master", | |||||
| "html_url": "http://localhost:10080/yystopf/ceshi/src/branch/master/README.md" | |||||
| } | |||||
| ] | |||||
| ``` | |||||
| ## 获取仓库代码目录 | ## 获取仓库代码目录 | ||||
| 获取仓库代码目录 | 获取仓库代码目录 | ||||
| @@ -1,4 +1,9 @@ | |||||
| module ProjectsHelper | module ProjectsHelper | ||||
| def menu_hash_by_name(name) | |||||
| { | |||||
| menu_name: name | |||||
| } | |||||
| end | |||||
| def render_zh_project_type(project_type) | def render_zh_project_type(project_type) | ||||
| case project_type | case project_type | ||||
| @@ -89,4 +89,7 @@ module ProjectOperable | |||||
| member.member_roles.create!(role: role) | member.member_roles.create!(role: role) | ||||
| end | end | ||||
| def has_menu_permission(unit_type) | |||||
| self.project_units.where(unit_type: unit_type).exists? | |||||
| end | |||||
| end | end | ||||
| @@ -1,73 +1,76 @@ | |||||
| # == 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") | |||||
| # | |||||
| # 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) | |||||
| # | |||||
| # 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 | class Project < ApplicationRecord | ||||
| @@ -110,12 +113,15 @@ class Project < ApplicationRecord | |||||
| has_and_belongs_to_many :trackers, :order => "#{Tracker.table_name}.position" | has_and_belongs_to_many :trackers, :order => "#{Tracker.table_name}.position" | ||||
| has_one :project_detail, dependent: :destroy | has_one :project_detail, dependent: :destroy | ||||
| has_many :team_projects, dependent: :destroy | has_many :team_projects, dependent: :destroy | ||||
| has_many :project_units, dependent: :destroy | |||||
| after_save :check_project_members | after_save :check_project_members | ||||
| 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 :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 :no_anomory_projects, -> {where("projects.user_id is not null and projects.user_id != ?", 2)} | ||||
| scope :recommend, -> { visible.project_statics_select.where(recommend: true) } | scope :recommend, -> { visible.project_statics_select.where(recommend: true) } | ||||
| delegate :content, to: :project_detail, allow_nil: true | |||||
| delegate :name, to: :license, prefix: true, allow_nil: true | |||||
| def self.search_project(search) | def self.search_project(search) | ||||
| @@ -0,0 +1,35 @@ | |||||
| # == Schema Information | |||||
| # | |||||
| # Table name: project_units | |||||
| # | |||||
| # id :integer not null, primary key | |||||
| # project_id :integer | |||||
| # unit_type :integer | |||||
| # created_at :datetime not null | |||||
| # updated_at :datetime not null | |||||
| # | |||||
| # Indexes | |||||
| # | |||||
| # index_project_units_on_project_id (project_id) | |||||
| # | |||||
| class ProjectUnit < ApplicationRecord | |||||
| belongs_to :project | |||||
| enum unit_type: {code: 1, issues: 2, pulls: 3, devops: 4, versions: 5} | |||||
| validates :unit_type, uniqueness: { scope: :project_id} | |||||
| def self.init_types(project_id) | |||||
| ProjectUnit::unit_types.each do |_, v| | |||||
| self.create!(project_id: project_id, unit_type: v) | |||||
| end | |||||
| end | |||||
| def self.update_by_unit_types!(project, types) | |||||
| project.project_units.where.not(unit_type: types).each(&:destroy!) | |||||
| types.each do |type| | |||||
| project.project_units.find_or_create_by!(unit_type: type) | |||||
| end | |||||
| end | |||||
| end | |||||
| @@ -41,6 +41,8 @@ class Repository < ApplicationRecord | |||||
| validates :identifier, presence: true | validates :identifier, presence: true | ||||
| delegate :default_branch, to: :project, allow_nil: true | |||||
| def to_param | def to_param | ||||
| self.identifier.parameterize | self.identifier.parameterize | ||||
| end | end | ||||
| @@ -0,0 +1,22 @@ | |||||
| class Gitea::Repository::Contributors::GetService < Gitea::ClientService | |||||
| attr_reader :owner, :repo_name | |||||
| def initialize(owner, repo_name) | |||||
| @owner = owner | |||||
| @repo_name = repo_name | |||||
| end | |||||
| def call | |||||
| response = get(url, params) | |||||
| render_status(response) | |||||
| end | |||||
| private | |||||
| def params | |||||
| Hash.new.merge(token: owner.gitea_token) | |||||
| end | |||||
| def url | |||||
| "/repos/#{owner.login}/#{repo_name}/contributors" | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,25 @@ | |||||
| class Gitea::Repository::Files::GetService < Gitea::ClientService | |||||
| attr_reader :owner, :repo_name, :ref, :q, :token | |||||
| def initialize(owner, repo_name, ref, q=nil, token=nil) | |||||
| @owner = owner | |||||
| @repo_name = repo_name | |||||
| @ref = ref | |||||
| @q = q | |||||
| @token = token | |||||
| end | |||||
| def call | |||||
| response = get(url, params) | |||||
| render_status(response) | |||||
| end | |||||
| private | |||||
| def params | |||||
| Hash.new.merge(token: token, ref: ref, q: q) | |||||
| end | |||||
| def url | |||||
| "/repos/#{owner.login}/#{repo_name}/find" | |||||
| end | |||||
| end | |||||
| @@ -18,7 +18,8 @@ class Gitea::Versions::CreateService < Gitea::ClientService | |||||
| end | end | ||||
| def call | def call | ||||
| post(url, request_params) | |||||
| response = post(url, request_params) | |||||
| render_status(response) | |||||
| end | end | ||||
| private | private | ||||
| @@ -13,6 +13,7 @@ class Projects::CreateService < ApplicationService | |||||
| ActiveRecord::Base.transaction do | ActiveRecord::Base.transaction do | ||||
| if @project.save! | if @project.save! | ||||
| Project.update_common_projects_count! | Project.update_common_projects_count! | ||||
| ProjectUnit.init_types(@project.id) | |||||
| Repositories::CreateService.new(user, @project, repository_params).call | Repositories::CreateService.new(user, @project, repository_params).call | ||||
| else | else | ||||
| Rails.logger.info("#############___________create_project_erros______###########{@project.errors.messages}") | Rails.logger.info("#############___________create_project_erros______###########{@project.errors.messages}") | ||||
| @@ -36,6 +37,7 @@ class Projects::CreateService < ApplicationService | |||||
| is_public: repo_is_public, | is_public: repo_is_public, | ||||
| ignore_id: params[:ignore_id], | ignore_id: params[:ignore_id], | ||||
| license_id: params[:license_id], | license_id: params[:license_id], | ||||
| website: params[:website], | |||||
| identifier: params[:repository_name] #新增,hs | identifier: params[:repository_name] #新增,hs | ||||
| } | } | ||||
| end | end | ||||
| @@ -44,6 +46,7 @@ class Projects::CreateService < ApplicationService | |||||
| { | { | ||||
| hidden: !repo_is_public, | hidden: !repo_is_public, | ||||
| user_id: params[:user_id], | user_id: params[:user_id], | ||||
| website: params[:website], | |||||
| identifier: params[:repository_name] | identifier: params[:repository_name] | ||||
| } | } | ||||
| end | end | ||||
| @@ -62,6 +62,7 @@ class Repositories::CreateService < ApplicationService | |||||
| project.update_columns( | project.update_columns( | ||||
| gpid: gitea_repository["id"], | gpid: gitea_repository["id"], | ||||
| identifier: repository.identifier, | identifier: repository.identifier, | ||||
| default_branch: gitea_repository["default_branch"], | |||||
| forked_count: gitea_repository["forks_count"]) | forked_count: gitea_repository["forks_count"]) | ||||
| end | end | ||||
| end | end | ||||
| @@ -0,0 +1,64 @@ | |||||
| class Repositories::DetailService < ApplicationService | |||||
| include Repository::LanguagesPercentagable | |||||
| attr_reader :owner, :repo, :user | |||||
| def initialize(owner, repo, user) | |||||
| @owner = owner | |||||
| @repo = repo | |||||
| @user = user | |||||
| end | |||||
| def call | |||||
| if @repo.project.educoder? | |||||
| return { | |||||
| repo: {}, | |||||
| release: [], | |||||
| branch: [], | |||||
| tag: [], | |||||
| contributor: [], | |||||
| language: {}, | |||||
| readme: {} | |||||
| } | |||||
| else | |||||
| return { | |||||
| repo: repo_suitable, | |||||
| release: release_suitable, | |||||
| branch: branch_suitable, | |||||
| tag: tag_suitable, | |||||
| contributor: contributor_suitable, | |||||
| language: language_suitable, | |||||
| readme: readme_suitable | |||||
| } | |||||
| end | |||||
| end | |||||
| private | |||||
| def repo_suitable | |||||
| Gitea::Repository::GetService.call(@owner, @repo.identifier) | |||||
| end | |||||
| def release_suitable | |||||
| Gitea::Versions::ListService.call(@owner.gitea_token, @owner.try(:login), @repo.try(:identifier)) | |||||
| end | |||||
| def branch_suitable | |||||
| Gitea::Repository::Branches::ListService.call(@owner, @repo.identifier) | |||||
| end | |||||
| def tag_suitable | |||||
| Gitea::Repository::Tags::ListService.call(@owner&.gitea_token, @owner.login, @repo.identifier) | |||||
| end | |||||
| def contributor_suitable | |||||
| Gitea::Repository::Contributors::GetService.call(@owner, @repo.identifier) | |||||
| end | |||||
| def language_suitable | |||||
| result = Gitea::Repository::Languages::ListService.call(@owner.login, @repo.identifier, @user&.gitea_token) | |||||
| result[:status] === :success ? hash_transform_precentagable(result[:body]) : nil | |||||
| end | |||||
| def readme_suitable | |||||
| result = Gitea::Repository::Readme::GetService.call(@owner.login, @repo.identifier, @repo.default_branch, @owner.gitea_token) | |||||
| result[:status] === :success ? result[:body] : nil | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,3 @@ | |||||
| json.array! @project_units do |unit| | |||||
| json.type unit.unit_type | |||||
| end | |||||
| @@ -0,0 +1,17 @@ | |||||
| total_count = @contributors.size | |||||
| json.contributors @contributors.each do |contributor| | |||||
| user = User.find_by(gitea_uid: contributor["id"]) | |||||
| if contributor["login"] == "root" | |||||
| total_count -= 1 | |||||
| next | |||||
| end | |||||
| json.contributions contributor["contributions"] | |||||
| json.gid contributor["id"] | |||||
| json.login user.login | |||||
| json.type user&.type | |||||
| json.name user.real_name | |||||
| json.image_url url_to_avatar(user) | |||||
| end | |||||
| json.total_count total_count | |||||
| @@ -0,0 +1,90 @@ | |||||
| json.content @project.content | |||||
| json.website @project.website | |||||
| json.readme @result[:readme].merge(content: readme_render_decode64_content(@result[:readme]["content"], nil)) | |||||
| json.identifier render_identifier(@project) | |||||
| json.name @project.name | |||||
| 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.project_identifier render_identifier(@project) | |||||
| json.praises_count @project.praises_count.to_i | |||||
| json.forked_count @project.forked_count.to_i | |||||
| json.watchers_count @project.watchers_count.to_i | |||||
| json.versions_count @project.versions_count #里程碑数量 | |||||
| json.version_releases_count @project.releases_size(@user.try(:id), "all") | |||||
| json.version_releasesed_count @project.releases_size(@user.try(:id), "released") #已发行的版本 | |||||
| json.permission render_permission(@user, @project) | |||||
| json.mirror_url @project&.repository.mirror_url | |||||
| json.mirror @project&.repository.mirror_url.present? | |||||
| json.type @project.numerical_for_project_type | |||||
| json.open_devops @project.open_devops? | |||||
| unless @project.common? | |||||
| json.mirror_status @repository.mirror_status | |||||
| json.mirror_num @repository.mirror_num | |||||
| json.first_sync @repository.first_sync? | |||||
| end | |||||
| json.watched @project.watched_by? @user | |||||
| json.praised @project.praised_by? @user | |||||
| json.status @project.status | |||||
| json.forked_from_project_id @project_fork_id | |||||
| json.fork_info do | |||||
| if @fork_project.present? | |||||
| json.fork_form_name @fork_project.try(:name) | |||||
| json.fork_project_user_login @fork_project_user.try(:login) | |||||
| json.fork_project_identifier @fork_project.identifier | |||||
| json.fork_project_user_name @fork_project_user.try(:show_real_name) | |||||
| end | |||||
| end | |||||
| 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.empty @result[:repo]['empty'] | |||||
| json.full_name @result[:repo]['full_name'] | |||||
| json.private @result[:repo]['private'] | |||||
| end | |||||
| json.license_name @project.license_name | |||||
| json.release_versions do | |||||
| json.list @result[:release].each do |release| | |||||
| forge_version = VersionRelease.find_by(version_gid: release["id"]) | |||||
| json.id forge_version&.id | |||||
| json.name release["name"] | |||||
| json.tag_name release["tag_name"] | |||||
| json.created_at format_time(release["created_at"].to_time) | |||||
| end | |||||
| json.total_count @result[:release].size | |||||
| end | |||||
| json.branches do | |||||
| json.list @result[:branch].each do |branch| | |||||
| json.name branch["name"] | |||||
| end | |||||
| json.total_count @result[:branch].size | |||||
| end | |||||
| json.tags do | |||||
| json.list @result[:tag].each do |tag| | |||||
| json.name tag["name"] | |||||
| end | |||||
| json.total_count @result[:tag].size | |||||
| end | |||||
| json.contributors do | |||||
| total_count = @result[:contributor].size | |||||
| json.list @result[:contributor].each do |contributor| | |||||
| user = User.find_by(gitea_uid: contributor["id"]) | |||||
| if contributor["login"] == "root" | |||||
| total_count -= 1 | |||||
| next | |||||
| end | |||||
| json.contributions contributor["contributions"] | |||||
| json.gid contributor["id"] | |||||
| json.login user.login | |||||
| json.type user&.type | |||||
| json.name user.real_name | |||||
| json.image_url url_to_avatar(user) | |||||
| end | |||||
| json.total_count total_count | |||||
| end | |||||
| json.languages @result[:language] | |||||
| @@ -41,7 +41,7 @@ if @project.forge? | |||||
| end | end | ||||
| #json.tags_count @tags_count | #json.tags_count @tags_count | ||||
| #json.branches_count @branches_count | #json.branches_count @branches_count | ||||
| #json.commits_count @commits_count | |||||
| json.commits_count @commits_count | |||||
| json.zip_url render_zip_url(@project, @ref) | json.zip_url render_zip_url(@project, @ref) | ||||
| json.tar_url render_tar_url(@project, @ref) | json.tar_url render_tar_url(@project, @ref) | ||||
| json.entries do | json.entries do | ||||
| @@ -369,6 +369,7 @@ Rails.application.routes.draw do | |||||
| resource :projects, path: '/', except: [:show, :edit] do | resource :projects, path: '/', except: [:show, :edit] do | ||||
| member do | member do | ||||
| get :menu_list | |||||
| get :branches | get :branches | ||||
| get :simple | get :simple | ||||
| get :watchers, to: 'projects#watch_users' | get :watchers, to: 'projects#watch_users' | ||||
| @@ -378,14 +379,17 @@ Rails.application.routes.draw do | |||||
| end | end | ||||
| end | end | ||||
| resource :repositories, path: '/', only: [:show, :create, :edit] do | |||||
| resource :repositories, path: '/', only: [:show, :create, :edit] do | |||||
| member do | member do | ||||
| get :files | |||||
| get :detail | |||||
| get :archive | get :archive | ||||
| get :top_counts | get :top_counts | ||||
| get :entries | get :entries | ||||
| match :sub_entries, :via => [:get, :put] | match :sub_entries, :via => [:get, :put] | ||||
| get :commits | get :commits | ||||
| get :tags | get :tags | ||||
| get :contributors | |||||
| post :create_file | post :create_file | ||||
| put :update_file | put :update_file | ||||
| delete :delete_file | delete :delete_file | ||||
| @@ -526,6 +530,7 @@ Rails.application.routes.draw do | |||||
| scope module: :projects do | scope module: :projects do | ||||
| resources :teams, only: [:index, :create, :destroy] | resources :teams, only: [:index, :create, :destroy] | ||||
| resources :project_units, only: [:index, :create] | |||||
| scope do | scope do | ||||
| get( | get( | ||||
| '/blob/*id/diff', | '/blob/*id/diff', | ||||
| @@ -0,0 +1,6 @@ | |||||
| class AddWebsiteToProjects < ActiveRecord::Migration[5.2] | |||||
| def change | |||||
| add_column :projects, :default_branch, :string, default: 'master' | |||||
| add_column :projects, :website, :string | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,10 @@ | |||||
| class CreateProjectUnits < ActiveRecord::Migration[5.2] | |||||
| def change | |||||
| create_table :project_units do |t| | |||||
| t.references :project | |||||
| t.integer :unit_type | |||||
| t.timestamps | |||||
| end | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,5 @@ | |||||
| require 'rails_helper' | |||||
| RSpec.describe ProjectUnit, type: :model do | |||||
| pending "add some examples to (or delete) #{__FILE__}" | |||||
| end | |||||