From e716dba249e0b626f21549c226ffb265a4792744 Mon Sep 17 00:00:00 2001 From: jasder Date: Mon, 24 May 2021 17:05:06 +0800 Subject: [PATCH 01/51] FIX query project members api bug --- app/models/user.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/user.rb b/app/models/user.rb index 03989cbab..b778c80f9 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -168,7 +168,7 @@ class User < Owner # Groups and active users scope :active, lambda { where(status: STATUS_ACTIVE) } scope :like, lambda { |keywords| - sql = "CONCAT(lastname, firstname) LIKE :keyword OR login LIKE :keyword OR mail LIKE :keyword OR nickname LIKE :keyword" + sql = "CONCAT(lastname, firstname) LIKE :search OR login LIKE :search OR mail LIKE :search OR nickname LIKE :search" where(sql, :search => "%#{keywords.split(" ").join('|')}%") unless keywords.blank? } From 77076c60a60de262241ada6770c9eb83e88ef679 Mon Sep 17 00:00:00 2001 From: jasder Date: Wed, 26 May 2021 17:37:13 +0800 Subject: [PATCH 02/51] =?UTF-8?q?ADD=20issue=E3=80=81pull=E3=80=81mileston?= =?UTF-8?q?e=E9=92=A9=E5=AD=90,=E8=87=AA=E5=8A=A8=E8=A7=A6=E5=8F=91?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E7=9A=84=E6=9B=B4=E6=96=B0=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/issue.rb | 2 +- app/models/pull_request.rb | 2 +- app/models/version.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models/issue.rb b/app/models/issue.rb index 934e1d314..69de1eae2 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -50,7 +50,7 @@ class Issue < ApplicationRecord #issue_type 1为普通,2为悬赏 - belongs_to :project, :counter_cache => true + belongs_to :project, counter_cache: true, touch: true belongs_to :tracker,optional: true has_many :project_trends, as: :trend, dependent: :destroy has_one :pull_request diff --git a/app/models/pull_request.rb b/app/models/pull_request.rb index cf057c3f2..62d6c3cc6 100644 --- a/app/models/pull_request.rb +++ b/app/models/pull_request.rb @@ -31,7 +31,7 @@ class PullRequest < ApplicationRecord belongs_to :issue belongs_to :user - belongs_to :project, :counter_cache => true + belongs_to :project, counter_cache: true, touch: true # belongs_to :fork_project, foreign_key: :fork_project_id has_many :pull_request_assigns, foreign_key: :pull_request_id has_many :pull_request_tags, foreign_key: :pull_request_id diff --git a/app/models/version.rb b/app/models/version.rb index bee22cd5c..650d5a656 100644 --- a/app/models/version.rb +++ b/app/models/version.rb @@ -24,7 +24,7 @@ # class Version < ApplicationRecord - belongs_to :project, counter_cache: true + belongs_to :project, counter_cache: true, touch: true has_many :issues, class_name: "Issue", foreign_key: "fixed_version_id" belongs_to :user, optional: true From cacc807978a71f849abbd5c5888a0e51f72151a9 Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Thu, 27 May 2021 10:30:34 +0800 Subject: [PATCH 03/51] add: user headmap --- app/controllers/users/headmaps_controller.rb | 26 ++++ app/docs/slate/source/includes/_users.md | 124 ++++++++++++++- app/services/gitea/user/headmap_service.rb | 23 +++ app/views/users/headmaps/index.json.jbuilder | 5 + config/routes.rb | 1 + public/docs/api.html | 152 +++++++++++++++++-- 6 files changed, 321 insertions(+), 10 deletions(-) create mode 100644 app/controllers/users/headmaps_controller.rb create mode 100644 app/services/gitea/user/headmap_service.rb create mode 100644 app/views/users/headmaps/index.json.jbuilder diff --git a/app/controllers/users/headmaps_controller.rb b/app/controllers/users/headmaps_controller.rb new file mode 100644 index 000000000..81bd5771c --- /dev/null +++ b/app/controllers/users/headmaps_controller.rb @@ -0,0 +1,26 @@ +class Users::HeadmapsController < Users::BaseController + def index + result = Gitea::User::HeadmapService.call(observed_user.login, start_stamp, end_stamp) + @headmaps = result[2] + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + + private + def start_stamp + if params[:year].present? + Date.new(params[:year], 1).to_time.to_i + else + Date.today.to_time.to_i - 365*24*60*60 + end + end + + def end_stamp + if params[:year].present? + Date.new(params[:year], 1).to_time.to_i + 365*24*60*60 + else + Date.today.to_time.to_i + end + end +end \ No newline at end of file diff --git a/app/docs/slate/source/includes/_users.md b/app/docs/slate/source/includes/_users.md index 1d1afc028..982543fdc 100644 --- a/app/docs/slate/source/includes/_users.md +++ b/app/docs/slate/source/includes/_users.md @@ -1,7 +1,7 @@ # Users @@ -47,6 +47,128 @@ await octokit.request('GET /api/users/me.json') Success Data. +## 获取用户贡献度 +获取用户贡献度 + +> 示例: + +```shell +curl -X GET http://localhost:3000/api/users/yystopf/headmaps.json +``` + +```javascript +await octokit.request('GET /api/users/:login/headmaps.json') +``` + +### HTTP 请求 +`GET api/users/:login/headmaps.json` + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|total_contributions |int |所选时间内的总贡献度 | +|headmaps.date |string|时间| +|headmaps.contributions |int|贡献度| + + +> 返回的JSON示例: + +```json +{ + "total_contributions": 139, + "headmaps": [ + { + "date": 1612627200, + "contributions": 1 + }, + { + "date": 1613836800, + "contributions": 13 + }, + { + "date": 1614182400, + "contributions": 5 + }, + { + "date": 1614528000, + "contributions": 2 + }, + { + "date": 1614787200, + "contributions": 1 + }, + { + "date": 1615737600, + "contributions": 9 + }, + { + "date": 1616342400, + "contributions": 14 + }, + { + "date": 1616515200, + "contributions": 1 + }, + { + "date": 1617033600, + "contributions": 11 + }, + { + "date": 1617638400, + "contributions": 1 + }, + { + "date": 1618156800, + "contributions": 1 + }, + { + "date": 1618243200, + "contributions": 2 + }, + { + "date": 1618761600, + "contributions": 3 + }, + { + "date": 1619107200, + "contributions": 37 + }, + { + "date": 1619280000, + "contributions": 2 + }, + { + "date": 1619366400, + "contributions": 6 + }, + { + "date": 1619539200, + "contributions": 1 + }, + { + "date": 1619625600, + "contributions": 18 + }, + { + "date": 1619712000, + "contributions": 9 + }, + { + "date": 1620057600, + "contributions": 1 + }, + { + "date": 1620230400, + "contributions": 1 + } + ] +} +``` + + + ## 待办事项-用户通知信息 待办事项-用户通知信息 diff --git a/app/services/gitea/user/headmap_service.rb b/app/services/gitea/user/headmap_service.rb new file mode 100644 index 000000000..611a8b9d0 --- /dev/null +++ b/app/services/gitea/user/headmap_service.rb @@ -0,0 +1,23 @@ +class Gitea::User::HeadmapService < Gitea::ClientService + attr_reader :start_time, :end_time, :username + + def initialize(username, start_time, end_time) + @username = username + @start_time = start_time + @end_time = end_time + end + + def call + response = get(url, params) + render_response(response) + end + + private + def params + Hash.new.merge(start: start_time, end: end_time) + end + + def url + "/users/#{username}/heatmap".freeze + end +end \ No newline at end of file diff --git a/app/views/users/headmaps/index.json.jbuilder b/app/views/users/headmaps/index.json.jbuilder new file mode 100644 index 000000000..7011b2559 --- /dev/null +++ b/app/views/users/headmaps/index.json.jbuilder @@ -0,0 +1,5 @@ +json.total_contributions @headmaps.collect{|map| map["contributions"]}.reduce(0, :+) +json.headmaps @headmaps.each do |map| + json.date map["timestamp"] + json.contributions map["contributions"] +end diff --git a/config/routes.rb b/config/routes.rb index a8c97effc..ae121bb08 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -265,6 +265,7 @@ Rails.application.routes.draw do post :refuse end end + resources :headmaps, only: [:index] resources :organizations, only: [:index] # resources :projects, only: [:index] # resources :subjects, only: [:index] diff --git a/public/docs/api.html b/public/docs/api.html index f970ea84d..9f52b9066 100644 --- a/public/docs/api.html +++ b/public/docs/api.html @@ -331,6 +331,9 @@
  • 获取当前登陆用户信息
  • +
  • + 获取用户贡献度 +
  • 待办事项-用户通知信息
  • @@ -587,7 +590,7 @@ Success — a happy kitten is an authenticated kitten!

    Users

    获取当前登陆用户信息

    @@ -649,6 +652,137 @@ Success — a happy kitten is an authenticated kitten! +

    获取用户贡献度

    +

    获取用户贡献度

    + +
    +

    示例:

    +
    +
    curl -X GET http://localhost:3000/api/users/yystopf/headmaps.json
    +
    await octokit.request('GET /api/users/:login/headmaps.json')
    +

    HTTP 请求

    +

    GET api/users/:login/headmaps.json

    +

    返回字段说明:

    + + + + + + + + + + + + + + + + + + + + + + +
    参数类型字段说明
    total_contributionsint所选时间内的总贡献度
    headmaps.datestring时间
    headmaps.contributionsint贡献度
    + +
    +

    返回的JSON示例:

    +
    +
    {
    +    "total_contributions": 139,
    +    "headmaps": [
    +        {
    +            "date": 1612627200,
    +            "contributions": 1
    +        },
    +        {
    +            "date": 1613836800,
    +            "contributions": 13
    +        },
    +        {
    +            "date": 1614182400,
    +            "contributions": 5
    +        },
    +        {
    +            "date": 1614528000,
    +            "contributions": 2
    +        },
    +        {
    +            "date": 1614787200,
    +            "contributions": 1
    +        },
    +        {
    +            "date": 1615737600,
    +            "contributions": 9
    +        },
    +        {
    +            "date": 1616342400,
    +            "contributions": 14
    +        },
    +        {
    +            "date": 1616515200,
    +            "contributions": 1
    +        },
    +        {
    +            "date": 1617033600,
    +            "contributions": 11
    +        },
    +        {
    +            "date": 1617638400,
    +            "contributions": 1
    +        },
    +        {
    +            "date": 1618156800,
    +            "contributions": 1
    +        },
    +        {
    +            "date": 1618243200,
    +            "contributions": 2
    +        },
    +        {
    +            "date": 1618761600,
    +            "contributions": 3
    +        },
    +        {
    +            "date": 1619107200,
    +            "contributions": 37
    +        },
    +        {
    +            "date": 1619280000,
    +            "contributions": 2
    +        },
    +        {
    +            "date": 1619366400,
    +            "contributions": 6
    +        },
    +        {
    +            "date": 1619539200,
    +            "contributions": 1
    +        },
    +        {
    +            "date": 1619625600,
    +            "contributions": 18
    +        },
    +        {
    +            "date": 1619712000,
    +            "contributions": 9
    +        },
    +        {
    +            "date": 1620057600,
    +            "contributions": 1
    +        },
    +        {
    +            "date": 1620230400,
    +            "contributions": 1
    +        }
    +    ]
    +}
    +
    +

    待办事项-用户通知信息

    待办事项-用户通知信息

    @@ -657,7 +791,7 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/applied_messages.json
     
    await octokit.request('GET /api/users/:login/applied_messages.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_messages.json

    请求字段说明:

    @@ -673,7 +807,7 @@ Success — a happy kitten is an authenticated kitten!
    用户标识
    -

    返回字段说明:

    +

    返回字段说明:

    @@ -894,7 +1028,7 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/applied_transfer_projects.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects.json

    请求字段说明:

    参数
    @@ -910,7 +1044,7 @@ Success — a happy kitten is an authenticated kitten!
    用户标识
    -

    返回字段说明:

    +

    返回字段说明:

    @@ -1086,7 +1220,7 @@ Success — a happy kitten is an authenticated kitten!
    curl -X POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/accept.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/accept.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects/:id/accept.json

    请求字段说明:

    参数
    @@ -1107,7 +1241,7 @@ Success — a happy kitten is an authenticated kitten!
    迁移id
    -

    返回字段说明:

    +

    返回字段说明:

    @@ -1277,7 +1411,7 @@ Success — a happy kitten is an authenticated kitten!
    curl -X POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/refuse.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/refuse.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects/:id/refuse.json

    请求字段说明:

    参数
    @@ -1298,7 +1432,7 @@ Success — a happy kitten is an authenticated kitten!
    迁移id
    -

    返回字段说明:

    +

    返回字段说明:

    From c2449d59afe3583db7dad88ee9be6f62a499df88 Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Thu, 27 May 2021 14:23:59 +0800 Subject: [PATCH 04/51] add: user pinned projects --- .../users/is_pinned_projects_controller.rb | 27 ++ app/docs/slate/source/includes/_users.md | 131 ++++++++- app/models/pinned_project.rb | 22 ++ app/models/project.rb | 148 +++++----- app/models/user.rb | 10 + .../projects/_project_detail.json.jbuilder | 3 + app/views/repositories/edit.json.jbuilder | 3 +- .../is_pinned_projects/index.json.jbuilder | 4 + config/routes.rb | 5 + .../20210527024043_create_pinned_projects.rb | 11 + public/docs/api.html | 266 ++++++++++++++++-- spec/models/pinned_project_spec.rb | 5 + 12 files changed, 544 insertions(+), 91 deletions(-) create mode 100644 app/controllers/users/is_pinned_projects_controller.rb create mode 100644 app/models/pinned_project.rb create mode 100644 app/views/users/is_pinned_projects/index.json.jbuilder create mode 100644 db/migrate/20210527024043_create_pinned_projects.rb create mode 100644 spec/models/pinned_project_spec.rb diff --git a/app/controllers/users/is_pinned_projects_controller.rb b/app/controllers/users/is_pinned_projects_controller.rb new file mode 100644 index 000000000..22ce29263 --- /dev/null +++ b/app/controllers/users/is_pinned_projects_controller.rb @@ -0,0 +1,27 @@ +class Users::IsPinnedProjectsController < Users::BaseController + before_action :private_user_resources!, only: [:pin] + def index + @is_pinned_projects = observed_user.is_pinned_projects.includes(:project_category, :project_language, :repository).order(position: :desc) + @is_pinned_projects = kaminari_paginate(@is_pinned_projects) + end + + def pin + observed_user.is_pinned_project_ids = is_pinned_project_ids + render_ok + rescue ActiveRecord::RecordNotFound => e + render_not_found + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + + private + def is_pinned_project_ids + if params[:is_pinned_project_ids].present? + return params[:is_pinned_project_ids].select{|id| observed_user.full_member_projects.pluck(:id).include?(id.to_i) } + end + if params[:is_pinned_project_id].present? + return observed_user.is_pinned_project_ids.include?(params[:is_pinned_project_id].to_i) ? observed_user.is_pinned_project_ids : observed_user.is_pinned_project_ids.push(params[:is_pinned_project_id].to_i) + end + end +end \ No newline at end of file diff --git a/app/docs/slate/source/includes/_users.md b/app/docs/slate/source/includes/_users.md index 982543fdc..b2c3ebccb 100644 --- a/app/docs/slate/source/includes/_users.md +++ b/app/docs/slate/source/includes/_users.md @@ -1,7 +1,7 @@ # Users @@ -47,6 +47,135 @@ await octokit.request('GET /api/users/me.json') Success Data. +## 获取用户星标项目 +获取用户星标项目 + +> 示例: + +```shell +curl -X GET http://localhost:3000/api/users/yystopf/is_pinned_projects.json +``` + +```javascript +await octokit.request('GET /api/users/:login/is_pinned_projects.json') +``` + +### HTTP 请求 +`GET api/users/:login/is_pinned_projects.json` + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|total_count |int |星标项目数量 | +|identifier |string |项目标识 | +|name |string |项目名称 | +|description |string |项目描述 | +|visits |int |项目访问数量| +|praises_count |int |项目点赞数量| +|watchers_count |int |项目关注数量| +|issues_count |int |项目issue数量| +|pull_requests_count |int |项目合并请求数量| +|forked_count |int |项目复刻数量| +|is_public |bool |项目是否公开| +|mirror_url |string |镜像地址| +|type |int |项目类型 0 普通项目 1 普通镜像项目 2 同步镜像项目| +|time_ago |string |上次更新时间| +|open_devops |int |是否开启devops| +|forked_from_project_id |int |fork项目id| +|platform |string |项目平台| +|author.name |string |项目拥有者名称| +|author.type |string |项目拥有者类型| +|author.login |string |项目拥有者用户名| +|author.image_url |string |项目拥有者头像| +|category.name |string |项目分类名称| +|language.name |string |项目语言名称| + + +> 返回的JSON示例: + +```json +{ + "total_count": 1, + "projects": [ + { + "id": 89, + "repo_id": 89, + "identifier": "monkey", + "name": "boke", + "description": "dkkd", + "visits": 4, + "praises_count": 0, + "watchers_count": 0, + "issues_count": 0, + "pull_requests_count": 0, + "forked_count": 0, + "is_public": true, + "mirror_url": "https://github.com/viletyy/monkey.git", + "type": 1, + "last_update_time": 1619685144, + "time_ago": "27天前", + "forked_from_project_id": null, + "open_devops": false, + "platform": "forge", + "author": { + "name": "测试组织", + "type": "Organization", + "login": "ceshi_org", + "image_url": "images/avatars/Organization/9?t=1612706073" + }, + "category": { + "id": 3, + "name": "深度学习" + }, + "language": { + "id": 2, + "name": "C" + } + } + ] +} +``` + + +## 用户添加星标项目 +用户添加星标项目 + +> 示例: + +```shell +curl -X POST http://localhost:3000/api/users/yystopf/is_pinned_projects/pin.json +``` + +```javascript +await octokit.request('GET /api/users/:login/is_pinned_projects/pin.json') +``` + +### HTTP 请求 +`POST /api/users/:login/is_pinned_projects/pin.json` + +### 请求字段说明: +#### 同时设定多个星标项目 +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|is_pinned_project_ids |array |设定为星标项目的id | + +#### 只设定一个星标项目 +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|is_pinned_project_id |integer |设定为星标项目的id | + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} +``` + + ## 获取用户贡献度 获取用户贡献度 diff --git a/app/models/pinned_project.rb b/app/models/pinned_project.rb new file mode 100644 index 000000000..8e47c9ea4 --- /dev/null +++ b/app/models/pinned_project.rb @@ -0,0 +1,22 @@ +# == Schema Information +# +# Table name: pinned_projects +# +# id :integer not null, primary key +# user_id :integer +# project_id :integer +# position :integer default("0") +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_pinned_projects_on_project_id (project_id) +# index_pinned_projects_on_user_id (user_id) +# + +class PinnedProject < ApplicationRecord + + belongs_to :user + belongs_to :project +end diff --git a/app/models/project.rb b/app/models/project.rb index b48680830..9299abcdb 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1,76 +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 -# praises_count :integer default("0") -# watchers_count :integer default("0") -# issues_count :integer default("0") -# pull_requests_count :integer default("0") -# language :string(255) -# versions_count :integer default("0") -# issue_tags_count :integer default("0") -# closed_issues_count :integer default("0") -# open_devops :boolean default("0") -# gitea_webhook_id :integer -# open_devops_count :integer default("0") -# recommend :boolean default("0") -# platform :integer default("0") -# license_id :integer -# ignore_id :integer -# default_branch :string(255) default("master") -# website :string(255) -# lesson_url :string(255) -# -# Indexes -# -# index_projects_on_forked_from_project_id (forked_from_project_id) -# index_projects_on_identifier (identifier) -# index_projects_on_is_public (is_public) -# index_projects_on_lft (lft) -# index_projects_on_name (name) -# index_projects_on_platform (platform) -# index_projects_on_project_type (project_type) -# index_projects_on_recommend (recommend) -# index_projects_on_rgt (rgt) -# index_projects_on_status (status) -# index_projects_on_updated_on (updated_on) -# - +# == Schema Information +# +# Table name: projects +# +# id :integer not null, primary key +# name :string(255) default(""), not null +# description :text(4294967295) +# homepage :string(255) default("") +# is_public :boolean default("1"), not null +# parent_id :integer +# created_on :datetime +# updated_on :datetime +# identifier :string(255) +# status :integer default("1"), not null +# lft :integer +# rgt :integer +# inherit_members :boolean default("0"), not null +# project_type :integer default("0") +# hidden_repo :boolean default("0"), not null +# attachmenttype :integer default("1") +# user_id :integer +# dts_test :integer default("0") +# enterprise_name :string(255) +# organization_id :integer +# project_new_type :integer +# gpid :integer +# forked_from_project_id :integer +# forked_count :integer default("0") +# publish_resource :integer default("0") +# visits :integer default("0") +# hot :integer default("0") +# invite_code :string(255) +# qrcode :string(255) +# qrcode_expiretime :integer default("0") +# script :text(65535) +# training_status :integer default("0") +# rep_identifier :string(255) +# project_category_id :integer +# project_language_id :integer +# praises_count :integer default("0") +# watchers_count :integer default("0") +# issues_count :integer default("0") +# pull_requests_count :integer default("0") +# language :string(255) +# versions_count :integer default("0") +# issue_tags_count :integer default("0") +# closed_issues_count :integer default("0") +# open_devops :boolean default("0") +# gitea_webhook_id :integer +# open_devops_count :integer default("0") +# recommend :boolean default("0") +# platform :integer default("0") +# license_id :integer +# ignore_id :integer +# default_branch :string(255) default("master") +# website :string(255) +# lesson_url :string(255) +# +# Indexes +# +# index_projects_on_forked_from_project_id (forked_from_project_id) +# index_projects_on_identifier (identifier) +# index_projects_on_is_public (is_public) +# index_projects_on_lft (lft) +# index_projects_on_name (name) +# index_projects_on_platform (platform) +# index_projects_on_project_type (project_type) +# index_projects_on_recommend (recommend) +# index_projects_on_rgt (rgt) +# index_projects_on_status (status) +# index_projects_on_updated_on (updated_on) +# + class Project < ApplicationRecord include Matchable @@ -114,6 +114,8 @@ class Project < ApplicationRecord has_many :team_projects, dependent: :destroy has_many :project_units, dependent: :destroy has_one :applied_transfer_project,-> { order created_at: :desc }, dependent: :destroy + has_many :pinned_projects, dependent: :destroy + has_many :has_pinned_users, through: :pinned_projects, source: :user after_save :check_project_members 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)} diff --git a/app/models/user.rb b/app/models/user.rb index b778c80f9..bac795dd5 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -164,6 +164,9 @@ class User < Owner has_many :organization_users, dependent: :destroy has_many :organizations, through: :organization_users + has_many :pinned_projects, dependent: :destroy + has_many :is_pinned_projects, through: :pinned_projects, source: :project + accepts_nested_attributes_for :is_pinned_projects # Groups and active users scope :active, lambda { where(status: STATUS_ACTIVE) } @@ -195,6 +198,13 @@ class User < Owner validate :validate_sensitive_string validate :validate_password_length + # 用户参与的所有项目 + def full_member_projects + normal_projects = Project.members_projects(self.id).to_sql + org_projects = Project.joins(team_projects: [team: :team_users]).where(team_users: {user_id: self.id}).to_sql + return Project.from("( #{ normal_projects} UNION #{ org_projects } ) AS projects").distinct + end + def name login end diff --git a/app/views/projects/_project_detail.json.jbuilder b/app/views/projects/_project_detail.json.jbuilder index d0b62aaa3..2e256fcb4 100644 --- a/app/views/projects/_project_detail.json.jbuilder +++ b/app/views/projects/_project_detail.json.jbuilder @@ -5,6 +5,9 @@ json.name project.name json.description Nokogiri::HTML(project.description).text json.visits project.visits json.praises_count project.praises_count.to_i +json.watchers_count project.watchers_count.to_i +json.issues_count project.issues_count.to_i +json.pull_requests_count project.pull_requests_count.to_i json.forked_count project.forked_count.to_i json.is_public project.is_public json.mirror_url project.repository&.mirror_url diff --git a/app/views/repositories/edit.json.jbuilder b/app/views/repositories/edit.json.jbuilder index 7a11411f4..e0b601f6d 100644 --- a/app/views/repositories/edit.json.jbuilder +++ b/app/views/repositories/edit.json.jbuilder @@ -12,4 +12,5 @@ json.permission render_permission(current_user, @project) json.is_transfering @project.is_transfering json.transfer do json.partial! "/users/user_simple", locals: {user: @project&.applied_transfer_project&.owner} -end \ No newline at end of file +end +json.is_pinned @project.has_pinned_users.include?(current_user) \ No newline at end of file diff --git a/app/views/users/is_pinned_projects/index.json.jbuilder b/app/views/users/is_pinned_projects/index.json.jbuilder new file mode 100644 index 000000000..facc158b9 --- /dev/null +++ b/app/views/users/is_pinned_projects/index.json.jbuilder @@ -0,0 +1,4 @@ +json.total_count @is_pinned_projects.total_count +json.projects @is_pinned_projects.each do |project| + json.partial! "projects/project_detail", project: project +end \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index ae121bb08..d61acaf8e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -266,6 +266,11 @@ Rails.application.routes.draw do end end resources :headmaps, only: [:index] + resources :is_pinned_projects, only: [:index] do + collection do + post :pin + end + end resources :organizations, only: [:index] # resources :projects, only: [:index] # resources :subjects, only: [:index] diff --git a/db/migrate/20210527024043_create_pinned_projects.rb b/db/migrate/20210527024043_create_pinned_projects.rb new file mode 100644 index 000000000..50345cebc --- /dev/null +++ b/db/migrate/20210527024043_create_pinned_projects.rb @@ -0,0 +1,11 @@ +class CreatePinnedProjects < ActiveRecord::Migration[5.2] + def change + create_table :pinned_projects do |t| + t.references :user + t.references :project + t.integer :position, default: 0 + + t.timestamps + end + end +end diff --git a/public/docs/api.html b/public/docs/api.html index 9f52b9066..9bd9bb6ea 100644 --- a/public/docs/api.html +++ b/public/docs/api.html @@ -331,6 +331,12 @@
  • 获取当前登陆用户信息
  • +
  • + 获取用户星标项目 +
  • +
  • + 用户添加星标项目 +
  • 获取用户贡献度
  • @@ -590,7 +596,7 @@ Success — a happy kitten is an authenticated kitten!

    Users

    获取当前登陆用户信息

    @@ -652,7 +658,235 @@ Success — a happy kitten is an authenticated kitten! -

    获取用户贡献度

    +

    获取用户星标项目

    +

    获取用户星标项目

    + +
    +

    示例:

    +
    +
    curl -X GET http://localhost:3000/api/users/yystopf/is_pinned_projects.json
    +
    await octokit.request('GET /api/users/:login/is_pinned_projects.json')
    +

    HTTP 请求

    +

    GET api/users/:login/is_pinned_projects.json

    +

    返回字段说明:

    +
    参数
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    参数类型字段说明
    total_countint星标项目数量
    identifierstring项目标识
    namestring项目名称
    descriptionstring项目描述
    visitsint项目访问数量
    praises_countint项目点赞数量
    watchers_countint项目关注数量
    issues_countint项目issue数量
    pull_requests_countint项目合并请求数量
    forked_countint项目复刻数量
    is_publicbool项目是否公开
    mirror_urlstring镜像地址
    typeint项目类型 0 普通项目 1 普通镜像项目 2 同步镜像项目
    time_agostring上次更新时间
    open_devopsint是否开启devops
    forked_from_project_idintfork项目id
    platformstring项目平台
    author.namestring项目拥有者名称
    author.typestring项目拥有者类型
    author.loginstring项目拥有者用户名
    author.image_urlstring项目拥有者头像
    category.namestring项目分类名称
    language.namestring项目语言名称
    + +
    +

    返回的JSON示例:

    +
    +
    {
    +    "total_count": 1,
    +    "projects": [
    +        {
    +            "id": 89,
    +            "repo_id": 89,
    +            "identifier": "monkey",
    +            "name": "boke",
    +            "description": "dkkd",
    +            "visits": 4,
    +            "praises_count": 0,
    +            "watchers_count": 0,
    +            "issues_count": 0,
    +            "pull_requests_count": 0,
    +            "forked_count": 0,
    +            "is_public": true,
    +            "mirror_url": "https://github.com/viletyy/monkey.git",
    +            "type": 1,
    +            "last_update_time": 1619685144,
    +            "time_ago": "27天前",
    +            "forked_from_project_id": null,
    +            "open_devops": false,
    +            "platform": "forge",
    +            "author": {
    +                "name": "测试组织",
    +                "type": "Organization",
    +                "login": "ceshi_org",
    +                "image_url": "images/avatars/Organization/9?t=1612706073"
    +            },
    +            "category": {
    +                "id": 3,
    +                "name": "深度学习"
    +            },
    +            "language": {
    +                "id": 2,
    +                "name": "C"
    +            }
    +        }
    +    ]
    +}
    +
    + +

    用户添加星标项目

    +

    用户添加星标项目

    + +
    +

    示例:

    +
    +
    curl -X POST http://localhost:3000/api/users/yystopf/is_pinned_projects/pin.json
    +
    await octokit.request('GET /api/users/:login/is_pinned_projects/pin.json')
    +

    HTTP 请求

    +

    POST /api/users/:login/is_pinned_projects/pin.json

    +

    请求字段说明:

    同时设定多个星标项目

    + + + + + + + + + + + + +
    参数类型字段说明
    is_pinned_project_idsarray设定为星标项目的id
    +

    只设定一个星标项目

    + + + + + + + + + + + + +
    参数类型字段说明
    is_pinned_project_idinteger设定为星标项目的id
    + +
    +

    返回的JSON示例:

    +
    +
    {
    +    "status": 0,
    +    "message": "success"
    +}
    +

    获取用户贡献度

    获取用户贡献度

    @@ -660,9 +894,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/headmaps.json
     
    await octokit.request('GET /api/users/:login/headmaps.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET api/users/:login/headmaps.json

    -

    返回字段说明:

    +

    返回字段说明:

    @@ -791,9 +1025,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/applied_messages.json
     
    await octokit.request('GET /api/users/:login/applied_messages.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_messages.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -807,7 +1041,7 @@ Success — a happy kitten is an authenticated kitten!
    参数用户标识
    -

    返回字段说明:

    +

    返回字段说明:

    @@ -1028,9 +1262,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/applied_transfer_projects.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1044,7 +1278,7 @@ Success — a happy kitten is an authenticated kitten!
    参数用户标识
    -

    返回字段说明:

    +

    返回字段说明:

    @@ -1220,9 +1454,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/accept.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/accept.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects/:id/accept.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1241,7 +1475,7 @@ Success — a happy kitten is an authenticated kitten!
    参数迁移id
    -

    返回字段说明:

    +

    返回字段说明:

    @@ -1411,9 +1645,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/refuse.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/refuse.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects/:id/refuse.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1432,7 +1666,7 @@ Success — a happy kitten is an authenticated kitten!
    参数迁移id
    -

    返回字段说明:

    +

    返回字段说明:

    diff --git a/spec/models/pinned_project_spec.rb b/spec/models/pinned_project_spec.rb new file mode 100644 index 000000000..cda43562e --- /dev/null +++ b/spec/models/pinned_project_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe PinnedProject, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end From ff1c80d1deed89146c583bc28d2f684195fc35f4 Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Thu, 27 May 2021 16:40:15 +0800 Subject: [PATCH 05/51] add: user project trends --- .../users/is_pinned_projects_controller.rb | 3 ++- .../users/project_trends_controller.rb | 11 ++++++++++ .../users/statistics_controller.rb | 2 ++ .../issues/_simple_issue_item.json.jbuilder | 3 +++ .../project_trends/_detail.json.jbuilder | 17 ++++++++++++++++ app/views/project_trends/index.json.jbuilder | 20 ++----------------- .../users/project_trends/index.json.jbuilder | 4 ++++ config/routes.rb | 1 + 8 files changed, 42 insertions(+), 19 deletions(-) create mode 100644 app/controllers/users/project_trends_controller.rb create mode 100644 app/controllers/users/statistics_controller.rb create mode 100644 app/views/project_trends/_detail.json.jbuilder create mode 100644 app/views/users/project_trends/index.json.jbuilder diff --git a/app/controllers/users/is_pinned_projects_controller.rb b/app/controllers/users/is_pinned_projects_controller.rb index 22ce29263..4f3f4e37e 100644 --- a/app/controllers/users/is_pinned_projects_controller.rb +++ b/app/controllers/users/is_pinned_projects_controller.rb @@ -18,9 +18,10 @@ class Users::IsPinnedProjectsController < Users::BaseController private def is_pinned_project_ids if params[:is_pinned_project_ids].present? - return params[:is_pinned_project_ids].select{|id| observed_user.full_member_projects.pluck(:id).include?(id.to_i) } + return params[:is_pinned_project_ids].select{|id| observed_user.full_member_projects.visible.pluck(:id).include?(id.to_i) } end if params[:is_pinned_project_id].present? + return observed_user.is_pinned_project_ids unless observed_user.full_member_projects.visible.pluck(:id).include?(params[:is_pinned_project_id].to_i) return observed_user.is_pinned_project_ids.include?(params[:is_pinned_project_id].to_i) ? observed_user.is_pinned_project_ids : observed_user.is_pinned_project_ids.push(params[:is_pinned_project_id].to_i) end end diff --git a/app/controllers/users/project_trends_controller.rb b/app/controllers/users/project_trends_controller.rb new file mode 100644 index 000000000..9edd56f18 --- /dev/null +++ b/app/controllers/users/project_trends_controller.rb @@ -0,0 +1,11 @@ +class Users::ProjectTrendsController < Users::BaseController + + def index + if params[:date].present? + @project_trends = observed_user.project_trends.where("DATE(created_at) = ?", params[:date]) + else + @project_trends = observed_user.project_trends + end + @project_trends = kaminari_paginate(@project_trends.includes(:trend, :project).order(created_at: :desc)) + end +end \ No newline at end of file diff --git a/app/controllers/users/statistics_controller.rb b/app/controllers/users/statistics_controller.rb new file mode 100644 index 000000000..82a3ef012 --- /dev/null +++ b/app/controllers/users/statistics_controller.rb @@ -0,0 +1,2 @@ +class Users::StatisticController < Users::BaseController +end \ No newline at end of file diff --git a/app/views/issues/_simple_issue_item.json.jbuilder b/app/views/issues/_simple_issue_item.json.jbuilder index f711253a4..3f9c22e9e 100644 --- a/app/views/issues/_simple_issue_item.json.jbuilder +++ b/app/views/issues/_simple_issue_item.json.jbuilder @@ -1,4 +1,7 @@ json.name issue.try(:subject) +json.issue_type issue.try(:issue_type) +json.status_id issue.try(:status_id) +json.priority_id issue.try(:priority_id) json.created_at format_time(issue.try(:created_on)) json.updated_at format_time(issue.try(:updated_on)) json.assign_user_name issue&.get_assign_user.try(:show_real_name) diff --git a/app/views/project_trends/_detail.json.jbuilder b/app/views/project_trends/_detail.json.jbuilder new file mode 100644 index 000000000..7ffa9f152 --- /dev/null +++ b/app/views/project_trends/_detail.json.jbuilder @@ -0,0 +1,17 @@ +json.id trend.id +json.trend_type trend.trend_type +json.action_type l("trend.#{trend.action_type}") + l("trend.#{trend.trend_type}") +json.trend_id trend.trend_id +json.user_name trend.user.try(:show_real_name) +json.user_login trend.user.login +json.user_avatar url_to_avatar(trend.user) +json.action_time time_from_now(trend.created_at) + +if trend.trend_type == "Issue" + json.partial! "issues/simple_issue_item", locals: {issue: trend.trend} +elsif trend.trend_type == "VersionRelease" + json.partial! "version_releases/simple_version_release", locals: {version: trend.trend} +else + json.name trend.trend.title + json.created_at format_time(trend.trend.created_at) +end diff --git a/app/views/project_trends/index.json.jbuilder b/app/views/project_trends/index.json.jbuilder index 159a3bdb8..6dca7bdb5 100644 --- a/app/views/project_trends/index.json.jbuilder +++ b/app/views/project_trends/index.json.jbuilder @@ -9,25 +9,9 @@ json.limit @limit json.project_trends_size @project_trends_size json.project_trends do json.array! @project_trends.to_a.each do |trend| - json.id trend.id - json.trend_type trend.trend_type - json.action_type l("trend.#{trend.action_type}") + l("trend.#{trend.trend_type}") - json.trend_id trend.trend_id - json.user_name trend.user.try(:show_real_name) - json.user_login trend.user.login - json.user_avatar url_to_avatar(trend.user) - - if trend.trend_type == "Issue" - json.partial! "issues/simple_issue_item", locals: {issue: trend.trend} - elsif trend.trend_type == "VersionRelease" - json.partial! "version_releases/simple_version_release", locals: {version: trend.trend} - else - json.name trend.trend.title - json.created_at format_time(trend.trend.created_at) - end - + #后续需要天际pullrequest 和 版本的内容 - + json.partial! "detail", trend: trend end end diff --git a/app/views/users/project_trends/index.json.jbuilder b/app/views/users/project_trends/index.json.jbuilder new file mode 100644 index 000000000..d1aab1390 --- /dev/null +++ b/app/views/users/project_trends/index.json.jbuilder @@ -0,0 +1,4 @@ +json.total_count @project_trends.total_count +json.project_trends @project_trends.each do |trend| + json.partial! "project_trends/detail", trend: trend +end \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index d61acaf8e..2363b89df 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -271,6 +271,7 @@ Rails.application.routes.draw do post :pin end end + resources :project_trends, only: [:index] resources :organizations, only: [:index] # resources :projects, only: [:index] # resources :subjects, only: [:index] From 1df95eab4dfce6883fc12e4ca12a55cf96f87933 Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Fri, 28 May 2021 15:36:05 +0800 Subject: [PATCH 06/51] add: user statistics --- .../users/statistics_controller.rb | 190 +++++++++++++++++- app/models/concerns/project_operable.rb | 1 + app/models/project.rb | 1 - app/models/user.rb | 4 +- .../projects/_project_detail.json.jbuilder | 1 + app/views/users/headmaps/index.json.jbuilder | 2 +- .../users/statistics/develop.json.jbuilder | 19 ++ app/views/users/statistics/role.json.jbuilder | 19 ++ config/routes.rb | 8 + 9 files changed, 241 insertions(+), 4 deletions(-) create mode 100644 app/views/users/statistics/develop.json.jbuilder create mode 100644 app/views/users/statistics/role.json.jbuilder diff --git a/app/controllers/users/statistics_controller.rb b/app/controllers/users/statistics_controller.rb index 82a3ef012..7ab9a4bf4 100644 --- a/app/controllers/users/statistics_controller.rb +++ b/app/controllers/users/statistics_controller.rb @@ -1,2 +1,190 @@ -class Users::StatisticController < Users::BaseController +class Users::StatisticsController < Users::BaseController + before_action :preload_develop_data, only: [:develop] + + # 近期活动统计 + def activity + date_range = (1.week.ago.to_date..Date.today).to_a + commit_request = Gitea::User::HeadmapService.call(observed_user.login, 1.week.ago.to_date.to_time.to_i, Date.today.to_time.to_i) + commit_data = commit_request[2] + @date_data = [] + @issue_data = [] + @pull_request_data = [] + @commit_data = [] + date_range.each do |date| + @date_data << date.strftime("%Y.%m.%d") + @issue_data << observed_user.issues.where("DATE(created_on) = ?", date).size + @pull_request_data << observed_user.pull_requests.where("DATE(created_at) = ?", date).size + date_commit_data = commit_data.select{|item| item["timestamp"] == date.to_time.to_i} + @commit_data << (date_commit_data.blank? ? 0 : date_commit_data[0]["contributions"].to_i) + end + render :json => {dates: @date_data, issues_count: @issue_data, pull_requests_count: @pull_request_data, commtis_count: @commit_data} + end + + # 开发能力 + def develop + if params[:start_time].present? && params[:end_time].present? + # 影响力 + @influence = (60.0 + @follow_count / (@follow_count + 10.0) * 40.0).to_i + @platform_influence = (60.0 + @platform_follow_count / (@platform_follow_count + 10.0) * 40.0).to_i + # 贡献度 + @contribution = (60.0 + @pullrequest_count / (@pullrequest_count + 10.0) * 40.0).to_i + @platform_contribution = (60.0 + @platform_pullrequest_count / (@platform_pullrequest_count + 10.0) * 40.0).to_i + # 活跃度 + @activity = (60.0 + @issues_count / (@issues_count + 10.0) * 40.0).to_i + @platform_activity = (60.0 + @platform_issues_count / (@platform_issues_count + 10.0) * 40.0).to_i + # 项目经验 + @experience = 10 * @project_count + 5 * @fork_count + @project_watchers_count + @project_praises_count + @experience = (60.0 + @experience / (@experience + 100.0) * 40.0).to_i + @platform_experience = 10 * @platform_project_count + 5 * @platform_fork_count + @platform_project_watchers_count + @platform_project_praises_count + @platform_experience = (60.0 + @platform_experience / (@platform_experience + 100.0) * 40.0).to_i + # 语言能力 + @language = (60.0 + @project_languages_count.length / (@project_languages_count.length + 5.0) * 40.0).to_i + @platform_language = (60.0 + @platform_project_languages_count.length / (@platform_project_languages_count.length + 5.0) * 40.0).to_i + # 语言百分比 + @languages_percent = Hash.new + for key in @project_languages_count.keys do + @languages_percent[key] = (@project_languages_count[key].to_f / @project_languages_count.values.sum).round(2) + end + @platform_languages_percent = Hash.new + for key in @platform_project_languages_count.keys do + @platform_languages_percent[key] = (@platform_project_languages_count[key].to_f / @platform_project_languages_count.values.sum).round(2) + end + # 各门语言分数 + @each_language_score = Hash.new + for key in @project_languages_count.keys do + @each_language_score[key] = (60.0 + @project_languages_count[key] / (@project_languages_count[key] + 5.0) * 40.0).to_i + end + @platform_each_language_score = Hash.new + for key in @platform_project_languages_count.keys do + @platform_each_language_score[key] = (60.0 + @platform_project_languages_count[key] / (@platform_project_languages_count[key] + 5.0) * 40.0).to_i + end + else + # 影响力 + @influence = (60.0 + @follow_count / (@follow_count + 20.0) * 40.0).to_i + @platform_influence = (60.0 + @platform_follow_count / (@platform_follow_count + 20.0) * 40.0).to_i + + # 贡献度 + @contribution = (60.0 + @pullrequest_count / (@pullrequest_count + 20.0) * 40.0).to_i + @platform_contribution = (60.0 + @platform_pullrequest_count / (@platform_pullrequest_count + 20.0) * 40.0).to_i + + # 活跃度 + @activity = (60.0 + @issues_count / (@issues_count + 80.0) * 40.0).to_i + @platform_activity = (60.0 + @platform_issues_count / (@platform_issues_count + 80.0) * 40.0).to_i + + # 项目经验 + @experience = 10 * @project_count + 5 * @fork_count + @project_watchers_count + @project_praises_count + @experience = (60.0 + @experience / (@experience + 100.0) * 40.0).to_i + @platform_experience = 10 * @platform_project_count + 5 * @platform_fork_count + @platform_project_watchers_count + @platform_project_praises_count + @platform_experience = (60.0 + @platform_experience / (@platform_experience + 100.0) * 40.0).to_i + # 语言能力 + @language = (60.0 + @project_languages_count.length / (@project_languages_count.length + 5.0) * 40.0).to_i + @platform_language = (60.0 + @platform_project_languages_count.length / (@platform_project_languages_count.length + 5.0) * 40.0).to_i + + # 语言百分比 + @languages_percent = Hash.new + for key in @project_languages_count.keys do + @languages_percent[key] = (@project_languages_count[key].to_f / @project_languages_count.values.sum).round(2) + end + @platform_languages_percent = Hash.new + for key in @platform_project_languages_count.keys do + @platform_languages_percent[key] = (@platform_project_languages_count[key].to_f / @platform_project_languages_count.values.sum).round(2) + end + # 各门语言分数 + @each_language_score = Hash.new + for key in @project_languages_count.keys do + @each_language_score[key] = (60.0 + @project_languages_count[key] / (@project_languages_count[key] + 5.0) * 40.0).to_i + end + @platform_each_language_score = Hash.new + for key in @platform_project_languages_count.keys do + @platform_each_language_score[key] = (60.0 + @platform_project_languages_count[key] / (@platform_project_languages_count[key] + 5.0) * 40.0).to_i + end + end + + end + + # 角色定位 + def role + full_member_projects = observed_user.full_member_projects + owner_projects = filter_member_projects_by_role("Owner") + manager_projects = filter_member_projects_by_role("Manager").where.not(id: owner_projects.ids) + developer_projects = filter_member_projects_by_role("Developer").where.not(id: owner_projects.ids + manager_projects.ids) + reporter_projects = filter_member_projects_by_role("Reporter").where.not(id: owner_projects.ids + manager_projects.ids + developer_projects.ids) + + @full_member_projects_count = full_member_projects.size + @owner_projects_count = owner_projects.size + @manager_projects_count = manager_projects.size + @developer_projects_count = developer_projects.size + @reporter_projects_count = reporter_projects.size + + end + + # 专业定位 + def major + # 参与项目 + join_normal_projects_sql = Project.members_projects(observed_user.id).to_sql + join_org_projects_sql = Project.joins(team_projects: [team: :team_users]).where(team_users: {user_id: observed_user.id}).to_sql + # 关注项目 + star_projects_sql = Project.joins(:watchers).where(watchers: {watchable_type: "Project", user_id: observed_user.id}).to_sql + # fork项目 + fork_projects_sql = Project.where(id: observed_user.fork_users.select(:id, :fork_project_id).pluck(:fork_project_id)).to_sql + major_projects = Project.from("( #{ join_normal_projects_sql} UNION #{ join_org_projects_sql } UNION #{ star_projects_sql } UNION #{fork_projects_sql}) AS projects").distinct + categories = ProjectCategory.joins(:projects).merge(Project.where(id: time_filter(major_projects, 'created_on'))).distinct.pluck(:name) + render :json => {categories: categories} + end + + private + def time_filter(collection, time_field) + if params[:start_time].present? && params[:end_time].present? + return collection.where("#{time_field} > ? AND #{time_field} < ?", Time.at(params[:start_time].to_i).beginning_of_day, Time.at(params[:end_time].to_i).end_of_day) + else + return collection + end + rescue + return collection + end + + def filter_member_projects_by_role(role) + case role + when 'Owner' + normal_projects_sql = Project.joins(members: :roles).where(user_id: observed_user.id).where(members: {user_id: observed_user.id}, roles: {name: 'Manager'}).to_sql + org_projects_sql = Project.joins(:owner, teams: :team_users).where(users: {type: 'Organization'}, teams: {authorize: "owner"}, team_users: {user_id: observed_user.id}).to_sql + when "Manager" + normal_projects_sql = Project.joins(members: :roles).where.not(user_id: observed_user.id).where(members: {user_id: observed_user.id}, roles: {name: 'Manager'}).to_sql + org_projects_sql = Project.joins(:owner, teams: :team_users).where(users: {type: 'Organization'}, teams: {authorize: "admin"}, team_users: {user_id: observed_user.id}).to_sql + when "Developer" + normal_projects_sql = Project.joins(members: :roles).where.not(user_id: observed_user.id).where(members: {user_id: observed_user.id}, roles: {name: 'Developer'}).to_sql + org_projects_sql = Project.joins(:owner, teams: :team_users).where(users: {type: 'Organization'}, teams: {authorize: "write"}, team_users: {user_id: observed_user.id}).to_sql + when "Reporter" + normal_projects_sql = Project.joins(members: :roles).where.not(user_id: observed_user.id).where(members: {user_id: observed_user.id}, roles: {name: 'Reporter'}).to_sql + org_projects_sql = Project.joins(:owner, teams: :team_users).where(users: {type: 'Organization'}, teams: {authorize: "read"}, team_users: {user_id: observed_user.id}).to_sql + end + return time_filter(Project.from("( #{normal_projects_sql} UNION #{org_projects_sql} ) AS projects").distinct, 'created_on') + end + + def preload_develop_data + # 用户被follow数量 + @follow_count = time_filter(Watcher.where(watchable: observed_user), 'created_at').count + @platform_follow_count = time_filter(Watcher.where(watchable_type: 'User'), 'created_at').count + # 用户pr数量 + @pullrequest_count = time_filter(PullRequest.where(user_id: observed_user.id), 'created_at').count + @platform_pullrequest_count = time_filter(PullRequest, 'created_at').count + # 用户issue数量 + @issues_count = time_filter(Issue.where(author_id: observed_user.id), 'created_on').count + @platform_issues_count = time_filter(Issue, 'created_on').count + # 用户总项目数 @fork_count + @project_watchers_count + @project_praises_count + @project_count = filter_member_projects_by_role("Owner").count + @platform_project_count = time_filter(Project, 'created_on').count + # 用户项目被fork数量 + @fork_count = filter_member_projects_by_role("Owner").sum("forked_count") + @platform_fork_count = time_filter(Project, 'created_on').sum("forked_count") + # 用户项目关注数 + @project_watchers_count = filter_member_projects_by_role("Owner").sum("watchers_count") + @platform_project_watchers_count = time_filter(Project, 'created_on').sum("watchers_count") + # 用户项目点赞数 + @project_praises_count = filter_member_projects_by_role("Owner").sum("praises_count") + @platform_project_praises_count = time_filter(Project, 'created_on').sum("praises_count") + # 用户不同语言项目数量 + @project_languages_count = filter_member_projects_by_role("Owner").joins(:project_language).group("project_languages.name").count + @platform_project_languages_count = time_filter(Project, 'created_on').joins(:project_language).group("project_languages.name").count + end end \ No newline at end of file diff --git a/app/models/concerns/project_operable.rb b/app/models/concerns/project_operable.rb index b8adf5c8a..e016ca1dc 100644 --- a/app/models/concerns/project_operable.rb +++ b/app/models/concerns/project_operable.rb @@ -9,6 +9,7 @@ module ProjectOperable has_many :reporters, -> { joins(:roles).where(roles: { name: 'Reporter' }) }, class_name: 'Member' has_many :writable_members, -> { joins(:roles).where.not(roles: {name: 'Reporter'}) }, class_name: 'Member' has_many :team_projects, dependent: :destroy + has_many :teams, through: :team_projects, source: :team end def set_owner_permission(creator) diff --git a/app/models/project.rb b/app/models/project.rb index 9299abcdb..8141a56bf 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -111,7 +111,6 @@ class Project < ApplicationRecord has_many :praise_treads, as: :praise_tread_object, dependent: :destroy has_and_belongs_to_many :trackers, :order => "#{Tracker.table_name}.position" has_one :project_detail, dependent: :destroy - has_many :team_projects, dependent: :destroy has_many :project_units, dependent: :destroy has_one :applied_transfer_project,-> { order created_at: :desc }, dependent: :destroy has_many :pinned_projects, dependent: :destroy diff --git a/app/models/user.rb b/app/models/user.rb index bac795dd5..56043f5f6 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -167,6 +167,8 @@ class User < Owner has_many :pinned_projects, dependent: :destroy has_many :is_pinned_projects, through: :pinned_projects, source: :project accepts_nested_attributes_for :is_pinned_projects + has_many :issues, dependent: :destroy, foreign_key: :author_id + has_many :pull_requests, dependent: :destroy # Groups and active users scope :active, lambda { where(status: STATUS_ACTIVE) } @@ -201,7 +203,7 @@ class User < Owner # 用户参与的所有项目 def full_member_projects normal_projects = Project.members_projects(self.id).to_sql - org_projects = Project.joins(team_projects: [team: :team_users]).where(team_users: {user_id: self.id}).to_sql + org_projects = Project.joins(teams: :team_users).where(team_users: {user_id: self.id}).to_sql return Project.from("( #{ normal_projects} UNION #{ org_projects } ) AS projects").distinct end diff --git a/app/views/projects/_project_detail.json.jbuilder b/app/views/projects/_project_detail.json.jbuilder index 2e256fcb4..da5d67473 100644 --- a/app/views/projects/_project_detail.json.jbuilder +++ b/app/views/projects/_project_detail.json.jbuilder @@ -17,6 +17,7 @@ json.time_ago time_from_now(project.updated_on) json.forked_from_project_id project.forked_from_project_id json.open_devops project.open_devops? json.platform project.platform +json.is_pinned @project.has_pinned_users.include?(current_user) json.author do if project.educoder? project_educoder = project.project_educoder diff --git a/app/views/users/headmaps/index.json.jbuilder b/app/views/users/headmaps/index.json.jbuilder index 7011b2559..0e6a540b5 100644 --- a/app/views/users/headmaps/index.json.jbuilder +++ b/app/views/users/headmaps/index.json.jbuilder @@ -1,5 +1,5 @@ json.total_contributions @headmaps.collect{|map| map["contributions"]}.reduce(0, :+) json.headmaps @headmaps.each do |map| - json.date map["timestamp"] + json.date Time.at(map["timestamp"].to_i).strftime("%Y-%m-%d") json.contributions map["contributions"] end diff --git a/app/views/users/statistics/develop.json.jbuilder b/app/views/users/statistics/develop.json.jbuilder new file mode 100644 index 000000000..9d530fbbe --- /dev/null +++ b/app/views/users/statistics/develop.json.jbuilder @@ -0,0 +1,19 @@ +json.platform do + json.influence @platform_influence + json.contribution @platform_contribution + json.activity @platform_activity + json.experience @platform_experience + json.language @platform_language + json.languages_percent @platform_languages_percent + json.each_language_score @platform_each_language_score +end + +json.user do + json.influence @influence + json.contribution @contribution + json.activity @activity + json.experience @experience + json.language @language + json.languages_percent @languages_percent + json.each_language_score @each_language_score +end \ No newline at end of file diff --git a/app/views/users/statistics/role.json.jbuilder b/app/views/users/statistics/role.json.jbuilder new file mode 100644 index 000000000..5ca290586 --- /dev/null +++ b/app/views/users/statistics/role.json.jbuilder @@ -0,0 +1,19 @@ +json.total_projects_count @full_member_projects_count +json.role do + json.owner do + json.count @owner_projects_count + json.percent (@owner_projects_count.to_f/@full_member_projects_count).round(2) + end + json.manager do + json.count @manager_projects_count + json.percent (@manager_projects_count.to_f/@full_member_projects_count).round(2) + end + json.developer do + json.count @developer_projects_count + json.percent (@developer_projects_count.to_f/@full_member_projects_count).round(2) + end + json.reporter do + json.count @reporter_projects_count + json.percent (@reporter_projects_count.to_f/@full_member_projects_count).round(2) + end +end \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 2363b89df..cfadf4941 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -271,6 +271,14 @@ Rails.application.routes.draw do post :pin end end + resources :statistics, only: [:index] do + collection do + get :activity + get :develop + get :role + get :major + end + end resources :project_trends, only: [:index] resources :organizations, only: [:index] # resources :projects, only: [:index] From 61b19c17459d13cbdc8c33f68ad621e98524fde3 Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Fri, 28 May 2021 16:04:52 +0800 Subject: [PATCH 07/51] uupdate: api docs --- .../users/statistics_controller.rb | 2 +- app/docs/slate/source/includes/_users.md | 609 +++++++++++++- public/docs/api.html | 795 +++++++++++++++++- 3 files changed, 1346 insertions(+), 60 deletions(-) diff --git a/app/controllers/users/statistics_controller.rb b/app/controllers/users/statistics_controller.rb index 7ab9a4bf4..d508176e2 100644 --- a/app/controllers/users/statistics_controller.rb +++ b/app/controllers/users/statistics_controller.rb @@ -17,7 +17,7 @@ class Users::StatisticsController < Users::BaseController date_commit_data = commit_data.select{|item| item["timestamp"] == date.to_time.to_i} @commit_data << (date_commit_data.blank? ? 0 : date_commit_data[0]["contributions"].to_i) end - render :json => {dates: @date_data, issues_count: @issue_data, pull_requests_count: @pull_request_data, commtis_count: @commit_data} + render :json => {dates: @date_data, issues_count: @issue_data, pull_requests_count: @pull_request_data, commits_count: @commit_data} end # 开发能力 diff --git a/app/docs/slate/source/includes/_users.md b/app/docs/slate/source/includes/_users.md index b2c3ebccb..d7e8ed488 100644 --- a/app/docs/slate/source/includes/_users.md +++ b/app/docs/slate/source/includes/_users.md @@ -1,7 +1,7 @@ # Users @@ -176,6 +176,82 @@ await octokit.request('GET /api/users/:login/is_pinned_projects/pin.json') ``` +## 用户近期活动统计 +用户近期活动统计, 默认显示近一周的数据 + +> 示例: + +```shell +curl -X GET http://localhost:3000/api/users/yystopf/statistics/activity.json +``` + +```javascript +await octokit.request('GET /api/users/:login/statistics/activity.json') +``` + +### HTTP 请求 +`GET /api/users/:login/statistics/activity.json` + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|dates |array |时间 | +|issues_count |array |易修数量| +|pull_requests_count |array |合并请求数量| +|commtis_count |array |贡献数量| + + +> 返回的JSON示例: + +```json +{ + "dates": [ + "2021.05.21", + "2021.05.22", + "2021.05.23", + "2021.05.24", + "2021.05.25", + "2021.05.26", + "2021.05.27", + "2021.05.28" + ], + "issues_count": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "pull_requests_count": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "commits_count": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] +} +``` + + + ## 获取用户贡献度 获取用户贡献度 @@ -192,6 +268,12 @@ await octokit.request('GET /api/users/:login/headmaps.json') ### HTTP 请求 `GET api/users/:login/headmaps.json` + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|year |string |年份 | + ### 返回字段说明: 参数 | 类型 | 字段说明 --------- | ----------- | ----------- @@ -207,87 +289,87 @@ await octokit.request('GET /api/users/:login/headmaps.json') "total_contributions": 139, "headmaps": [ { - "date": 1612627200, + "date": "2021-02-07", "contributions": 1 }, { - "date": 1613836800, + "date": "2021-02-21", "contributions": 13 }, { - "date": 1614182400, + "date": "2021-02-25", "contributions": 5 }, { - "date": 1614528000, + "date": "2021-03-01", "contributions": 2 }, { - "date": 1614787200, + "date": "2021-03-04", "contributions": 1 }, { - "date": 1615737600, + "date": "2021-03-15", "contributions": 9 }, { - "date": 1616342400, + "date": "2021-03-22", "contributions": 14 }, { - "date": 1616515200, + "date": "2021-03-24", "contributions": 1 }, { - "date": 1617033600, + "date": "2021-03-30", "contributions": 11 }, { - "date": 1617638400, + "date": "2021-04-06", "contributions": 1 }, { - "date": 1618156800, + "date": "2021-04-12", "contributions": 1 }, { - "date": 1618243200, + "date": "2021-04-13", "contributions": 2 }, { - "date": 1618761600, + "date": "2021-04-19", "contributions": 3 }, { - "date": 1619107200, + "date": "2021-04-23", "contributions": 37 }, { - "date": 1619280000, + "date": "2021-04-25", "contributions": 2 }, { - "date": 1619366400, + "date": "2021-04-26", "contributions": 6 }, { - "date": 1619539200, + "date": "2021-04-28", "contributions": 1 }, { - "date": 1619625600, + "date": "2021-04-29", "contributions": 18 }, { - "date": 1619712000, + "date": "2021-04-30", "contributions": 9 }, { - "date": 1620057600, + "date": "2021-05-04", "contributions": 1 }, { - "date": 1620230400, + "date": "2021-05-06", "contributions": 1 } ] @@ -297,6 +379,489 @@ await octokit.request('GET /api/users/:login/headmaps.json') Success Data. +## 获取用户动态 +获取用户动态 + +> 示例: + +```shell +curl -X GET http://localhost:3000/api/users/yystopf/project_trends.json +``` + +```javascript +await octokit.request('GET /api/users/:login/project_trends.json') +``` + +### HTTP 请求 +`GET api/users/:login/project_trends.json` + + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|date |string |日期,格式: 2021-05-28 | + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|total_count |int |所选时间内的总动态数 | +|project_trends.trend_type |string|动态类型,Issue:易修,VersionRelease:版本发布,PullRequest:合并请求| +|project_trends.action_type |string|操作类型| +|project_trends.trend_id |integer|动态id| +|project_trends.user_name |string|用户名称| +|project_trends.user_login |string|用户用户名| +|project_trends.user_avatar |string|用户头像| +|project_trends.action_time |string|操作时间| +|project_trends.name |string|动态标题| + +> 返回的JSON示例: + +```json +{ + "total_count": 16, + "project_trends": [ + { + "id": 27, + "trend_type": "Issue", + "action_type": "创建了工单", + "trend_id": 18, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "21天前", + "name": "31213123123", + "issue_type": "1", + "status_id": 2, + "priority_id": 4, + "created_at": "2021-05-07 15:39", + "updated_at": "2021-05-27 15:42", + "assign_user_name": "yystopf", + "assign_user_login": "yystopf", + "issue_journal_size": 1, + "issue_journals": [] + }, + { + "id": 8, + "trend_type": "VersionRelease", + "action_type": "创建了版本发布", + "trend_id": 8, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "24天前", + "name": "heihei1", + "tag_name": "v1.0", + "target_commitish": "master", + "tarball_url": "http://localhost:10080/forgeceshiorg1/ceshi1/archive/v1.0.tar.gz", + "zipball_url": "http://localhost:10080/forgeceshiorg1/ceshi1/archive/v1.0.zip", + "url": "http://localhost:10080/api/v1/repos/forgeceshiorg1/ceshi1/releases/84", + "version_gid": "84", + "created_at": "2021-05-04 12:04" + }, + { + "id": 25, + "trend_type": "PullRequest", + "action_type": "关闭了合并请求", + "trend_id": 14, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "28天前", + "name": "13", + "created_at": "2021-04-30 15:39" + }, + { + "id": 24, + "trend_type": "PullRequest", + "action_type": "创建了合并请求", + "trend_id": 13, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "28天前", + "name": "211212", + "created_at": "2021-04-30 15:37" + }, + { + "id": 23, + "trend_type": "PullRequest", + "action_type": "创建了合并请求", + "trend_id": 12, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "28天前", + "name": "奇偶哦iu", + "created_at": "2021-04-30 10:19" + }, + { + "id": 22, + "trend_type": "PullRequest", + "action_type": "创建了合并请求", + "trend_id": 11, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "28天前", + "name": "2112123", + "created_at": "2021-04-29 18:46" + }, + { + "id": 21, + "trend_type": "PullRequest", + "action_type": "关闭了合并请求", + "trend_id": 10, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "28天前", + "name": "23123", + "created_at": "2021-04-29 18:45" + }, + { + "id": 20, + "trend_type": "PullRequest", + "action_type": "创建了合并请求", + "trend_id": 9, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "28天前", + "name": "33", + "created_at": "2021-04-29 18:37" + }, + { + "id": 19, + "trend_type": "PullRequest", + "action_type": "关闭了合并请求", + "trend_id": 8, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "28天前", + "name": "gggg", + "created_at": "2021-04-29 17:51" + }, + { + "id": 16, + "trend_type": "Issue", + "action_type": "创建了工单", + "trend_id": 8, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "1个月前", + "name": "hjhkj", + "issue_type": "1", + "status_id": 1, + "priority_id": 2, + "created_at": "2021-04-19 10:52", + "updated_at": "2021-04-19 10:52", + "assign_user_name": null, + "assign_user_login": null, + "issue_journal_size": 0, + "issue_journals": [] + }, + { + "id": 7, + "trend_type": "VersionRelease", + "action_type": "创建了版本发布", + "trend_id": 7, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "1个月前", + "name": "v3.0.1", + "tag_name": "v3.0.1", + "target_commitish": "master", + "tarball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v3.0.1.tar.gz", + "zipball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v3.0.1.zip", + "url": "http://localhost:10080/api/v1/repos/yystopf/ceshirepo1/releases/78", + "version_gid": "78", + "created_at": "2021-03-30 15:51" + }, + { + "id": 6, + "trend_type": "VersionRelease", + "action_type": "创建了版本发布", + "trend_id": 6, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "1个月前", + "name": "v3.0.0", + "tag_name": "v3.0.0", + "target_commitish": "master", + "tarball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v3.0.0.tar.gz", + "zipball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v3.0.0.zip", + "url": "http://localhost:10080/api/v1/repos/yystopf/ceshirepo1/releases/77", + "version_gid": "77", + "created_at": "2021-03-30 15:33" + }, + { + "id": 5, + "trend_type": "VersionRelease", + "action_type": "创建了版本发布", + "trend_id": 5, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "1个月前", + "name": "v1.0.0", + "tag_name": "v1.0.0", + "target_commitish": "master", + "tarball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v1.0.0.tar.gz", + "zipball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v1.0.0.zip", + "url": "http://localhost:10080/api/v1/repos/yystopf/ceshirepo1/releases/76", + "version_gid": "76", + "created_at": "2021-03-30 15:27" + }, + { + "id": 2, + "trend_type": "VersionRelease", + "action_type": "创建了版本发布", + "trend_id": 2, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "2个月前", + "name": "vvvv", + "tag_name": "v1.1", + "target_commitish": "dev", + "tarball_url": "http://localhost:10080/yystopf/virus_blog/archive/v1.1.tar.gz", + "zipball_url": "http://localhost:10080/yystopf/virus_blog/archive/v1.1.zip", + "url": "http://localhost:10080/api/v1/repos/yystopf/virus_blog/releases/6", + "version_gid": "6", + "created_at": "2021-03-15 14:18" + }, + { + "id": 2, + "trend_type": "PullRequest", + "action_type": "创建了合并请求", + "trend_id": 2, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "3个月前", + "name": "444", + "created_at": "2021-02-25 17:31" + } + ] +} +``` + + +## 用户开发能力 +用户开发能力, 默认为所有时间下的开发能力 + +> 示例: + +```shell +curl -X GET http://localhost:3000/api/users/yystopf/statistics/develop.json +``` + +```javascript +await octokit.request('GET /api/users/:login/statistics/develop.json') +``` + +### HTTP 请求 +`GET /api/users/:login/statistics/develop.json` + + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|start_time |integer |时间戳,开始时间,格式:1621526400| +|end_time |integer |时间戳,结束时间,格式:1622131200| + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|influence |int |影响力 | +|contribution |int |贡献度| +|activity |int |活跃度| +|experience |int |项目经验| +|language |int |语言能力| +|languages_percent |float |语言百分比| +|each_language_score |int |各门语言分数| + + +> 返回的JSON示例: + +```json +{ + "platform": { + "influence": 61, + "contribution": 75, + "activity": 66, + "experience": 95, + "language": 87, + "languages_percent": { + "CSS": 0.03, + "C#": 0.13, + "Ruby": 0.04, + "Go": 0.05, + "C": 0.19, + "Java": 0.34, + "Python": 0.09, + "C+": 0.01, + "C++": 0.11, + "Scala": 0.01, + "HTML": 0.01 + }, + "each_language_score": { + "CSS": 71, + "C#": 86, + "Ruby": 75, + "Go": 77, + "C": 90, + "Java": 93, + "Python": 83, + "C+": 66, + "C++": 85, + "Scala": 66, + "HTML": 66 + } + }, + "user": { + "influence": 60, + "contribution": 72, + "activity": 65, + "experience": 88, + "language": 84, + "languages_percent": { + "C": 0.25, + "C#": 0.33, + "C++": 0.13, + "CSS": 0.08, + "Go": 0.04, + "HTML": 0.04, + "Java": 0.04, + "Ruby": 0.08 + }, + "each_language_score": { + "C": 81, + "C#": 84, + "C++": 75, + "CSS": 71, + "Go": 66, + "HTML": 66, + "Java": 66, + "Ruby": 71 + } + } +} +``` + + +## 用户角色定位 +用户角色定位,默认显示所有时间下的角色定位数据 + +> 示例: + +```shell +curl -X GET http://localhost:3000/api/users/yystopf/statistics/role.json +``` + +```javascript +await octokit.request('GET /api/users/:login/statistics/role.json') +``` + +### HTTP 请求 +`GET /api/users/:login/statistics/role.json` + + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|start_time |integer |时间戳,开始时间,格式:1621526400| +|end_time |integer |时间戳,结束时间,格式:1622131200| + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|total_projects_count |int |用户所有的项目数量 | +|role.object.count |int |用户该语言下的项目数量| +|role.object.percent |float |用户该语言下的项目占比| + +> 返回的JSON示例: + +```json +{ + "total_projects_count": 27, + "role": { + "owner": { + "count": 24, + "percent": 0.89 + }, + "manager": { + "count": 1, + "percent": 0.04 + }, + "developer": { + "count": 2, + "percent": 0.07 + }, + "reporter": { + "count": 0, + "percent": 0.0 + } + } +} +``` + + +## 用户专业定位 +用户专业定位,默认显示所有时间下的专业定位数据 + +> 示例: + +```shell +curl -X GET http://localhost:3000/api/users/yystopf/statistics/major.json +``` + +```javascript +await octokit.request('GET /api/users/:login/statistics/major.json') +``` + +### HTTP 请求 +`GET /api/users/:login/statistics/major.json` + + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|start_time |integer |时间戳,开始时间,格式:1621526400| +|end_time |integer |时间戳,结束时间,格式:1622131200| + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|categories |int |用户项目分类 | + +> 返回的JSON示例: + +```json +{ + "categories": [ + "大数据", + "机器学习", + "深度学习", + "人工智能", + "智慧医疗", + "云计算" + ] +} +``` + ## 待办事项-用户通知信息 待办事项-用户通知信息 diff --git a/public/docs/api.html b/public/docs/api.html index 9bd9bb6ea..616803e4e 100644 --- a/public/docs/api.html +++ b/public/docs/api.html @@ -337,9 +337,24 @@
  • 用户添加星标项目
  • +
  • + 用户近期活动统计 +
  • 获取用户贡献度
  • +
  • + 获取用户动态 +
  • +
  • + 用户开发能力 +
  • +
  • + 用户角色定位 +
  • +
  • + 用户专业定位 +
  • 待办事项-用户通知信息
  • @@ -596,7 +611,7 @@ Success — a happy kitten is an authenticated kitten!

    Users

    获取当前登陆用户信息

    @@ -886,7 +901,96 @@ Success — a happy kitten is an authenticated kitten! "status": 0, "message": "success" } -

    获取用户贡献度

    +

    用户近期活动统计

    +

    用户近期活动统计, 默认显示近一周的数据

    + +
    +

    示例:

    +
    +
    curl -X GET http://localhost:3000/api/users/yystopf/statistics/activity.json
    +
    await octokit.request('GET /api/users/:login/statistics/activity.json')
    +

    HTTP 请求

    +

    GET /api/users/:login/statistics/activity.json

    +

    返回字段说明:

    +
    参数
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    参数类型字段说明
    datesarray时间
    issues_countarray易修数量
    pull_requests_countarray合并请求数量
    commtis_countarray贡献数量
    + +
    +

    返回的JSON示例:

    +
    +
    {
    +    "dates": [
    +        "2021.05.21",
    +        "2021.05.22",
    +        "2021.05.23",
    +        "2021.05.24",
    +        "2021.05.25",
    +        "2021.05.26",
    +        "2021.05.27",
    +        "2021.05.28"
    +    ],
    +    "issues_count": [
    +        0,
    +        0,
    +        0,
    +        0,
    +        0,
    +        0,
    +        0,
    +        0
    +    ],
    +    "pull_requests_count": [
    +        0,
    +        0,
    +        0,
    +        0,
    +        0,
    +        0,
    +        0,
    +        0
    +    ],
    +    "commits_count": [
    +        0,
    +        0,
    +        0,
    +        0,
    +        0,
    +        0,
    +        0,
    +        0
    +    ]
    +}
    +
    + +

    获取用户贡献度

    获取用户贡献度

    @@ -894,9 +998,23 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/headmaps.json
     
    await octokit.request('GET /api/users/:login/headmaps.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET api/users/:login/headmaps.json

    -

    返回字段说明:

    +

    请求字段说明:

    + + + + + + + + + + + + +
    参数类型字段说明
    yearstring年份
    +

    返回字段说明:

    @@ -928,87 +1046,87 @@ Success — a happy kitten is an authenticated kitten! "total_contributions": 139, "headmaps": [ { - "date": 1612627200, + "date": "2021-02-07", "contributions": 1 }, { - "date": 1613836800, + "date": "2021-02-21", "contributions": 13 }, { - "date": 1614182400, + "date": "2021-02-25", "contributions": 5 }, { - "date": 1614528000, + "date": "2021-03-01", "contributions": 2 }, { - "date": 1614787200, + "date": "2021-03-04", "contributions": 1 }, { - "date": 1615737600, + "date": "2021-03-15", "contributions": 9 }, { - "date": 1616342400, + "date": "2021-03-22", "contributions": 14 }, { - "date": 1616515200, + "date": "2021-03-24", "contributions": 1 }, { - "date": 1617033600, + "date": "2021-03-30", "contributions": 11 }, { - "date": 1617638400, + "date": "2021-04-06", "contributions": 1 }, { - "date": 1618156800, + "date": "2021-04-12", "contributions": 1 }, { - "date": 1618243200, + "date": "2021-04-13", "contributions": 2 }, { - "date": 1618761600, + "date": "2021-04-19", "contributions": 3 }, { - "date": 1619107200, + "date": "2021-04-23", "contributions": 37 }, { - "date": 1619280000, + "date": "2021-04-25", "contributions": 2 }, { - "date": 1619366400, + "date": "2021-04-26", "contributions": 6 }, { - "date": 1619539200, + "date": "2021-04-28", "contributions": 1 }, { - "date": 1619625600, + "date": "2021-04-29", "contributions": 18 }, { - "date": 1619712000, + "date": "2021-04-30", "contributions": 9 }, { - "date": 1620057600, + "date": "2021-05-04", "contributions": 1 }, { - "date": 1620230400, + "date": "2021-05-06", "contributions": 1 } ] @@ -1017,6 +1135,609 @@ Success — a happy kitten is an authenticated kitten! +

    获取用户动态

    +

    获取用户动态

    + +
    +

    示例:

    +
    +
    curl -X GET http://localhost:3000/api/users/yystopf/project_trends.json
    +
    await octokit.request('GET /api/users/:login/project_trends.json')
    +

    HTTP 请求

    +

    GET api/users/:login/project_trends.json

    +

    请求字段说明:

    +
    参数
    + + + + + + + + + + + +
    参数类型字段说明
    datestring日期,格式: 2021-05-28
    +

    返回字段说明:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    参数类型字段说明
    total_countint所选时间内的总动态数
    project_trends.trend_typestring动态类型,Issue:易修,VersionRelease:版本发布,PullRequest:合并请求
    project_trends.action_typestring操作类型
    project_trends.trend_idinteger动态id
    project_trends.user_namestring用户名称
    project_trends.user_loginstring用户用户名
    project_trends.user_avatarstring用户头像
    project_trends.action_timestring操作时间
    project_trends.namestring动态标题
    + +
    +

    返回的JSON示例:

    +
    +
    {
    +    "total_count": 16,
    +    "project_trends": [
    +        {
    +            "id": 27,
    +            "trend_type": "Issue",
    +            "action_type": "创建了工单",
    +            "trend_id": 18,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "21天前",
    +            "name": "31213123123",
    +            "issue_type": "1",
    +            "status_id": 2,
    +            "priority_id": 4,
    +            "created_at": "2021-05-07 15:39",
    +            "updated_at": "2021-05-27 15:42",
    +            "assign_user_name": "yystopf",
    +            "assign_user_login": "yystopf",
    +            "issue_journal_size": 1,
    +            "issue_journals": []
    +        },
    +        {
    +            "id": 8,
    +            "trend_type": "VersionRelease",
    +            "action_type": "创建了版本发布",
    +            "trend_id": 8,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "24天前",
    +            "name": "heihei1",
    +            "tag_name": "v1.0",
    +            "target_commitish": "master",
    +            "tarball_url": "http://localhost:10080/forgeceshiorg1/ceshi1/archive/v1.0.tar.gz",
    +            "zipball_url": "http://localhost:10080/forgeceshiorg1/ceshi1/archive/v1.0.zip",
    +            "url": "http://localhost:10080/api/v1/repos/forgeceshiorg1/ceshi1/releases/84",
    +            "version_gid": "84",
    +            "created_at": "2021-05-04 12:04"
    +        },
    +        {
    +            "id": 25,
    +            "trend_type": "PullRequest",
    +            "action_type": "关闭了合并请求",
    +            "trend_id": 14,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "28天前",
    +            "name": "13",
    +            "created_at": "2021-04-30 15:39"
    +        },
    +        {
    +            "id": 24,
    +            "trend_type": "PullRequest",
    +            "action_type": "创建了合并请求",
    +            "trend_id": 13,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "28天前",
    +            "name": "211212",
    +            "created_at": "2021-04-30 15:37"
    +        },
    +        {
    +            "id": 23,
    +            "trend_type": "PullRequest",
    +            "action_type": "创建了合并请求",
    +            "trend_id": 12,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "28天前",
    +            "name": "奇偶哦iu",
    +            "created_at": "2021-04-30 10:19"
    +        },
    +        {
    +            "id": 22,
    +            "trend_type": "PullRequest",
    +            "action_type": "创建了合并请求",
    +            "trend_id": 11,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "28天前",
    +            "name": "2112123",
    +            "created_at": "2021-04-29 18:46"
    +        },
    +        {
    +            "id": 21,
    +            "trend_type": "PullRequest",
    +            "action_type": "关闭了合并请求",
    +            "trend_id": 10,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "28天前",
    +            "name": "23123",
    +            "created_at": "2021-04-29 18:45"
    +        },
    +        {
    +            "id": 20,
    +            "trend_type": "PullRequest",
    +            "action_type": "创建了合并请求",
    +            "trend_id": 9,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "28天前",
    +            "name": "33",
    +            "created_at": "2021-04-29 18:37"
    +        },
    +        {
    +            "id": 19,
    +            "trend_type": "PullRequest",
    +            "action_type": "关闭了合并请求",
    +            "trend_id": 8,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "28天前",
    +            "name": "gggg",
    +            "created_at": "2021-04-29 17:51"
    +        },
    +        {
    +            "id": 16,
    +            "trend_type": "Issue",
    +            "action_type": "创建了工单",
    +            "trend_id": 8,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "1个月前",
    +            "name": "hjhkj",
    +            "issue_type": "1",
    +            "status_id": 1,
    +            "priority_id": 2,
    +            "created_at": "2021-04-19 10:52",
    +            "updated_at": "2021-04-19 10:52",
    +            "assign_user_name": null,
    +            "assign_user_login": null,
    +            "issue_journal_size": 0,
    +            "issue_journals": []
    +        },
    +        {
    +            "id": 7,
    +            "trend_type": "VersionRelease",
    +            "action_type": "创建了版本发布",
    +            "trend_id": 7,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "1个月前",
    +            "name": "v3.0.1",
    +            "tag_name": "v3.0.1",
    +            "target_commitish": "master",
    +            "tarball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v3.0.1.tar.gz",
    +            "zipball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v3.0.1.zip",
    +            "url": "http://localhost:10080/api/v1/repos/yystopf/ceshirepo1/releases/78",
    +            "version_gid": "78",
    +            "created_at": "2021-03-30 15:51"
    +        },
    +        {
    +            "id": 6,
    +            "trend_type": "VersionRelease",
    +            "action_type": "创建了版本发布",
    +            "trend_id": 6,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "1个月前",
    +            "name": "v3.0.0",
    +            "tag_name": "v3.0.0",
    +            "target_commitish": "master",
    +            "tarball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v3.0.0.tar.gz",
    +            "zipball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v3.0.0.zip",
    +            "url": "http://localhost:10080/api/v1/repos/yystopf/ceshirepo1/releases/77",
    +            "version_gid": "77",
    +            "created_at": "2021-03-30 15:33"
    +        },
    +        {
    +            "id": 5,
    +            "trend_type": "VersionRelease",
    +            "action_type": "创建了版本发布",
    +            "trend_id": 5,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "1个月前",
    +            "name": "v1.0.0",
    +            "tag_name": "v1.0.0",
    +            "target_commitish": "master",
    +            "tarball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v1.0.0.tar.gz",
    +            "zipball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v1.0.0.zip",
    +            "url": "http://localhost:10080/api/v1/repos/yystopf/ceshirepo1/releases/76",
    +            "version_gid": "76",
    +            "created_at": "2021-03-30 15:27"
    +        },
    +        {
    +            "id": 2,
    +            "trend_type": "VersionRelease",
    +            "action_type": "创建了版本发布",
    +            "trend_id": 2,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "2个月前",
    +            "name": "vvvv",
    +            "tag_name": "v1.1",
    +            "target_commitish": "dev",
    +            "tarball_url": "http://localhost:10080/yystopf/virus_blog/archive/v1.1.tar.gz",
    +            "zipball_url": "http://localhost:10080/yystopf/virus_blog/archive/v1.1.zip",
    +            "url": "http://localhost:10080/api/v1/repos/yystopf/virus_blog/releases/6",
    +            "version_gid": "6",
    +            "created_at": "2021-03-15 14:18"
    +        },
    +        {
    +            "id": 2,
    +            "trend_type": "PullRequest",
    +            "action_type": "创建了合并请求",
    +            "trend_id": 2,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "3个月前",
    +            "name": "444",
    +            "created_at": "2021-02-25 17:31"
    +        }
    +    ]
    +}
    +
    + +

    用户开发能力

    +

    用户开发能力, 默认为所有时间下的开发能力

    + +
    +

    示例:

    +
    +
    curl -X GET http://localhost:3000/api/users/yystopf/statistics/develop.json
    +
    await octokit.request('GET /api/users/:login/statistics/develop.json')
    +

    HTTP 请求

    +

    GET /api/users/:login/statistics/develop.json

    +

    请求字段说明:

    + + + + + + + + + + + + + + + + + +
    参数类型字段说明
    start_timeinteger时间戳,开始时间,格式:1621526400
    end_timeinteger时间戳,结束时间,格式:1622131200
    +

    返回字段说明:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    参数类型字段说明
    influenceint影响力
    contributionint贡献度
    activityint活跃度
    experienceint项目经验
    languageint语言能力
    languages_percentfloat语言百分比
    each_language_scoreint各门语言分数
    + +
    +

    返回的JSON示例:

    +
    +
    {
    +    "platform": {
    +        "influence": 61,
    +        "contribution": 75,
    +        "activity": 66,
    +        "experience": 95,
    +        "language": 87,
    +        "languages_percent": {
    +            "CSS": 0.03,
    +            "C#": 0.13,
    +            "Ruby": 0.04,
    +            "Go": 0.05,
    +            "C": 0.19,
    +            "Java": 0.34,
    +            "Python": 0.09,
    +            "C+": 0.01,
    +            "C++": 0.11,
    +            "Scala": 0.01,
    +            "HTML": 0.01
    +        },
    +        "each_language_score": {
    +            "CSS": 71,
    +            "C#": 86,
    +            "Ruby": 75,
    +            "Go": 77,
    +            "C": 90,
    +            "Java": 93,
    +            "Python": 83,
    +            "C+": 66,
    +            "C++": 85,
    +            "Scala": 66,
    +            "HTML": 66
    +        }
    +    },
    +    "user": {
    +        "influence": 60,
    +        "contribution": 72,
    +        "activity": 65,
    +        "experience": 88,
    +        "language": 84,
    +        "languages_percent": {
    +            "C": 0.25,
    +            "C#": 0.33,
    +            "C++": 0.13,
    +            "CSS": 0.08,
    +            "Go": 0.04,
    +            "HTML": 0.04,
    +            "Java": 0.04,
    +            "Ruby": 0.08
    +        },
    +        "each_language_score": {
    +            "C": 81,
    +            "C#": 84,
    +            "C++": 75,
    +            "CSS": 71,
    +            "Go": 66,
    +            "HTML": 66,
    +            "Java": 66,
    +            "Ruby": 71
    +        }
    +    }
    +}
    +
    + +

    用户角色定位

    +

    用户角色定位,默认显示所有时间下的角色定位数据

    + +
    +

    示例:

    +
    +
    curl -X GET http://localhost:3000/api/users/yystopf/statistics/role.json
    +
    await octokit.request('GET /api/users/:login/statistics/role.json')
    +

    HTTP 请求

    +

    GET /api/users/:login/statistics/role.json

    +

    请求字段说明:

    + + + + + + + + + + + + + + + + + +
    参数类型字段说明
    start_timeinteger时间戳,开始时间,格式:1621526400
    end_timeinteger时间戳,结束时间,格式:1622131200
    +

    返回字段说明:

    + + + + + + + + + + + + + + + + + + + + + + +
    参数类型字段说明
    total_projects_countint用户所有的项目数量
    role.object.countint用户该语言下的项目数量
    role.object.percentfloat用户该语言下的项目占比
    + +
    +

    返回的JSON示例:

    +
    +
    {
    +    "total_projects_count": 27,
    +    "role": {
    +        "owner": {
    +            "count": 24,
    +            "percent": 0.89
    +        },
    +        "manager": {
    +            "count": 1,
    +            "percent": 0.04
    +        },
    +        "developer": {
    +            "count": 2,
    +            "percent": 0.07
    +        },
    +        "reporter": {
    +            "count": 0,
    +            "percent": 0.0
    +        }
    +    }
    +}
    +
    + +

    用户专业定位

    +

    用户专业定位,默认显示所有时间下的专业定位数据

    + +
    +

    示例:

    +
    +
    curl -X GET http://localhost:3000/api/users/yystopf/statistics/major.json
    +
    await octokit.request('GET /api/users/:login/statistics/major.json')
    +

    HTTP 请求

    +

    GET /api/users/:login/statistics/major.json

    +

    请求字段说明:

    + + + + + + + + + + + + + + + + + +
    参数类型字段说明
    start_timeinteger时间戳,开始时间,格式:1621526400
    end_timeinteger时间戳,结束时间,格式:1622131200
    +

    返回字段说明:

    + + + + + + + + + + + + +
    参数类型字段说明
    categoriesint用户项目分类
    + +
    +

    返回的JSON示例:

    +
    +
    {
    +    "categories": [
    +        "大数据",
    +        "机器学习",
    +        "深度学习",
    +        "人工智能",
    +        "智慧医疗",
    +        "云计算"
    +    ]
    +}
    +
    +

    待办事项-用户通知信息

    待办事项-用户通知信息

    @@ -1025,9 +1746,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/applied_messages.json
     
    await octokit.request('GET /api/users/:login/applied_messages.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_messages.json

    -

    请求字段说明:

    +

    请求字段说明:

    @@ -1041,7 +1762,7 @@ Success — a happy kitten is an authenticated kitten!
    参数用户标识
    -

    返回字段说明:

    +

    返回字段说明:

    @@ -1262,9 +1983,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/applied_transfer_projects.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1278,7 +1999,7 @@ Success — a happy kitten is an authenticated kitten!
    参数用户标识
    -

    返回字段说明:

    +

    返回字段说明:

    @@ -1454,9 +2175,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/accept.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/accept.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects/:id/accept.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1475,7 +2196,7 @@ Success — a happy kitten is an authenticated kitten!
    参数迁移id
    -

    返回字段说明:

    +

    返回字段说明:

    @@ -1645,9 +2366,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/refuse.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/refuse.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects/:id/refuse.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1666,7 +2387,7 @@ Success — a happy kitten is an authenticated kitten!
    参数迁移id
    -

    返回字段说明:

    +

    返回字段说明:

    From 5431349d4640347047f1cb864edbcc712ac236c4 Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Fri, 28 May 2021 16:08:49 +0800 Subject: [PATCH 08/51] fix --- app/views/projects/_project_detail.json.jbuilder | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/_project_detail.json.jbuilder b/app/views/projects/_project_detail.json.jbuilder index da5d67473..c9e03fa22 100644 --- a/app/views/projects/_project_detail.json.jbuilder +++ b/app/views/projects/_project_detail.json.jbuilder @@ -17,7 +17,7 @@ json.time_ago time_from_now(project.updated_on) json.forked_from_project_id project.forked_from_project_id json.open_devops project.open_devops? json.platform project.platform -json.is_pinned @project.has_pinned_users.include?(current_user) +json.is_pinned project.has_pinned_users.include?(current_user) json.author do if project.educoder? project_educoder = project.project_educoder From 9a2b067bc185263e1cc81db4de40e3c30a5113eb Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Fri, 28 May 2021 16:53:37 +0800 Subject: [PATCH 09/51] add: user created time --- app/views/users/show.json.jbuilder | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/users/show.json.jbuilder b/app/views/users/show.json.jbuilder index e80ac7494..c529cf79f 100644 --- a/app/views/users/show.json.jbuilder +++ b/app/views/users/show.json.jbuilder @@ -17,4 +17,5 @@ json.user_composes_count @user_composes_count json.user_org_count @user_org_count json.common_projects_count @projects_common_count json.mirror_projects_count @projects_mirrior_count -json.sync_mirror_projects_count @projects_sync_mirrior_count \ No newline at end of file +json.sync_mirror_projects_count @projects_sync_mirrior_count +json.created_time format_time(@user.created_on) \ No newline at end of file From a0f0b5e3f1ac205a936fd479943d00cce79d727f Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Fri, 28 May 2021 18:00:53 +0800 Subject: [PATCH 10/51] fix: psimple issue field --- app/views/issues/_simple_issue_item.json.jbuilder | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/views/issues/_simple_issue_item.json.jbuilder b/app/views/issues/_simple_issue_item.json.jbuilder index 3f9c22e9e..d21c9fcae 100644 --- a/app/views/issues/_simple_issue_item.json.jbuilder +++ b/app/views/issues/_simple_issue_item.json.jbuilder @@ -1,7 +1,10 @@ json.name issue.try(:subject) -json.issue_type issue.try(:issue_type) +json.issue_type issue.issue_type == "1" ? "普通" : "悬赏" json.status_id issue.try(:status_id) +json.issue_status issue.issue_status.try(:name) +json.priority issue.priority.try(:name) json.priority_id issue.try(:priority_id) +json.version issue.version.try(:name) json.created_at format_time(issue.try(:created_on)) json.updated_at format_time(issue.try(:updated_on)) json.assign_user_name issue&.get_assign_user.try(:show_real_name) From 0b450c0c5f1f92c8b622084e8afd31816b33fd58 Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Mon, 31 May 2021 18:39:49 +0800 Subject: [PATCH 11/51] add: update user_info --- app/controllers/users_controller.rb | 15 ++- app/docs/slate/source/includes/_users.md | 53 +++++++- app/models/user.rb | 2 +- app/models/user_extension.rb | 6 +- app/views/users/show.json.jbuilder | 7 +- ...531100250_add_fields_to_user_extensions.rb | 8 ++ public/docs/api.html | 124 ++++++++++++++---- 7 files changed, 180 insertions(+), 35 deletions(-) create mode 100644 db/migrate/20210531100250_add_fields_to_user_extensions.rb diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 3c62b1145..4cbb2cbdf 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -72,9 +72,13 @@ class UsersController < ApplicationController end def update - @user = User.find params[:id] - @user.update!(user_params) - render_ok + return render_not_found unless @user = User.find_by_id(params[:id]) || User.find_by(login: params[:id]) + @user.attributes = user_params + if @user.save + render_ok + else + render_error(@user.errors.full_messages.join(", ")) + end end def me @@ -274,11 +278,12 @@ class UsersController < ApplicationController end def user_params - params.require(:user).permit(:nickname, :lastname, :show_realname,:login,:mail, + params.require(:user).permit(:nickname, user_extension_attributes: [ :gender, :location, :location_city, :occupation, :technical_title, - :school_id, :department_id,:identity, :student_id, :description] + :school_id, :department_id, :province, :city, + :custom_department, :identity, :student_id, :description] ) end diff --git a/app/docs/slate/source/includes/_users.md b/app/docs/slate/source/includes/_users.md index d7e8ed488..573e171eb 100644 --- a/app/docs/slate/source/includes/_users.md +++ b/app/docs/slate/source/includes/_users.md @@ -1,7 +1,7 @@ # Users @@ -47,6 +47,57 @@ await octokit.request('GET /api/users/me.json') Success Data. +## 更改用户信息 +更改用户信息 + +> 示例: + +```shell +curl -X POST http://localhost:3000/api/users/yystopf.json +``` + +```javascript +await octokit.request('PATCH/PUT /api/users/:login.json') +``` + +### HTTP 请求 +`PATCH/PUT /api/users/:login.json` + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|user.nickname |string |用户昵称 | +|user.user_extension_attributes.gender |int |性别, 0男 1女 | +|user.user_extension_attributes.province |string |省份 | +|user.user_extension_attributes.city |string |城市 | +|user.user_extension_attributes.description |string |个性签名 | +|user.user_extension_attributes.custom_department|string |单位名称 | + +> 请求的JSON示例: + +```json +{ + "user": { + "nickname": "xxx", + "user_extension_attributes": { + "gender": 0, + "province": "湖南", + "city": "长沙", + "description": "个性签名", + "custom_department": "湖南智擎科技有限公司", + } + } +} +``` + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} +``` ## 获取用户星标项目 获取用户星标项目 diff --git a/app/models/user.rb b/app/models/user.rb index 56043f5f6..e190e82ea 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -181,7 +181,7 @@ class User < Owner attr_accessor :password, :password_confirmation - delegate :gender, :department_id, :school_id, :location, :location_city, :technical_title, to: :user_extension, allow_nil: true + delegate :description, :gender, :department_id, :school_id, :location, :location_city, :technical_title, :province, :city, :custom_department, to: :user_extension, allow_nil: true before_save :update_hashed_password after_create do diff --git a/app/models/user_extension.rb b/app/models/user_extension.rb index 4afd89bd5..56eed12bd 100644 --- a/app/models/user_extension.rb +++ b/app/models/user_extension.rb @@ -22,9 +22,9 @@ # school_id :integer # description :string(255) default("") # department_id :integer -# honor :text(65535) -# edu_background :integer -# edu_entry_year :integer +# province :string(255) +# city :string(255) +# custom_department :string(255) # # Indexes # diff --git a/app/views/users/show.json.jbuilder b/app/views/users/show.json.jbuilder index c529cf79f..560c207d6 100644 --- a/app/views/users/show.json.jbuilder +++ b/app/views/users/show.json.jbuilder @@ -18,4 +18,9 @@ json.user_org_count @user_org_count json.common_projects_count @projects_common_count json.mirror_projects_count @projects_mirrior_count json.sync_mirror_projects_count @projects_sync_mirrior_count -json.created_time format_time(@user.created_on) \ No newline at end of file +json.created_time format_time(@user.created_on) +json.email @user.mail +json.province @user.province +json.city @user.city +json.custom_department @user.custom_department +json.description @user.description \ No newline at end of file diff --git a/db/migrate/20210531100250_add_fields_to_user_extensions.rb b/db/migrate/20210531100250_add_fields_to_user_extensions.rb new file mode 100644 index 000000000..880438405 --- /dev/null +++ b/db/migrate/20210531100250_add_fields_to_user_extensions.rb @@ -0,0 +1,8 @@ +class AddFieldsToUserExtensions < ActiveRecord::Migration[5.2] + def change + add_column :user_extensions, :province, :string # 省份 + add_column :user_extensions, :city, :string # 城市 + add_column :user_extensions, :custom_department, :string #自己填写的单位名称 + remove_column :users, :description + end +end diff --git a/public/docs/api.html b/public/docs/api.html index 616803e4e..e713ea1d0 100644 --- a/public/docs/api.html +++ b/public/docs/api.html @@ -331,6 +331,9 @@
  • 获取当前登陆用户信息
  • +
  • + 更改用户信息 +
  • 获取用户星标项目
  • @@ -611,7 +614,7 @@ Success — a happy kitten is an authenticated kitten!

    Users

    获取当前登陆用户信息

    @@ -673,7 +676,80 @@ Success — a happy kitten is an authenticated kitten! -

    获取用户星标项目

    +

    更改用户信息

    +

    更改用户信息

    + +
    +

    示例:

    +
    +
    curl -X POST http://localhost:3000/api/users/yystopf.json
    +
    await octokit.request('PATCH/PUT /api/users/:login.json')
    +

    HTTP 请求

    +

    PATCH/PUT /api/users/:login.json

    +

    请求字段说明:

    +
    参数
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    参数类型字段说明
    user.nicknamestring用户昵称
    user.user_extension_attributes.genderint性别, 0男 1女
    user.user_extension_attributes.provincestring省份
    user.user_extension_attributes.citystring城市
    user.user_extension_attributes.descriptionstring个性签名
    user.user_extension_attributes.custom_departmentstring单位名称
    + +
    +

    请求的JSON示例:

    +
    +
    {
    +    "user": {
    +        "nickname": "xxx",
    +        "user_extension_attributes": {
    +            "gender": 0,
    +            "province": "湖南",
    +            "city": "长沙",
    +            "description": "个性签名",
    +            "custom_department": "湖南智擎科技有限公司",
    +        }
    +    }
    +}
    +
    +
    +

    返回的JSON示例:

    +
    +
    {
    +    "status": 0,
    +    "message": "success"
    +}
    +

    获取用户星标项目

    获取用户星标项目

    @@ -681,7 +757,7 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/is_pinned_projects.json
     
    await octokit.request('GET /api/users/:login/is_pinned_projects.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET api/users/:login/is_pinned_projects.json

    返回字段说明:

    @@ -863,9 +939,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X POST http://localhost:3000/api/users/yystopf/is_pinned_projects/pin.json
     
    await octokit.request('GET /api/users/:login/is_pinned_projects/pin.json')
    -

    HTTP 请求

    +

    HTTP 请求

    POST /api/users/:login/is_pinned_projects/pin.json

    -

    请求字段说明:

    同时设定多个星标项目

    +

    请求字段说明:

    同时设定多个星标项目

    @@ -909,7 +985,7 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/statistics/activity.json
     
    await octokit.request('GET /api/users/:login/statistics/activity.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/statistics/activity.json

    返回字段说明:

    参数
    @@ -998,9 +1074,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/headmaps.json
     
    await octokit.request('GET /api/users/:login/headmaps.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET api/users/:login/headmaps.json

    -

    请求字段说明:

    +

    请求字段说明:

    @@ -1143,9 +1219,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/project_trends.json
     
    await octokit.request('GET /api/users/:login/project_trends.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET api/users/:login/project_trends.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1460,9 +1536,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/statistics/develop.json
     
    await octokit.request('GET /api/users/:login/statistics/develop.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/statistics/develop.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1603,9 +1679,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/statistics/role.json
     
    await octokit.request('GET /api/users/:login/statistics/role.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/statistics/role.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1685,9 +1761,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/statistics/major.json
     
    await octokit.request('GET /api/users/:login/statistics/major.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/statistics/major.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1746,9 +1822,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/applied_messages.json
     
    await octokit.request('GET /api/users/:login/applied_messages.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_messages.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1983,9 +2059,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/applied_transfer_projects.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -2175,9 +2251,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/accept.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/accept.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects/:id/accept.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -2366,9 +2442,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/refuse.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/refuse.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects/:id/refuse.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    From 4a1b857655676b8bf8c4bddf6fb661559619f4f6 Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Mon, 31 May 2021 18:46:39 +0800 Subject: [PATCH 12/51] fix --- db/migrate/20210531100250_add_fields_to_user_extensions.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/migrate/20210531100250_add_fields_to_user_extensions.rb b/db/migrate/20210531100250_add_fields_to_user_extensions.rb index 880438405..890cd35ae 100644 --- a/db/migrate/20210531100250_add_fields_to_user_extensions.rb +++ b/db/migrate/20210531100250_add_fields_to_user_extensions.rb @@ -3,6 +3,6 @@ class AddFieldsToUserExtensions < ActiveRecord::Migration[5.2] add_column :user_extensions, :province, :string # 省份 add_column :user_extensions, :city, :string # 城市 add_column :user_extensions, :custom_department, :string #自己填写的单位名称 - remove_column :users, :description + # remove_column :users, :description end end From 2ad963cdf1bb3eacee78afcfcc1483a458d5bd5f Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Tue, 1 Jun 2021 10:07:01 +0800 Subject: [PATCH 13/51] add: update user image --- app/controllers/application_controller.rb | 19 +++++++++++++++++++ .../organizations/organizations_controller.rb | 19 ------------------- app/controllers/users_controller.rb | 6 ++++-- app/docs/slate/source/includes/_users.md | 3 ++- app/queries/projects/list_my_query.rb | 2 +- public/docs/api.html | 7 ++++++- 6 files changed, 32 insertions(+), 24 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 6875b8155..8536147ca 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -773,7 +773,26 @@ class ApplicationController < ActionController::Base def base_url request.base_url end + + def convert_image! + @image = params[:image] || user_params[:image] + return unless @image.present? + max_size = EduSetting.get('upload_avatar_max_size') || 2 * 1024 * 1024 # 2M + if @image.class == ActionDispatch::Http::UploadedFile + render_error('请上传文件') if @image.size.zero? + render_error('文件大小超过限制') if @image.size > max_size.to_i + else + image = @image.to_s.strip + return render_error('请上传正确的图片') if image.blank? + @image = Util.convert_base64_image(image, max_size: max_size.to_i) + end + rescue Base64ImageConverter::Error => ex + render_error(ex.message) + end + def avatar_path(object) + ApplicationController.helpers.disk_filename(object.class, object.id) + end private def object_not_found diff --git a/app/controllers/organizations/organizations_controller.rb b/app/controllers/organizations/organizations_controller.rb index 29cb15a6a..7be9390d7 100644 --- a/app/controllers/organizations/organizations_controller.rb +++ b/app/controllers/organizations/organizations_controller.rb @@ -70,25 +70,6 @@ class Organizations::OrganizationsController < Organizations::BaseController end private - def convert_image! - return unless params[:image].present? - max_size = EduSetting.get('upload_avatar_max_size') || 2 * 1024 * 1024 # 2M - if params[:image].class == ActionDispatch::Http::UploadedFile - @image = params[:image] - render_error('请上传文件') if @image.size.zero? - render_error('文件大小超过限制') if @image.size > max_size.to_i - else - image = params[:image].to_s.strip - return render_error('请上传正确的图片') if image.blank? - @image = Util.convert_base64_image(image, max_size: max_size.to_i) - end - rescue Base64ImageConverter::Error => ex - render_error(ex.message) - end - - def avatar_path(organization) - ApplicationController.helpers.disk_filename(organization.class, organization.id) - end def organization_params params.permit(:name, :description, :website, :location, diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 4cbb2cbdf..6c28271db 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -6,6 +6,7 @@ class UsersController < ApplicationController before_action :check_user_exist, only: [:show, :homepage_info,:projects, :watch_users, :fan_users, :hovercard] before_action :require_login, only: %i[me list sync_user_info] before_action :connect_to_ci_db, only: [:get_user_info] + before_action :convert_image!, only: [:update] skip_before_action :check_sign, only: [:attachment_show] def connect_to_ci_db(options={}) @@ -73,7 +74,8 @@ class UsersController < ApplicationController def update return render_not_found unless @user = User.find_by_id(params[:id]) || User.find_by(login: params[:id]) - @user.attributes = user_params + Util.write_file(@image, avatar_path(@user)) if user_params[:image].present? + @user.attributes = user_params.except(:image) if @user.save render_ok else @@ -278,7 +280,7 @@ class UsersController < ApplicationController end def user_params - params.require(:user).permit(:nickname, + params.require(:user).permit(:nickname, :image, user_extension_attributes: [ :gender, :location, :location_city, :occupation, :technical_title, diff --git a/app/docs/slate/source/includes/_users.md b/app/docs/slate/source/includes/_users.md index 573e171eb..b72ee0c12 100644 --- a/app/docs/slate/source/includes/_users.md +++ b/app/docs/slate/source/includes/_users.md @@ -1,7 +1,7 @@ # Users @@ -67,6 +67,7 @@ await octokit.request('PATCH/PUT /api/users/:login.json') 参数 | 类型 | 字段说明 --------- | ----------- | ----------- |user.nickname |string |用户昵称 | +|user.image |string/file |用户头像 | |user.user_extension_attributes.gender |int |性别, 0男 1女 | |user.user_extension_attributes.province |string |省份 | |user.user_extension_attributes.city |string |城市 | diff --git a/app/queries/projects/list_my_query.rb b/app/queries/projects/list_my_query.rb index 5bda56120..5c508c961 100644 --- a/app/queries/projects/list_my_query.rb +++ b/app/queries/projects/list_my_query.rb @@ -53,7 +53,7 @@ class Projects::ListMyQuery < ApplicationQuery q = projects.ransack(name_or_identifier_cont: params[:search]) - scope = q.result.includes(:project_category, :project_language,:owner, :repository) + scope = q.result.includes(:project_category, :project_language,:owner, :repository, :has_pinned_users) sort = params[:sort_by] || "updated_on" sort_direction = params[:sort_direction] || "desc" diff --git a/public/docs/api.html b/public/docs/api.html index e713ea1d0..71753c32b 100644 --- a/public/docs/api.html +++ b/public/docs/api.html @@ -614,7 +614,7 @@ Success — a happy kitten is an authenticated kitten!

    Users

    获取当前登陆用户信息

    @@ -700,6 +700,11 @@ Success — a happy kitten is an authenticated kitten!
    + + + + + From df6da37b95255236f8ece69f2df6a62bf023010f Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Wed, 2 Jun 2021 15:29:00 +0800 Subject: [PATCH 14/51] fix: some bug --- app/views/project_trends/_detail.json.jbuilder | 4 ++-- app/views/users/_watch_user_detail.json.jbuilder | 2 +- app/views/users/watch_users.json.jbuilder | 2 +- config/locales/zh-CN.yml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/views/project_trends/_detail.json.jbuilder b/app/views/project_trends/_detail.json.jbuilder index 7ffa9f152..75bcf2237 100644 --- a/app/views/project_trends/_detail.json.jbuilder +++ b/app/views/project_trends/_detail.json.jbuilder @@ -12,6 +12,6 @@ if trend.trend_type == "Issue" elsif trend.trend_type == "VersionRelease" json.partial! "version_releases/simple_version_release", locals: {version: trend.trend} else - json.name trend.trend.title - json.created_at format_time(trend.trend.created_at) + json.name trend.trend&.title + json.created_at format_time(trend.trend&.created_at) end diff --git a/app/views/users/_watch_user_detail.json.jbuilder b/app/views/users/_watch_user_detail.json.jbuilder index 80a711626..8c4881bcc 100644 --- a/app/views/users/_watch_user_detail.json.jbuilder +++ b/app/views/users/_watch_user_detail.json.jbuilder @@ -3,7 +3,7 @@ json.format_time target.created_at.strftime("%Y-%m-%d") json.name user.try(:show_real_name) json.login user.try(:login) json.image_url url_to_avatar(user) -json.is_current_user current_user.try(:id) == target.user_id +json.is_current_user current_user.try(:id) == user.id json.is_watch current_user&.watched?(user) diff --git a/app/views/users/watch_users.json.jbuilder b/app/views/users/watch_users.json.jbuilder index b265e2e0a..ed2697f0c 100644 --- a/app/views/users/watch_users.json.jbuilder +++ b/app/views/users/watch_users.json.jbuilder @@ -1,7 +1,7 @@ json.count @watchers_count json.users do json.array! @watchers do |watcher| - json.partial! "/users/watch_user_detail", locals: {target: watcher, user: watcher.watchable} + json.partial! "/users/watch_user_detail", target: watcher, user: watcher.watchable end # json.partial! "/users/watch_user_detail", collection: @watchers, as: :target end \ No newline at end of file diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index c040f9bd1..db1030163 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -15,7 +15,7 @@ zh-CN: 'refused': '已拒绝' 'agreed': '已同意' trend: - Issue: 工单 + Issue: 易修(Issue) PullRequest: 合并请求 VersionRelease: 版本发布 create: 创建了 From 96a8da5d26d557b74c56c73fad578ee0d7de1020 Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Wed, 2 Jun 2021 16:40:40 +0800 Subject: [PATCH 15/51] add: pinned projects order by position --- .../users/is_pinned_projects_controller.rb | 19 +++- app/docs/slate/source/includes/_users.md | 44 ++++++++- .../is_pinned_projects/index.json.jbuilder | 4 +- config/routes.rb | 2 +- public/docs/api.html | 91 ++++++++++++++----- 5 files changed, 134 insertions(+), 26 deletions(-) diff --git a/app/controllers/users/is_pinned_projects_controller.rb b/app/controllers/users/is_pinned_projects_controller.rb index 4f3f4e37e..1ddadd277 100644 --- a/app/controllers/users/is_pinned_projects_controller.rb +++ b/app/controllers/users/is_pinned_projects_controller.rb @@ -1,7 +1,7 @@ class Users::IsPinnedProjectsController < Users::BaseController before_action :private_user_resources!, only: [:pin] def index - @is_pinned_projects = observed_user.is_pinned_projects.includes(:project_category, :project_language, :repository).order(position: :desc) + @is_pinned_projects = observed_user.pinned_projects.order(position: :desc, created_at: :asc).includes(project: [:project_category, :project_language, :repository]).order(position: :desc) @is_pinned_projects = kaminari_paginate(@is_pinned_projects) end @@ -15,6 +15,19 @@ class Users::IsPinnedProjectsController < Users::BaseController tip_exception(e.message) end + def update + @pinned_project = PinnedProject.find_by_id(params[:id]) + @pinned_project.attributes = pinned_project_params + if @pinned_project.save + render_ok + else + render_error + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + private def is_pinned_project_ids if params[:is_pinned_project_ids].present? @@ -25,4 +38,8 @@ class Users::IsPinnedProjectsController < Users::BaseController return observed_user.is_pinned_project_ids.include?(params[:is_pinned_project_id].to_i) ? observed_user.is_pinned_project_ids : observed_user.is_pinned_project_ids.push(params[:is_pinned_project_id].to_i) end end + + def pinned_project_params + params.require(:pinned_project).permit(:position) + end end \ No newline at end of file diff --git a/app/docs/slate/source/includes/_users.md b/app/docs/slate/source/includes/_users.md index b72ee0c12..5771f757f 100644 --- a/app/docs/slate/source/includes/_users.md +++ b/app/docs/slate/source/includes/_users.md @@ -1,7 +1,7 @@ # Users @@ -53,7 +53,7 @@ await octokit.request('GET /api/users/me.json') > 示例: ```shell -curl -X POST http://localhost:3000/api/users/yystopf.json +curl -X PATCH/PUT http://localhost:3000/api/users/yystopf.json ``` ```javascript @@ -141,6 +141,7 @@ await octokit.request('GET /api/users/:login/is_pinned_projects.json') |author.image_url |string |项目拥有者头像| |category.name |string |项目分类名称| |language.name |string |项目语言名称| +|position |int |项目排序| > 返回的JSON示例: @@ -228,6 +229,45 @@ await octokit.request('GET /api/users/:login/is_pinned_projects/pin.json') ``` +## 星标项目展示排序 +星标项目展示排序 + +> 示例: + +```shell +curl -X PATCH http://localhost:3000/api/users/yystopf/is_pinned_projects/11.json +``` + +```javascript +await octokit.request('PATCH/PUT /api/users/:login/is_pinned_projects/:id.json') +``` + +### HTTP 请求 +`PATCH/PUT /api/users/:login/is_pinned_projects/:id.json` + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|pinned_projects.position |int |排序,数字越大排名越前 | + +> 请求的JSON示例: + +```json +{ + "pinned_project": { + "position": 1 + } +} +``` + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} +``` ## 用户近期活动统计 用户近期活动统计, 默认显示近一周的数据 diff --git a/app/views/users/is_pinned_projects/index.json.jbuilder b/app/views/users/is_pinned_projects/index.json.jbuilder index facc158b9..a96ecf986 100644 --- a/app/views/users/is_pinned_projects/index.json.jbuilder +++ b/app/views/users/is_pinned_projects/index.json.jbuilder @@ -1,4 +1,6 @@ json.total_count @is_pinned_projects.total_count json.projects @is_pinned_projects.each do |project| - json.partial! "projects/project_detail", project: project + json.partial! "projects/project_detail", project: project&.project + json.id project.id + json.position project.position end \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index cfadf4941..1160a4072 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -266,7 +266,7 @@ Rails.application.routes.draw do end end resources :headmaps, only: [:index] - resources :is_pinned_projects, only: [:index] do + resources :is_pinned_projects, only: [:index, :update] do collection do post :pin end diff --git a/public/docs/api.html b/public/docs/api.html index 71753c32b..c8fa29fa2 100644 --- a/public/docs/api.html +++ b/public/docs/api.html @@ -340,6 +340,9 @@
  • 用户添加星标项目
  • +
  • + 星标项目展示排序 +
  • 用户近期活动统计
  • @@ -614,7 +617,7 @@ Success — a happy kitten is an authenticated kitten!

    Users

    获取当前登陆用户信息

    @@ -682,7 +685,7 @@ Success — a happy kitten is an authenticated kitten!

    示例:

    -
    curl -X POST http://localhost:3000/api/users/yystopf.json
    +
    curl -X PATCH/PUT http://localhost:3000/api/users/yystopf.json
     
    await octokit.request('PATCH/PUT /api/users/:login.json')
     

    HTTP 请求

    PATCH/PUT /api/users/:login.json

    @@ -887,6 +890,11 @@ Success — a happy kitten is an authenticated kitten!
    + + + + +
    参数用户昵称
    user.imagestring/file用户头像
    user.user_extension_attributes.gender int 性别, 0男 1女string 项目语言名称
    positionint项目排序
    @@ -975,6 +983,47 @@ Success — a happy kitten is an authenticated kitten! +
    +

    返回的JSON示例:

    +
    +
    {
    +    "status": 0,
    +    "message": "success"
    +}
    +

    星标项目展示排序

    +

    星标项目展示排序

    + +
    +

    示例:

    +
    +
    curl -X PATCH http://localhost:3000/api/users/yystopf/is_pinned_projects/11.json
    +
    await octokit.request('PATCH/PUT /api/users/:login/is_pinned_projects/:id.json')
    +

    HTTP 请求

    +

    PATCH/PUT /api/users/:login/is_pinned_projects/:id.json

    +

    请求字段说明:

    + + + + + + + + + + + + +
    参数类型字段说明
    pinned_projects.positionint排序,数字越大排名越前
    + +
    +

    请求的JSON示例:

    +
    +
    {
    +    "pinned_project": {
    +        "position": 1
    +    }
    +}
    +

    返回的JSON示例:

    @@ -990,7 +1039,7 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/statistics/activity.json
     
    await octokit.request('GET /api/users/:login/statistics/activity.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/statistics/activity.json

    返回字段说明:

    @@ -1079,9 +1128,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/headmaps.json
     
    await octokit.request('GET /api/users/:login/headmaps.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET api/users/:login/headmaps.json

    -

    请求字段说明:

    +

    请求字段说明:

    @@ -1224,9 +1273,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/project_trends.json
     
    await octokit.request('GET /api/users/:login/project_trends.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET api/users/:login/project_trends.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1541,9 +1590,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/statistics/develop.json
     
    await octokit.request('GET /api/users/:login/statistics/develop.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/statistics/develop.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1684,9 +1733,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/statistics/role.json
     
    await octokit.request('GET /api/users/:login/statistics/role.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/statistics/role.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1766,9 +1815,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/statistics/major.json
     
    await octokit.request('GET /api/users/:login/statistics/major.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/statistics/major.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1827,9 +1876,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/applied_messages.json
     
    await octokit.request('GET /api/users/:login/applied_messages.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_messages.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -2064,9 +2113,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/applied_transfer_projects.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -2256,9 +2305,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/accept.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/accept.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects/:id/accept.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -2447,9 +2496,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/refuse.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/refuse.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects/:id/refuse.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    From c727ccf3e603903339cdd1317d3c11ad75c72095 Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Wed, 2 Jun 2021 17:29:11 +0800 Subject: [PATCH 16/51] add: pinned projects project_id --- app/views/users/is_pinned_projects/index.json.jbuilder | 1 + 1 file changed, 1 insertion(+) diff --git a/app/views/users/is_pinned_projects/index.json.jbuilder b/app/views/users/is_pinned_projects/index.json.jbuilder index a96ecf986..7790607d6 100644 --- a/app/views/users/is_pinned_projects/index.json.jbuilder +++ b/app/views/users/is_pinned_projects/index.json.jbuilder @@ -3,4 +3,5 @@ json.projects @is_pinned_projects.each do |project| json.partial! "projects/project_detail", project: project&.project json.id project.id json.position project.position + json.project_id project.project_id end \ No newline at end of file From a0ca4d3acb5fc08f51635e19990937cd3cfe69d2 Mon Sep 17 00:00:00 2001 From: jasder Date: Wed, 2 Jun 2021 17:35:06 +0800 Subject: [PATCH 17/51] =?UTF-8?q?FIX=20=E6=96=B0=E5=BB=BA=E6=98=93?= =?UTF-8?q?=E4=BF=AEapi=E4=B8=AD=20=E6=9B=B4=E6=96=B0=E7=9B=B8=E5=85=B3cac?= =?UTF-8?q?he=20key?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/helpers/tag_chosen_helper.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/helpers/tag_chosen_helper.rb b/app/helpers/tag_chosen_helper.rb index 1e7879d18..348062c77 100644 --- a/app/helpers/tag_chosen_helper.rb +++ b/app/helpers/tag_chosen_helper.rb @@ -94,7 +94,7 @@ module TagChosenHelper def render_issue_tags(project) # project.issue_tags.last&.cache_key - cache_key = "all_issue_tags/#{project.issue_tags.maximum('updated_at')}" + cache_key = "project-#{project.id}/all_issue_tags/size-#{project.issue_tags.size}/#{project.issue_tags.maximum('updated_at')}" Rails.cache.fetch(cache_key) do project.issue_tags.select(:id, :name, :color).collect do |event| @@ -109,7 +109,7 @@ module TagChosenHelper end def render_cache_milestones(project) - cache_key = "all_milestones/#{project.versions.maximum('updated_on')}" + cache_key = "project-#{project.id}/all_milestones/size-#{project.version}/#{project.versions.maximum('updated_on')}" Rails.cache.fetch(cache_key) do project.versions.select(:id, :name, :status).collect do |event| @@ -124,7 +124,7 @@ module TagChosenHelper end def render_cache_collaborators(project) - cache_key = "all_collaborators/#{project.all_collaborators.maximum('created_on')}" + cache_key = "project-#{project.id}/all_collaborators/size-#{project.all_collaborators.size}/#{project.all_collaborators.maximum('updated_on')}" Rails.cache.fetch(cache_key) do project.all_collaborators.order(created_on: :desc).collect do |user| { From e4a40fb382d4242a0fe559e0e6f9065e3ea03651 Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Thu, 3 Jun 2021 09:48:58 +0800 Subject: [PATCH 18/51] fix: org transfer bug --- app/services/projects/transfer_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb index a2da34f09..0b4f1d998 100644 --- a/app/services/projects/transfer_service.rb +++ b/app/services/projects/transfer_service.rb @@ -34,7 +34,7 @@ class Projects::TransferService < ApplicationService def update_visit_teams if new_owner.is_a?(Organization) # 为包含组织所有项目的团队创建项目访问权限 - new_owner.build_permit_team_projects(project.id) + new_owner.build_permit_team_projects!(project.id) else project.team_projects.each(&:destroy!) end From 496867cac7208f2fa3fa87bf356aec80aa479941 Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Thu, 3 Jun 2021 10:19:33 +0800 Subject: [PATCH 19/51] add: update user more info --- app/controllers/users_controller.rb | 3 ++- app/docs/slate/source/includes/_users.md | 12 ++++++--- app/models/user.rb | 4 ++- app/models/user_extension.rb | 3 +++ app/views/users/show.json.jbuilder | 8 +++--- ...7_add_show_condition_to_user_extensions.rb | 7 +++++ public/docs/api.html | 26 ++++++++++++++++--- 7 files changed, 50 insertions(+), 13 deletions(-) create mode 100644 db/migrate/20210603020327_add_show_condition_to_user_extensions.rb diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 6c28271db..3f7cd4170 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -285,7 +285,8 @@ class UsersController < ApplicationController :gender, :location, :location_city, :occupation, :technical_title, :school_id, :department_id, :province, :city, - :custom_department, :identity, :student_id, :description] + :custom_department, :identity, :student_id, :description, + :show_email, :show_location, :show_department] ) end diff --git a/app/docs/slate/source/includes/_users.md b/app/docs/slate/source/includes/_users.md index 5771f757f..72bf724a5 100644 --- a/app/docs/slate/source/includes/_users.md +++ b/app/docs/slate/source/includes/_users.md @@ -1,7 +1,7 @@ # Users @@ -66,13 +66,17 @@ await octokit.request('PATCH/PUT /api/users/:login.json') ### 请求字段说明: 参数 | 类型 | 字段说明 --------- | ----------- | ----------- -|user.nickname |string |用户昵称 | -|user.image |string/file |用户头像 | +|user.nickname |string |用户昵称 | +|user.image |base64/file |用户头像 | |user.user_extension_attributes.gender |int |性别, 0男 1女 | |user.user_extension_attributes.province |string |省份 | |user.user_extension_attributes.city |string |城市 | -|user.user_extension_attributes.description |string |个性签名 | +|user.user_extension_attributes.description |string |简介 | |user.user_extension_attributes.custom_department|string |单位名称 | +|user.user_extension_attributes.technical_title |string |职业 | +|user.user_extension_attributes.show_email |bool |是否展示邮箱 | +|user.user_extension_attributes.show_location |bool |是否展示位置 | +|user.user_extension_attributes.show_department |bool |是否展示公司 | > 请求的JSON示例: diff --git a/app/models/user.rb b/app/models/user.rb index e190e82ea..09880b8cd 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -181,7 +181,9 @@ class User < Owner attr_accessor :password, :password_confirmation - delegate :description, :gender, :department_id, :school_id, :location, :location_city, :technical_title, :province, :city, :custom_department, to: :user_extension, allow_nil: true + delegate :description, :gender, :department_id, :school_id, :location, :location_city, + :show_email, :show_location, :show_department, + :technical_title, :province, :city, :custom_department, to: :user_extension, allow_nil: true before_save :update_hashed_password after_create do diff --git a/app/models/user_extension.rb b/app/models/user_extension.rb index 56eed12bd..47b27c08b 100644 --- a/app/models/user_extension.rb +++ b/app/models/user_extension.rb @@ -25,6 +25,9 @@ # province :string(255) # city :string(255) # custom_department :string(255) +# show_email :boolean default("0") +# show_location :boolean default("0") +# show_department :boolean default("0") # # Indexes # diff --git a/app/views/users/show.json.jbuilder b/app/views/users/show.json.jbuilder index 560c207d6..06fab129f 100644 --- a/app/views/users/show.json.jbuilder +++ b/app/views/users/show.json.jbuilder @@ -19,8 +19,8 @@ json.common_projects_count @projects_common_count json.mirror_projects_count @projects_mirrior_count json.sync_mirror_projects_count @projects_sync_mirrior_count json.created_time format_time(@user.created_on) -json.email @user.mail -json.province @user.province -json.city @user.city -json.custom_department @user.custom_department +json.email @user.show_email ? @user.mail : nil +json.province @user.show_location ? @user.province : nil +json.city @user.show_location ? @user.city : nil +json.custom_department @user.show_department ? @user.custom_department : nil json.description @user.description \ No newline at end of file diff --git a/db/migrate/20210603020327_add_show_condition_to_user_extensions.rb b/db/migrate/20210603020327_add_show_condition_to_user_extensions.rb new file mode 100644 index 000000000..e64da0b71 --- /dev/null +++ b/db/migrate/20210603020327_add_show_condition_to_user_extensions.rb @@ -0,0 +1,7 @@ +class AddShowConditionToUserExtensions < ActiveRecord::Migration[5.2] + def change + add_column :user_extensions, :show_email, :boolean, default: false + add_column :user_extensions, :show_location, :boolean, default: false + add_column :user_extensions, :show_department, :boolean, default: false + end +end diff --git a/public/docs/api.html b/public/docs/api.html index c8fa29fa2..0cf007cf1 100644 --- a/public/docs/api.html +++ b/public/docs/api.html @@ -617,7 +617,7 @@ Success — a happy kitten is an authenticated kitten!

    Users

    获取当前登陆用户信息

    @@ -704,7 +704,7 @@ Success — a happy kitten is an authenticated kitten!
    - + @@ -725,13 +725,33 @@ Success — a happy kitten is an authenticated kitten! - + + + + + + + + + + + + + + + + + + + + +
    参数
    user.imagestring/filebase64/file 用户头像
    user.user_extension_attributes.description string个性签名简介
    user.user_extension_attributes.custom_department string 单位名称
    user.user_extension_attributes.technical_titlestring职业
    user.user_extension_attributes.show_emailbool是否展示邮箱
    user.user_extension_attributes.show_locationbool是否展示位置
    user.user_extension_attributes.show_departmentbool是否展示公司
    From 422fd35f1eb1b5b5b941fe8141555df267f2d5b6 Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Thu, 27 May 2021 10:30:34 +0800 Subject: [PATCH 20/51] add: user headmap --- app/controllers/users/headmaps_controller.rb | 26 ++++ app/docs/slate/source/includes/_users.md | 124 ++++++++++++++- app/services/gitea/user/headmap_service.rb | 23 +++ app/views/users/headmaps/index.json.jbuilder | 5 + config/routes.rb | 1 + public/docs/api.html | 152 +++++++++++++++++-- 6 files changed, 321 insertions(+), 10 deletions(-) create mode 100644 app/controllers/users/headmaps_controller.rb create mode 100644 app/services/gitea/user/headmap_service.rb create mode 100644 app/views/users/headmaps/index.json.jbuilder diff --git a/app/controllers/users/headmaps_controller.rb b/app/controllers/users/headmaps_controller.rb new file mode 100644 index 000000000..81bd5771c --- /dev/null +++ b/app/controllers/users/headmaps_controller.rb @@ -0,0 +1,26 @@ +class Users::HeadmapsController < Users::BaseController + def index + result = Gitea::User::HeadmapService.call(observed_user.login, start_stamp, end_stamp) + @headmaps = result[2] + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + + private + def start_stamp + if params[:year].present? + Date.new(params[:year], 1).to_time.to_i + else + Date.today.to_time.to_i - 365*24*60*60 + end + end + + def end_stamp + if params[:year].present? + Date.new(params[:year], 1).to_time.to_i + 365*24*60*60 + else + Date.today.to_time.to_i + end + end +end \ No newline at end of file diff --git a/app/docs/slate/source/includes/_users.md b/app/docs/slate/source/includes/_users.md index 1d1afc028..982543fdc 100644 --- a/app/docs/slate/source/includes/_users.md +++ b/app/docs/slate/source/includes/_users.md @@ -1,7 +1,7 @@ # Users @@ -47,6 +47,128 @@ await octokit.request('GET /api/users/me.json') Success Data. +## 获取用户贡献度 +获取用户贡献度 + +> 示例: + +```shell +curl -X GET http://localhost:3000/api/users/yystopf/headmaps.json +``` + +```javascript +await octokit.request('GET /api/users/:login/headmaps.json') +``` + +### HTTP 请求 +`GET api/users/:login/headmaps.json` + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|total_contributions |int |所选时间内的总贡献度 | +|headmaps.date |string|时间| +|headmaps.contributions |int|贡献度| + + +> 返回的JSON示例: + +```json +{ + "total_contributions": 139, + "headmaps": [ + { + "date": 1612627200, + "contributions": 1 + }, + { + "date": 1613836800, + "contributions": 13 + }, + { + "date": 1614182400, + "contributions": 5 + }, + { + "date": 1614528000, + "contributions": 2 + }, + { + "date": 1614787200, + "contributions": 1 + }, + { + "date": 1615737600, + "contributions": 9 + }, + { + "date": 1616342400, + "contributions": 14 + }, + { + "date": 1616515200, + "contributions": 1 + }, + { + "date": 1617033600, + "contributions": 11 + }, + { + "date": 1617638400, + "contributions": 1 + }, + { + "date": 1618156800, + "contributions": 1 + }, + { + "date": 1618243200, + "contributions": 2 + }, + { + "date": 1618761600, + "contributions": 3 + }, + { + "date": 1619107200, + "contributions": 37 + }, + { + "date": 1619280000, + "contributions": 2 + }, + { + "date": 1619366400, + "contributions": 6 + }, + { + "date": 1619539200, + "contributions": 1 + }, + { + "date": 1619625600, + "contributions": 18 + }, + { + "date": 1619712000, + "contributions": 9 + }, + { + "date": 1620057600, + "contributions": 1 + }, + { + "date": 1620230400, + "contributions": 1 + } + ] +} +``` + + + ## 待办事项-用户通知信息 待办事项-用户通知信息 diff --git a/app/services/gitea/user/headmap_service.rb b/app/services/gitea/user/headmap_service.rb new file mode 100644 index 000000000..611a8b9d0 --- /dev/null +++ b/app/services/gitea/user/headmap_service.rb @@ -0,0 +1,23 @@ +class Gitea::User::HeadmapService < Gitea::ClientService + attr_reader :start_time, :end_time, :username + + def initialize(username, start_time, end_time) + @username = username + @start_time = start_time + @end_time = end_time + end + + def call + response = get(url, params) + render_response(response) + end + + private + def params + Hash.new.merge(start: start_time, end: end_time) + end + + def url + "/users/#{username}/heatmap".freeze + end +end \ No newline at end of file diff --git a/app/views/users/headmaps/index.json.jbuilder b/app/views/users/headmaps/index.json.jbuilder new file mode 100644 index 000000000..7011b2559 --- /dev/null +++ b/app/views/users/headmaps/index.json.jbuilder @@ -0,0 +1,5 @@ +json.total_contributions @headmaps.collect{|map| map["contributions"]}.reduce(0, :+) +json.headmaps @headmaps.each do |map| + json.date map["timestamp"] + json.contributions map["contributions"] +end diff --git a/config/routes.rb b/config/routes.rb index a8c97effc..ae121bb08 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -265,6 +265,7 @@ Rails.application.routes.draw do post :refuse end end + resources :headmaps, only: [:index] resources :organizations, only: [:index] # resources :projects, only: [:index] # resources :subjects, only: [:index] diff --git a/public/docs/api.html b/public/docs/api.html index f970ea84d..9f52b9066 100644 --- a/public/docs/api.html +++ b/public/docs/api.html @@ -331,6 +331,9 @@
  • 获取当前登陆用户信息
  • +
  • + 获取用户贡献度 +
  • 待办事项-用户通知信息
  • @@ -587,7 +590,7 @@ Success — a happy kitten is an authenticated kitten!

    Users

    获取当前登陆用户信息

    @@ -649,6 +652,137 @@ Success — a happy kitten is an authenticated kitten! +

    获取用户贡献度

    +

    获取用户贡献度

    + +
    +

    示例:

    +
    +
    curl -X GET http://localhost:3000/api/users/yystopf/headmaps.json
    +
    await octokit.request('GET /api/users/:login/headmaps.json')
    +

    HTTP 请求

    +

    GET api/users/:login/headmaps.json

    +

    返回字段说明:

    + + + + + + + + + + + + + + + + + + + + + + +
    参数类型字段说明
    total_contributionsint所选时间内的总贡献度
    headmaps.datestring时间
    headmaps.contributionsint贡献度
    + +
    +

    返回的JSON示例:

    +
    +
    {
    +    "total_contributions": 139,
    +    "headmaps": [
    +        {
    +            "date": 1612627200,
    +            "contributions": 1
    +        },
    +        {
    +            "date": 1613836800,
    +            "contributions": 13
    +        },
    +        {
    +            "date": 1614182400,
    +            "contributions": 5
    +        },
    +        {
    +            "date": 1614528000,
    +            "contributions": 2
    +        },
    +        {
    +            "date": 1614787200,
    +            "contributions": 1
    +        },
    +        {
    +            "date": 1615737600,
    +            "contributions": 9
    +        },
    +        {
    +            "date": 1616342400,
    +            "contributions": 14
    +        },
    +        {
    +            "date": 1616515200,
    +            "contributions": 1
    +        },
    +        {
    +            "date": 1617033600,
    +            "contributions": 11
    +        },
    +        {
    +            "date": 1617638400,
    +            "contributions": 1
    +        },
    +        {
    +            "date": 1618156800,
    +            "contributions": 1
    +        },
    +        {
    +            "date": 1618243200,
    +            "contributions": 2
    +        },
    +        {
    +            "date": 1618761600,
    +            "contributions": 3
    +        },
    +        {
    +            "date": 1619107200,
    +            "contributions": 37
    +        },
    +        {
    +            "date": 1619280000,
    +            "contributions": 2
    +        },
    +        {
    +            "date": 1619366400,
    +            "contributions": 6
    +        },
    +        {
    +            "date": 1619539200,
    +            "contributions": 1
    +        },
    +        {
    +            "date": 1619625600,
    +            "contributions": 18
    +        },
    +        {
    +            "date": 1619712000,
    +            "contributions": 9
    +        },
    +        {
    +            "date": 1620057600,
    +            "contributions": 1
    +        },
    +        {
    +            "date": 1620230400,
    +            "contributions": 1
    +        }
    +    ]
    +}
    +
    +

    待办事项-用户通知信息

    待办事项-用户通知信息

    @@ -657,7 +791,7 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/applied_messages.json
     
    await octokit.request('GET /api/users/:login/applied_messages.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_messages.json

    请求字段说明:

    @@ -673,7 +807,7 @@ Success — a happy kitten is an authenticated kitten!
    用户标识
    -

    返回字段说明:

    +

    返回字段说明:

    @@ -894,7 +1028,7 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/applied_transfer_projects.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects.json

    请求字段说明:

    参数
    @@ -910,7 +1044,7 @@ Success — a happy kitten is an authenticated kitten!
    用户标识
    -

    返回字段说明:

    +

    返回字段说明:

    @@ -1086,7 +1220,7 @@ Success — a happy kitten is an authenticated kitten!
    curl -X POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/accept.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/accept.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects/:id/accept.json

    请求字段说明:

    参数
    @@ -1107,7 +1241,7 @@ Success — a happy kitten is an authenticated kitten!
    迁移id
    -

    返回字段说明:

    +

    返回字段说明:

    @@ -1277,7 +1411,7 @@ Success — a happy kitten is an authenticated kitten!
    curl -X POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/refuse.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/refuse.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects/:id/refuse.json

    请求字段说明:

    参数
    @@ -1298,7 +1432,7 @@ Success — a happy kitten is an authenticated kitten!
    迁移id
    -

    返回字段说明:

    +

    返回字段说明:

    From ea79772bd27b099f080376e8a34d661e0d690e88 Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Thu, 27 May 2021 14:23:59 +0800 Subject: [PATCH 21/51] add: user pinned projects --- .../users/is_pinned_projects_controller.rb | 27 ++ app/docs/slate/source/includes/_users.md | 131 ++++++++- app/models/pinned_project.rb | 22 ++ app/models/project.rb | 148 +++++----- app/models/user.rb | 10 + .../projects/_project_detail.json.jbuilder | 3 + app/views/repositories/edit.json.jbuilder | 3 +- .../is_pinned_projects/index.json.jbuilder | 4 + config/routes.rb | 5 + .../20210527024043_create_pinned_projects.rb | 11 + public/docs/api.html | 266 ++++++++++++++++-- spec/models/pinned_project_spec.rb | 5 + 12 files changed, 544 insertions(+), 91 deletions(-) create mode 100644 app/controllers/users/is_pinned_projects_controller.rb create mode 100644 app/models/pinned_project.rb create mode 100644 app/views/users/is_pinned_projects/index.json.jbuilder create mode 100644 db/migrate/20210527024043_create_pinned_projects.rb create mode 100644 spec/models/pinned_project_spec.rb diff --git a/app/controllers/users/is_pinned_projects_controller.rb b/app/controllers/users/is_pinned_projects_controller.rb new file mode 100644 index 000000000..22ce29263 --- /dev/null +++ b/app/controllers/users/is_pinned_projects_controller.rb @@ -0,0 +1,27 @@ +class Users::IsPinnedProjectsController < Users::BaseController + before_action :private_user_resources!, only: [:pin] + def index + @is_pinned_projects = observed_user.is_pinned_projects.includes(:project_category, :project_language, :repository).order(position: :desc) + @is_pinned_projects = kaminari_paginate(@is_pinned_projects) + end + + def pin + observed_user.is_pinned_project_ids = is_pinned_project_ids + render_ok + rescue ActiveRecord::RecordNotFound => e + render_not_found + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + + private + def is_pinned_project_ids + if params[:is_pinned_project_ids].present? + return params[:is_pinned_project_ids].select{|id| observed_user.full_member_projects.pluck(:id).include?(id.to_i) } + end + if params[:is_pinned_project_id].present? + return observed_user.is_pinned_project_ids.include?(params[:is_pinned_project_id].to_i) ? observed_user.is_pinned_project_ids : observed_user.is_pinned_project_ids.push(params[:is_pinned_project_id].to_i) + end + end +end \ No newline at end of file diff --git a/app/docs/slate/source/includes/_users.md b/app/docs/slate/source/includes/_users.md index 982543fdc..b2c3ebccb 100644 --- a/app/docs/slate/source/includes/_users.md +++ b/app/docs/slate/source/includes/_users.md @@ -1,7 +1,7 @@ # Users @@ -47,6 +47,135 @@ await octokit.request('GET /api/users/me.json') Success Data. +## 获取用户星标项目 +获取用户星标项目 + +> 示例: + +```shell +curl -X GET http://localhost:3000/api/users/yystopf/is_pinned_projects.json +``` + +```javascript +await octokit.request('GET /api/users/:login/is_pinned_projects.json') +``` + +### HTTP 请求 +`GET api/users/:login/is_pinned_projects.json` + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|total_count |int |星标项目数量 | +|identifier |string |项目标识 | +|name |string |项目名称 | +|description |string |项目描述 | +|visits |int |项目访问数量| +|praises_count |int |项目点赞数量| +|watchers_count |int |项目关注数量| +|issues_count |int |项目issue数量| +|pull_requests_count |int |项目合并请求数量| +|forked_count |int |项目复刻数量| +|is_public |bool |项目是否公开| +|mirror_url |string |镜像地址| +|type |int |项目类型 0 普通项目 1 普通镜像项目 2 同步镜像项目| +|time_ago |string |上次更新时间| +|open_devops |int |是否开启devops| +|forked_from_project_id |int |fork项目id| +|platform |string |项目平台| +|author.name |string |项目拥有者名称| +|author.type |string |项目拥有者类型| +|author.login |string |项目拥有者用户名| +|author.image_url |string |项目拥有者头像| +|category.name |string |项目分类名称| +|language.name |string |项目语言名称| + + +> 返回的JSON示例: + +```json +{ + "total_count": 1, + "projects": [ + { + "id": 89, + "repo_id": 89, + "identifier": "monkey", + "name": "boke", + "description": "dkkd", + "visits": 4, + "praises_count": 0, + "watchers_count": 0, + "issues_count": 0, + "pull_requests_count": 0, + "forked_count": 0, + "is_public": true, + "mirror_url": "https://github.com/viletyy/monkey.git", + "type": 1, + "last_update_time": 1619685144, + "time_ago": "27天前", + "forked_from_project_id": null, + "open_devops": false, + "platform": "forge", + "author": { + "name": "测试组织", + "type": "Organization", + "login": "ceshi_org", + "image_url": "images/avatars/Organization/9?t=1612706073" + }, + "category": { + "id": 3, + "name": "深度学习" + }, + "language": { + "id": 2, + "name": "C" + } + } + ] +} +``` + + +## 用户添加星标项目 +用户添加星标项目 + +> 示例: + +```shell +curl -X POST http://localhost:3000/api/users/yystopf/is_pinned_projects/pin.json +``` + +```javascript +await octokit.request('GET /api/users/:login/is_pinned_projects/pin.json') +``` + +### HTTP 请求 +`POST /api/users/:login/is_pinned_projects/pin.json` + +### 请求字段说明: +#### 同时设定多个星标项目 +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|is_pinned_project_ids |array |设定为星标项目的id | + +#### 只设定一个星标项目 +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|is_pinned_project_id |integer |设定为星标项目的id | + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} +``` + + ## 获取用户贡献度 获取用户贡献度 diff --git a/app/models/pinned_project.rb b/app/models/pinned_project.rb new file mode 100644 index 000000000..8e47c9ea4 --- /dev/null +++ b/app/models/pinned_project.rb @@ -0,0 +1,22 @@ +# == Schema Information +# +# Table name: pinned_projects +# +# id :integer not null, primary key +# user_id :integer +# project_id :integer +# position :integer default("0") +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_pinned_projects_on_project_id (project_id) +# index_pinned_projects_on_user_id (user_id) +# + +class PinnedProject < ApplicationRecord + + belongs_to :user + belongs_to :project +end diff --git a/app/models/project.rb b/app/models/project.rb index b48680830..9299abcdb 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1,76 +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 -# praises_count :integer default("0") -# watchers_count :integer default("0") -# issues_count :integer default("0") -# pull_requests_count :integer default("0") -# language :string(255) -# versions_count :integer default("0") -# issue_tags_count :integer default("0") -# closed_issues_count :integer default("0") -# open_devops :boolean default("0") -# gitea_webhook_id :integer -# open_devops_count :integer default("0") -# recommend :boolean default("0") -# platform :integer default("0") -# license_id :integer -# ignore_id :integer -# default_branch :string(255) default("master") -# website :string(255) -# lesson_url :string(255) -# -# Indexes -# -# index_projects_on_forked_from_project_id (forked_from_project_id) -# index_projects_on_identifier (identifier) -# index_projects_on_is_public (is_public) -# index_projects_on_lft (lft) -# index_projects_on_name (name) -# index_projects_on_platform (platform) -# index_projects_on_project_type (project_type) -# index_projects_on_recommend (recommend) -# index_projects_on_rgt (rgt) -# index_projects_on_status (status) -# index_projects_on_updated_on (updated_on) -# - +# == Schema Information +# +# Table name: projects +# +# id :integer not null, primary key +# name :string(255) default(""), not null +# description :text(4294967295) +# homepage :string(255) default("") +# is_public :boolean default("1"), not null +# parent_id :integer +# created_on :datetime +# updated_on :datetime +# identifier :string(255) +# status :integer default("1"), not null +# lft :integer +# rgt :integer +# inherit_members :boolean default("0"), not null +# project_type :integer default("0") +# hidden_repo :boolean default("0"), not null +# attachmenttype :integer default("1") +# user_id :integer +# dts_test :integer default("0") +# enterprise_name :string(255) +# organization_id :integer +# project_new_type :integer +# gpid :integer +# forked_from_project_id :integer +# forked_count :integer default("0") +# publish_resource :integer default("0") +# visits :integer default("0") +# hot :integer default("0") +# invite_code :string(255) +# qrcode :string(255) +# qrcode_expiretime :integer default("0") +# script :text(65535) +# training_status :integer default("0") +# rep_identifier :string(255) +# project_category_id :integer +# project_language_id :integer +# praises_count :integer default("0") +# watchers_count :integer default("0") +# issues_count :integer default("0") +# pull_requests_count :integer default("0") +# language :string(255) +# versions_count :integer default("0") +# issue_tags_count :integer default("0") +# closed_issues_count :integer default("0") +# open_devops :boolean default("0") +# gitea_webhook_id :integer +# open_devops_count :integer default("0") +# recommend :boolean default("0") +# platform :integer default("0") +# license_id :integer +# ignore_id :integer +# default_branch :string(255) default("master") +# website :string(255) +# lesson_url :string(255) +# +# Indexes +# +# index_projects_on_forked_from_project_id (forked_from_project_id) +# index_projects_on_identifier (identifier) +# index_projects_on_is_public (is_public) +# index_projects_on_lft (lft) +# index_projects_on_name (name) +# index_projects_on_platform (platform) +# index_projects_on_project_type (project_type) +# index_projects_on_recommend (recommend) +# index_projects_on_rgt (rgt) +# index_projects_on_status (status) +# index_projects_on_updated_on (updated_on) +# + class Project < ApplicationRecord include Matchable @@ -114,6 +114,8 @@ class Project < ApplicationRecord has_many :team_projects, dependent: :destroy has_many :project_units, dependent: :destroy has_one :applied_transfer_project,-> { order created_at: :desc }, dependent: :destroy + has_many :pinned_projects, dependent: :destroy + has_many :has_pinned_users, through: :pinned_projects, source: :user after_save :check_project_members 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)} diff --git a/app/models/user.rb b/app/models/user.rb index b778c80f9..bac795dd5 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -164,6 +164,9 @@ class User < Owner has_many :organization_users, dependent: :destroy has_many :organizations, through: :organization_users + has_many :pinned_projects, dependent: :destroy + has_many :is_pinned_projects, through: :pinned_projects, source: :project + accepts_nested_attributes_for :is_pinned_projects # Groups and active users scope :active, lambda { where(status: STATUS_ACTIVE) } @@ -195,6 +198,13 @@ class User < Owner validate :validate_sensitive_string validate :validate_password_length + # 用户参与的所有项目 + def full_member_projects + normal_projects = Project.members_projects(self.id).to_sql + org_projects = Project.joins(team_projects: [team: :team_users]).where(team_users: {user_id: self.id}).to_sql + return Project.from("( #{ normal_projects} UNION #{ org_projects } ) AS projects").distinct + end + def name login end diff --git a/app/views/projects/_project_detail.json.jbuilder b/app/views/projects/_project_detail.json.jbuilder index d0b62aaa3..2e256fcb4 100644 --- a/app/views/projects/_project_detail.json.jbuilder +++ b/app/views/projects/_project_detail.json.jbuilder @@ -5,6 +5,9 @@ json.name project.name json.description Nokogiri::HTML(project.description).text json.visits project.visits json.praises_count project.praises_count.to_i +json.watchers_count project.watchers_count.to_i +json.issues_count project.issues_count.to_i +json.pull_requests_count project.pull_requests_count.to_i json.forked_count project.forked_count.to_i json.is_public project.is_public json.mirror_url project.repository&.mirror_url diff --git a/app/views/repositories/edit.json.jbuilder b/app/views/repositories/edit.json.jbuilder index 7a11411f4..e0b601f6d 100644 --- a/app/views/repositories/edit.json.jbuilder +++ b/app/views/repositories/edit.json.jbuilder @@ -12,4 +12,5 @@ json.permission render_permission(current_user, @project) json.is_transfering @project.is_transfering json.transfer do json.partial! "/users/user_simple", locals: {user: @project&.applied_transfer_project&.owner} -end \ No newline at end of file +end +json.is_pinned @project.has_pinned_users.include?(current_user) \ No newline at end of file diff --git a/app/views/users/is_pinned_projects/index.json.jbuilder b/app/views/users/is_pinned_projects/index.json.jbuilder new file mode 100644 index 000000000..facc158b9 --- /dev/null +++ b/app/views/users/is_pinned_projects/index.json.jbuilder @@ -0,0 +1,4 @@ +json.total_count @is_pinned_projects.total_count +json.projects @is_pinned_projects.each do |project| + json.partial! "projects/project_detail", project: project +end \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index ae121bb08..d61acaf8e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -266,6 +266,11 @@ Rails.application.routes.draw do end end resources :headmaps, only: [:index] + resources :is_pinned_projects, only: [:index] do + collection do + post :pin + end + end resources :organizations, only: [:index] # resources :projects, only: [:index] # resources :subjects, only: [:index] diff --git a/db/migrate/20210527024043_create_pinned_projects.rb b/db/migrate/20210527024043_create_pinned_projects.rb new file mode 100644 index 000000000..50345cebc --- /dev/null +++ b/db/migrate/20210527024043_create_pinned_projects.rb @@ -0,0 +1,11 @@ +class CreatePinnedProjects < ActiveRecord::Migration[5.2] + def change + create_table :pinned_projects do |t| + t.references :user + t.references :project + t.integer :position, default: 0 + + t.timestamps + end + end +end diff --git a/public/docs/api.html b/public/docs/api.html index 9f52b9066..9bd9bb6ea 100644 --- a/public/docs/api.html +++ b/public/docs/api.html @@ -331,6 +331,12 @@
  • 获取当前登陆用户信息
  • +
  • + 获取用户星标项目 +
  • +
  • + 用户添加星标项目 +
  • 获取用户贡献度
  • @@ -590,7 +596,7 @@ Success — a happy kitten is an authenticated kitten!

    Users

    获取当前登陆用户信息

    @@ -652,7 +658,235 @@ Success — a happy kitten is an authenticated kitten! -

    获取用户贡献度

    +

    获取用户星标项目

    +

    获取用户星标项目

    + +
    +

    示例:

    +
    +
    curl -X GET http://localhost:3000/api/users/yystopf/is_pinned_projects.json
    +
    await octokit.request('GET /api/users/:login/is_pinned_projects.json')
    +

    HTTP 请求

    +

    GET api/users/:login/is_pinned_projects.json

    +

    返回字段说明:

    +
    参数
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    参数类型字段说明
    total_countint星标项目数量
    identifierstring项目标识
    namestring项目名称
    descriptionstring项目描述
    visitsint项目访问数量
    praises_countint项目点赞数量
    watchers_countint项目关注数量
    issues_countint项目issue数量
    pull_requests_countint项目合并请求数量
    forked_countint项目复刻数量
    is_publicbool项目是否公开
    mirror_urlstring镜像地址
    typeint项目类型 0 普通项目 1 普通镜像项目 2 同步镜像项目
    time_agostring上次更新时间
    open_devopsint是否开启devops
    forked_from_project_idintfork项目id
    platformstring项目平台
    author.namestring项目拥有者名称
    author.typestring项目拥有者类型
    author.loginstring项目拥有者用户名
    author.image_urlstring项目拥有者头像
    category.namestring项目分类名称
    language.namestring项目语言名称
    + +
    +

    返回的JSON示例:

    +
    +
    {
    +    "total_count": 1,
    +    "projects": [
    +        {
    +            "id": 89,
    +            "repo_id": 89,
    +            "identifier": "monkey",
    +            "name": "boke",
    +            "description": "dkkd",
    +            "visits": 4,
    +            "praises_count": 0,
    +            "watchers_count": 0,
    +            "issues_count": 0,
    +            "pull_requests_count": 0,
    +            "forked_count": 0,
    +            "is_public": true,
    +            "mirror_url": "https://github.com/viletyy/monkey.git",
    +            "type": 1,
    +            "last_update_time": 1619685144,
    +            "time_ago": "27天前",
    +            "forked_from_project_id": null,
    +            "open_devops": false,
    +            "platform": "forge",
    +            "author": {
    +                "name": "测试组织",
    +                "type": "Organization",
    +                "login": "ceshi_org",
    +                "image_url": "images/avatars/Organization/9?t=1612706073"
    +            },
    +            "category": {
    +                "id": 3,
    +                "name": "深度学习"
    +            },
    +            "language": {
    +                "id": 2,
    +                "name": "C"
    +            }
    +        }
    +    ]
    +}
    +
    + +

    用户添加星标项目

    +

    用户添加星标项目

    + +
    +

    示例:

    +
    +
    curl -X POST http://localhost:3000/api/users/yystopf/is_pinned_projects/pin.json
    +
    await octokit.request('GET /api/users/:login/is_pinned_projects/pin.json')
    +

    HTTP 请求

    +

    POST /api/users/:login/is_pinned_projects/pin.json

    +

    请求字段说明:

    同时设定多个星标项目

    + + + + + + + + + + + + +
    参数类型字段说明
    is_pinned_project_idsarray设定为星标项目的id
    +

    只设定一个星标项目

    + + + + + + + + + + + + +
    参数类型字段说明
    is_pinned_project_idinteger设定为星标项目的id
    + +
    +

    返回的JSON示例:

    +
    +
    {
    +    "status": 0,
    +    "message": "success"
    +}
    +

    获取用户贡献度

    获取用户贡献度

    @@ -660,9 +894,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/headmaps.json
     
    await octokit.request('GET /api/users/:login/headmaps.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET api/users/:login/headmaps.json

    -

    返回字段说明:

    +

    返回字段说明:

    @@ -791,9 +1025,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/applied_messages.json
     
    await octokit.request('GET /api/users/:login/applied_messages.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_messages.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -807,7 +1041,7 @@ Success — a happy kitten is an authenticated kitten!
    参数用户标识
    -

    返回字段说明:

    +

    返回字段说明:

    @@ -1028,9 +1262,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/applied_transfer_projects.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1044,7 +1278,7 @@ Success — a happy kitten is an authenticated kitten!
    参数用户标识
    -

    返回字段说明:

    +

    返回字段说明:

    @@ -1220,9 +1454,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/accept.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/accept.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects/:id/accept.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1241,7 +1475,7 @@ Success — a happy kitten is an authenticated kitten!
    参数迁移id
    -

    返回字段说明:

    +

    返回字段说明:

    @@ -1411,9 +1645,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/refuse.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/refuse.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects/:id/refuse.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1432,7 +1666,7 @@ Success — a happy kitten is an authenticated kitten!
    参数迁移id
    -

    返回字段说明:

    +

    返回字段说明:

    diff --git a/spec/models/pinned_project_spec.rb b/spec/models/pinned_project_spec.rb new file mode 100644 index 000000000..cda43562e --- /dev/null +++ b/spec/models/pinned_project_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe PinnedProject, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end From ca8fa20c2c0b28e1a0e5ad1d8b5c6585073c833d Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Thu, 27 May 2021 16:40:15 +0800 Subject: [PATCH 22/51] add: user project trends --- .../users/is_pinned_projects_controller.rb | 3 ++- .../users/project_trends_controller.rb | 11 ++++++++++ .../users/statistics_controller.rb | 2 ++ .../issues/_simple_issue_item.json.jbuilder | 3 +++ .../project_trends/_detail.json.jbuilder | 17 ++++++++++++++++ app/views/project_trends/index.json.jbuilder | 20 ++----------------- .../users/project_trends/index.json.jbuilder | 4 ++++ config/routes.rb | 1 + 8 files changed, 42 insertions(+), 19 deletions(-) create mode 100644 app/controllers/users/project_trends_controller.rb create mode 100644 app/controllers/users/statistics_controller.rb create mode 100644 app/views/project_trends/_detail.json.jbuilder create mode 100644 app/views/users/project_trends/index.json.jbuilder diff --git a/app/controllers/users/is_pinned_projects_controller.rb b/app/controllers/users/is_pinned_projects_controller.rb index 22ce29263..4f3f4e37e 100644 --- a/app/controllers/users/is_pinned_projects_controller.rb +++ b/app/controllers/users/is_pinned_projects_controller.rb @@ -18,9 +18,10 @@ class Users::IsPinnedProjectsController < Users::BaseController private def is_pinned_project_ids if params[:is_pinned_project_ids].present? - return params[:is_pinned_project_ids].select{|id| observed_user.full_member_projects.pluck(:id).include?(id.to_i) } + return params[:is_pinned_project_ids].select{|id| observed_user.full_member_projects.visible.pluck(:id).include?(id.to_i) } end if params[:is_pinned_project_id].present? + return observed_user.is_pinned_project_ids unless observed_user.full_member_projects.visible.pluck(:id).include?(params[:is_pinned_project_id].to_i) return observed_user.is_pinned_project_ids.include?(params[:is_pinned_project_id].to_i) ? observed_user.is_pinned_project_ids : observed_user.is_pinned_project_ids.push(params[:is_pinned_project_id].to_i) end end diff --git a/app/controllers/users/project_trends_controller.rb b/app/controllers/users/project_trends_controller.rb new file mode 100644 index 000000000..9edd56f18 --- /dev/null +++ b/app/controllers/users/project_trends_controller.rb @@ -0,0 +1,11 @@ +class Users::ProjectTrendsController < Users::BaseController + + def index + if params[:date].present? + @project_trends = observed_user.project_trends.where("DATE(created_at) = ?", params[:date]) + else + @project_trends = observed_user.project_trends + end + @project_trends = kaminari_paginate(@project_trends.includes(:trend, :project).order(created_at: :desc)) + end +end \ No newline at end of file diff --git a/app/controllers/users/statistics_controller.rb b/app/controllers/users/statistics_controller.rb new file mode 100644 index 000000000..82a3ef012 --- /dev/null +++ b/app/controllers/users/statistics_controller.rb @@ -0,0 +1,2 @@ +class Users::StatisticController < Users::BaseController +end \ No newline at end of file diff --git a/app/views/issues/_simple_issue_item.json.jbuilder b/app/views/issues/_simple_issue_item.json.jbuilder index f711253a4..3f9c22e9e 100644 --- a/app/views/issues/_simple_issue_item.json.jbuilder +++ b/app/views/issues/_simple_issue_item.json.jbuilder @@ -1,4 +1,7 @@ json.name issue.try(:subject) +json.issue_type issue.try(:issue_type) +json.status_id issue.try(:status_id) +json.priority_id issue.try(:priority_id) json.created_at format_time(issue.try(:created_on)) json.updated_at format_time(issue.try(:updated_on)) json.assign_user_name issue&.get_assign_user.try(:show_real_name) diff --git a/app/views/project_trends/_detail.json.jbuilder b/app/views/project_trends/_detail.json.jbuilder new file mode 100644 index 000000000..7ffa9f152 --- /dev/null +++ b/app/views/project_trends/_detail.json.jbuilder @@ -0,0 +1,17 @@ +json.id trend.id +json.trend_type trend.trend_type +json.action_type l("trend.#{trend.action_type}") + l("trend.#{trend.trend_type}") +json.trend_id trend.trend_id +json.user_name trend.user.try(:show_real_name) +json.user_login trend.user.login +json.user_avatar url_to_avatar(trend.user) +json.action_time time_from_now(trend.created_at) + +if trend.trend_type == "Issue" + json.partial! "issues/simple_issue_item", locals: {issue: trend.trend} +elsif trend.trend_type == "VersionRelease" + json.partial! "version_releases/simple_version_release", locals: {version: trend.trend} +else + json.name trend.trend.title + json.created_at format_time(trend.trend.created_at) +end diff --git a/app/views/project_trends/index.json.jbuilder b/app/views/project_trends/index.json.jbuilder index 159a3bdb8..6dca7bdb5 100644 --- a/app/views/project_trends/index.json.jbuilder +++ b/app/views/project_trends/index.json.jbuilder @@ -9,25 +9,9 @@ json.limit @limit json.project_trends_size @project_trends_size json.project_trends do json.array! @project_trends.to_a.each do |trend| - json.id trend.id - json.trend_type trend.trend_type - json.action_type l("trend.#{trend.action_type}") + l("trend.#{trend.trend_type}") - json.trend_id trend.trend_id - json.user_name trend.user.try(:show_real_name) - json.user_login trend.user.login - json.user_avatar url_to_avatar(trend.user) - - if trend.trend_type == "Issue" - json.partial! "issues/simple_issue_item", locals: {issue: trend.trend} - elsif trend.trend_type == "VersionRelease" - json.partial! "version_releases/simple_version_release", locals: {version: trend.trend} - else - json.name trend.trend.title - json.created_at format_time(trend.trend.created_at) - end - + #后续需要天际pullrequest 和 版本的内容 - + json.partial! "detail", trend: trend end end diff --git a/app/views/users/project_trends/index.json.jbuilder b/app/views/users/project_trends/index.json.jbuilder new file mode 100644 index 000000000..d1aab1390 --- /dev/null +++ b/app/views/users/project_trends/index.json.jbuilder @@ -0,0 +1,4 @@ +json.total_count @project_trends.total_count +json.project_trends @project_trends.each do |trend| + json.partial! "project_trends/detail", trend: trend +end \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index d61acaf8e..2363b89df 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -271,6 +271,7 @@ Rails.application.routes.draw do post :pin end end + resources :project_trends, only: [:index] resources :organizations, only: [:index] # resources :projects, only: [:index] # resources :subjects, only: [:index] From 2410f5bbc095511c464673409dc643f0769efbf9 Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Fri, 28 May 2021 15:36:05 +0800 Subject: [PATCH 23/51] add: user statistics --- .../users/statistics_controller.rb | 190 +++++++++++++++++- app/models/concerns/project_operable.rb | 1 + app/models/project.rb | 1 - app/models/user.rb | 4 +- .../projects/_project_detail.json.jbuilder | 1 + app/views/users/headmaps/index.json.jbuilder | 2 +- .../users/statistics/develop.json.jbuilder | 19 ++ app/views/users/statistics/role.json.jbuilder | 19 ++ config/routes.rb | 8 + 9 files changed, 241 insertions(+), 4 deletions(-) create mode 100644 app/views/users/statistics/develop.json.jbuilder create mode 100644 app/views/users/statistics/role.json.jbuilder diff --git a/app/controllers/users/statistics_controller.rb b/app/controllers/users/statistics_controller.rb index 82a3ef012..7ab9a4bf4 100644 --- a/app/controllers/users/statistics_controller.rb +++ b/app/controllers/users/statistics_controller.rb @@ -1,2 +1,190 @@ -class Users::StatisticController < Users::BaseController +class Users::StatisticsController < Users::BaseController + before_action :preload_develop_data, only: [:develop] + + # 近期活动统计 + def activity + date_range = (1.week.ago.to_date..Date.today).to_a + commit_request = Gitea::User::HeadmapService.call(observed_user.login, 1.week.ago.to_date.to_time.to_i, Date.today.to_time.to_i) + commit_data = commit_request[2] + @date_data = [] + @issue_data = [] + @pull_request_data = [] + @commit_data = [] + date_range.each do |date| + @date_data << date.strftime("%Y.%m.%d") + @issue_data << observed_user.issues.where("DATE(created_on) = ?", date).size + @pull_request_data << observed_user.pull_requests.where("DATE(created_at) = ?", date).size + date_commit_data = commit_data.select{|item| item["timestamp"] == date.to_time.to_i} + @commit_data << (date_commit_data.blank? ? 0 : date_commit_data[0]["contributions"].to_i) + end + render :json => {dates: @date_data, issues_count: @issue_data, pull_requests_count: @pull_request_data, commtis_count: @commit_data} + end + + # 开发能力 + def develop + if params[:start_time].present? && params[:end_time].present? + # 影响力 + @influence = (60.0 + @follow_count / (@follow_count + 10.0) * 40.0).to_i + @platform_influence = (60.0 + @platform_follow_count / (@platform_follow_count + 10.0) * 40.0).to_i + # 贡献度 + @contribution = (60.0 + @pullrequest_count / (@pullrequest_count + 10.0) * 40.0).to_i + @platform_contribution = (60.0 + @platform_pullrequest_count / (@platform_pullrequest_count + 10.0) * 40.0).to_i + # 活跃度 + @activity = (60.0 + @issues_count / (@issues_count + 10.0) * 40.0).to_i + @platform_activity = (60.0 + @platform_issues_count / (@platform_issues_count + 10.0) * 40.0).to_i + # 项目经验 + @experience = 10 * @project_count + 5 * @fork_count + @project_watchers_count + @project_praises_count + @experience = (60.0 + @experience / (@experience + 100.0) * 40.0).to_i + @platform_experience = 10 * @platform_project_count + 5 * @platform_fork_count + @platform_project_watchers_count + @platform_project_praises_count + @platform_experience = (60.0 + @platform_experience / (@platform_experience + 100.0) * 40.0).to_i + # 语言能力 + @language = (60.0 + @project_languages_count.length / (@project_languages_count.length + 5.0) * 40.0).to_i + @platform_language = (60.0 + @platform_project_languages_count.length / (@platform_project_languages_count.length + 5.0) * 40.0).to_i + # 语言百分比 + @languages_percent = Hash.new + for key in @project_languages_count.keys do + @languages_percent[key] = (@project_languages_count[key].to_f / @project_languages_count.values.sum).round(2) + end + @platform_languages_percent = Hash.new + for key in @platform_project_languages_count.keys do + @platform_languages_percent[key] = (@platform_project_languages_count[key].to_f / @platform_project_languages_count.values.sum).round(2) + end + # 各门语言分数 + @each_language_score = Hash.new + for key in @project_languages_count.keys do + @each_language_score[key] = (60.0 + @project_languages_count[key] / (@project_languages_count[key] + 5.0) * 40.0).to_i + end + @platform_each_language_score = Hash.new + for key in @platform_project_languages_count.keys do + @platform_each_language_score[key] = (60.0 + @platform_project_languages_count[key] / (@platform_project_languages_count[key] + 5.0) * 40.0).to_i + end + else + # 影响力 + @influence = (60.0 + @follow_count / (@follow_count + 20.0) * 40.0).to_i + @platform_influence = (60.0 + @platform_follow_count / (@platform_follow_count + 20.0) * 40.0).to_i + + # 贡献度 + @contribution = (60.0 + @pullrequest_count / (@pullrequest_count + 20.0) * 40.0).to_i + @platform_contribution = (60.0 + @platform_pullrequest_count / (@platform_pullrequest_count + 20.0) * 40.0).to_i + + # 活跃度 + @activity = (60.0 + @issues_count / (@issues_count + 80.0) * 40.0).to_i + @platform_activity = (60.0 + @platform_issues_count / (@platform_issues_count + 80.0) * 40.0).to_i + + # 项目经验 + @experience = 10 * @project_count + 5 * @fork_count + @project_watchers_count + @project_praises_count + @experience = (60.0 + @experience / (@experience + 100.0) * 40.0).to_i + @platform_experience = 10 * @platform_project_count + 5 * @platform_fork_count + @platform_project_watchers_count + @platform_project_praises_count + @platform_experience = (60.0 + @platform_experience / (@platform_experience + 100.0) * 40.0).to_i + # 语言能力 + @language = (60.0 + @project_languages_count.length / (@project_languages_count.length + 5.0) * 40.0).to_i + @platform_language = (60.0 + @platform_project_languages_count.length / (@platform_project_languages_count.length + 5.0) * 40.0).to_i + + # 语言百分比 + @languages_percent = Hash.new + for key in @project_languages_count.keys do + @languages_percent[key] = (@project_languages_count[key].to_f / @project_languages_count.values.sum).round(2) + end + @platform_languages_percent = Hash.new + for key in @platform_project_languages_count.keys do + @platform_languages_percent[key] = (@platform_project_languages_count[key].to_f / @platform_project_languages_count.values.sum).round(2) + end + # 各门语言分数 + @each_language_score = Hash.new + for key in @project_languages_count.keys do + @each_language_score[key] = (60.0 + @project_languages_count[key] / (@project_languages_count[key] + 5.0) * 40.0).to_i + end + @platform_each_language_score = Hash.new + for key in @platform_project_languages_count.keys do + @platform_each_language_score[key] = (60.0 + @platform_project_languages_count[key] / (@platform_project_languages_count[key] + 5.0) * 40.0).to_i + end + end + + end + + # 角色定位 + def role + full_member_projects = observed_user.full_member_projects + owner_projects = filter_member_projects_by_role("Owner") + manager_projects = filter_member_projects_by_role("Manager").where.not(id: owner_projects.ids) + developer_projects = filter_member_projects_by_role("Developer").where.not(id: owner_projects.ids + manager_projects.ids) + reporter_projects = filter_member_projects_by_role("Reporter").where.not(id: owner_projects.ids + manager_projects.ids + developer_projects.ids) + + @full_member_projects_count = full_member_projects.size + @owner_projects_count = owner_projects.size + @manager_projects_count = manager_projects.size + @developer_projects_count = developer_projects.size + @reporter_projects_count = reporter_projects.size + + end + + # 专业定位 + def major + # 参与项目 + join_normal_projects_sql = Project.members_projects(observed_user.id).to_sql + join_org_projects_sql = Project.joins(team_projects: [team: :team_users]).where(team_users: {user_id: observed_user.id}).to_sql + # 关注项目 + star_projects_sql = Project.joins(:watchers).where(watchers: {watchable_type: "Project", user_id: observed_user.id}).to_sql + # fork项目 + fork_projects_sql = Project.where(id: observed_user.fork_users.select(:id, :fork_project_id).pluck(:fork_project_id)).to_sql + major_projects = Project.from("( #{ join_normal_projects_sql} UNION #{ join_org_projects_sql } UNION #{ star_projects_sql } UNION #{fork_projects_sql}) AS projects").distinct + categories = ProjectCategory.joins(:projects).merge(Project.where(id: time_filter(major_projects, 'created_on'))).distinct.pluck(:name) + render :json => {categories: categories} + end + + private + def time_filter(collection, time_field) + if params[:start_time].present? && params[:end_time].present? + return collection.where("#{time_field} > ? AND #{time_field} < ?", Time.at(params[:start_time].to_i).beginning_of_day, Time.at(params[:end_time].to_i).end_of_day) + else + return collection + end + rescue + return collection + end + + def filter_member_projects_by_role(role) + case role + when 'Owner' + normal_projects_sql = Project.joins(members: :roles).where(user_id: observed_user.id).where(members: {user_id: observed_user.id}, roles: {name: 'Manager'}).to_sql + org_projects_sql = Project.joins(:owner, teams: :team_users).where(users: {type: 'Organization'}, teams: {authorize: "owner"}, team_users: {user_id: observed_user.id}).to_sql + when "Manager" + normal_projects_sql = Project.joins(members: :roles).where.not(user_id: observed_user.id).where(members: {user_id: observed_user.id}, roles: {name: 'Manager'}).to_sql + org_projects_sql = Project.joins(:owner, teams: :team_users).where(users: {type: 'Organization'}, teams: {authorize: "admin"}, team_users: {user_id: observed_user.id}).to_sql + when "Developer" + normal_projects_sql = Project.joins(members: :roles).where.not(user_id: observed_user.id).where(members: {user_id: observed_user.id}, roles: {name: 'Developer'}).to_sql + org_projects_sql = Project.joins(:owner, teams: :team_users).where(users: {type: 'Organization'}, teams: {authorize: "write"}, team_users: {user_id: observed_user.id}).to_sql + when "Reporter" + normal_projects_sql = Project.joins(members: :roles).where.not(user_id: observed_user.id).where(members: {user_id: observed_user.id}, roles: {name: 'Reporter'}).to_sql + org_projects_sql = Project.joins(:owner, teams: :team_users).where(users: {type: 'Organization'}, teams: {authorize: "read"}, team_users: {user_id: observed_user.id}).to_sql + end + return time_filter(Project.from("( #{normal_projects_sql} UNION #{org_projects_sql} ) AS projects").distinct, 'created_on') + end + + def preload_develop_data + # 用户被follow数量 + @follow_count = time_filter(Watcher.where(watchable: observed_user), 'created_at').count + @platform_follow_count = time_filter(Watcher.where(watchable_type: 'User'), 'created_at').count + # 用户pr数量 + @pullrequest_count = time_filter(PullRequest.where(user_id: observed_user.id), 'created_at').count + @platform_pullrequest_count = time_filter(PullRequest, 'created_at').count + # 用户issue数量 + @issues_count = time_filter(Issue.where(author_id: observed_user.id), 'created_on').count + @platform_issues_count = time_filter(Issue, 'created_on').count + # 用户总项目数 @fork_count + @project_watchers_count + @project_praises_count + @project_count = filter_member_projects_by_role("Owner").count + @platform_project_count = time_filter(Project, 'created_on').count + # 用户项目被fork数量 + @fork_count = filter_member_projects_by_role("Owner").sum("forked_count") + @platform_fork_count = time_filter(Project, 'created_on').sum("forked_count") + # 用户项目关注数 + @project_watchers_count = filter_member_projects_by_role("Owner").sum("watchers_count") + @platform_project_watchers_count = time_filter(Project, 'created_on').sum("watchers_count") + # 用户项目点赞数 + @project_praises_count = filter_member_projects_by_role("Owner").sum("praises_count") + @platform_project_praises_count = time_filter(Project, 'created_on').sum("praises_count") + # 用户不同语言项目数量 + @project_languages_count = filter_member_projects_by_role("Owner").joins(:project_language).group("project_languages.name").count + @platform_project_languages_count = time_filter(Project, 'created_on').joins(:project_language).group("project_languages.name").count + end end \ No newline at end of file diff --git a/app/models/concerns/project_operable.rb b/app/models/concerns/project_operable.rb index b8adf5c8a..e016ca1dc 100644 --- a/app/models/concerns/project_operable.rb +++ b/app/models/concerns/project_operable.rb @@ -9,6 +9,7 @@ module ProjectOperable has_many :reporters, -> { joins(:roles).where(roles: { name: 'Reporter' }) }, class_name: 'Member' has_many :writable_members, -> { joins(:roles).where.not(roles: {name: 'Reporter'}) }, class_name: 'Member' has_many :team_projects, dependent: :destroy + has_many :teams, through: :team_projects, source: :team end def set_owner_permission(creator) diff --git a/app/models/project.rb b/app/models/project.rb index 9299abcdb..8141a56bf 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -111,7 +111,6 @@ class Project < ApplicationRecord has_many :praise_treads, as: :praise_tread_object, dependent: :destroy has_and_belongs_to_many :trackers, :order => "#{Tracker.table_name}.position" has_one :project_detail, dependent: :destroy - has_many :team_projects, dependent: :destroy has_many :project_units, dependent: :destroy has_one :applied_transfer_project,-> { order created_at: :desc }, dependent: :destroy has_many :pinned_projects, dependent: :destroy diff --git a/app/models/user.rb b/app/models/user.rb index bac795dd5..56043f5f6 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -167,6 +167,8 @@ class User < Owner has_many :pinned_projects, dependent: :destroy has_many :is_pinned_projects, through: :pinned_projects, source: :project accepts_nested_attributes_for :is_pinned_projects + has_many :issues, dependent: :destroy, foreign_key: :author_id + has_many :pull_requests, dependent: :destroy # Groups and active users scope :active, lambda { where(status: STATUS_ACTIVE) } @@ -201,7 +203,7 @@ class User < Owner # 用户参与的所有项目 def full_member_projects normal_projects = Project.members_projects(self.id).to_sql - org_projects = Project.joins(team_projects: [team: :team_users]).where(team_users: {user_id: self.id}).to_sql + org_projects = Project.joins(teams: :team_users).where(team_users: {user_id: self.id}).to_sql return Project.from("( #{ normal_projects} UNION #{ org_projects } ) AS projects").distinct end diff --git a/app/views/projects/_project_detail.json.jbuilder b/app/views/projects/_project_detail.json.jbuilder index 2e256fcb4..da5d67473 100644 --- a/app/views/projects/_project_detail.json.jbuilder +++ b/app/views/projects/_project_detail.json.jbuilder @@ -17,6 +17,7 @@ json.time_ago time_from_now(project.updated_on) json.forked_from_project_id project.forked_from_project_id json.open_devops project.open_devops? json.platform project.platform +json.is_pinned @project.has_pinned_users.include?(current_user) json.author do if project.educoder? project_educoder = project.project_educoder diff --git a/app/views/users/headmaps/index.json.jbuilder b/app/views/users/headmaps/index.json.jbuilder index 7011b2559..0e6a540b5 100644 --- a/app/views/users/headmaps/index.json.jbuilder +++ b/app/views/users/headmaps/index.json.jbuilder @@ -1,5 +1,5 @@ json.total_contributions @headmaps.collect{|map| map["contributions"]}.reduce(0, :+) json.headmaps @headmaps.each do |map| - json.date map["timestamp"] + json.date Time.at(map["timestamp"].to_i).strftime("%Y-%m-%d") json.contributions map["contributions"] end diff --git a/app/views/users/statistics/develop.json.jbuilder b/app/views/users/statistics/develop.json.jbuilder new file mode 100644 index 000000000..9d530fbbe --- /dev/null +++ b/app/views/users/statistics/develop.json.jbuilder @@ -0,0 +1,19 @@ +json.platform do + json.influence @platform_influence + json.contribution @platform_contribution + json.activity @platform_activity + json.experience @platform_experience + json.language @platform_language + json.languages_percent @platform_languages_percent + json.each_language_score @platform_each_language_score +end + +json.user do + json.influence @influence + json.contribution @contribution + json.activity @activity + json.experience @experience + json.language @language + json.languages_percent @languages_percent + json.each_language_score @each_language_score +end \ No newline at end of file diff --git a/app/views/users/statistics/role.json.jbuilder b/app/views/users/statistics/role.json.jbuilder new file mode 100644 index 000000000..5ca290586 --- /dev/null +++ b/app/views/users/statistics/role.json.jbuilder @@ -0,0 +1,19 @@ +json.total_projects_count @full_member_projects_count +json.role do + json.owner do + json.count @owner_projects_count + json.percent (@owner_projects_count.to_f/@full_member_projects_count).round(2) + end + json.manager do + json.count @manager_projects_count + json.percent (@manager_projects_count.to_f/@full_member_projects_count).round(2) + end + json.developer do + json.count @developer_projects_count + json.percent (@developer_projects_count.to_f/@full_member_projects_count).round(2) + end + json.reporter do + json.count @reporter_projects_count + json.percent (@reporter_projects_count.to_f/@full_member_projects_count).round(2) + end +end \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 2363b89df..cfadf4941 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -271,6 +271,14 @@ Rails.application.routes.draw do post :pin end end + resources :statistics, only: [:index] do + collection do + get :activity + get :develop + get :role + get :major + end + end resources :project_trends, only: [:index] resources :organizations, only: [:index] # resources :projects, only: [:index] From 1872ad00d56f3e3e8f32538b980b8f3fe136525e Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Fri, 28 May 2021 16:04:52 +0800 Subject: [PATCH 24/51] uupdate: api docs --- .../users/statistics_controller.rb | 2 +- app/docs/slate/source/includes/_users.md | 609 +++++++++++++- public/docs/api.html | 795 +++++++++++++++++- 3 files changed, 1346 insertions(+), 60 deletions(-) diff --git a/app/controllers/users/statistics_controller.rb b/app/controllers/users/statistics_controller.rb index 7ab9a4bf4..d508176e2 100644 --- a/app/controllers/users/statistics_controller.rb +++ b/app/controllers/users/statistics_controller.rb @@ -17,7 +17,7 @@ class Users::StatisticsController < Users::BaseController date_commit_data = commit_data.select{|item| item["timestamp"] == date.to_time.to_i} @commit_data << (date_commit_data.blank? ? 0 : date_commit_data[0]["contributions"].to_i) end - render :json => {dates: @date_data, issues_count: @issue_data, pull_requests_count: @pull_request_data, commtis_count: @commit_data} + render :json => {dates: @date_data, issues_count: @issue_data, pull_requests_count: @pull_request_data, commits_count: @commit_data} end # 开发能力 diff --git a/app/docs/slate/source/includes/_users.md b/app/docs/slate/source/includes/_users.md index b2c3ebccb..d7e8ed488 100644 --- a/app/docs/slate/source/includes/_users.md +++ b/app/docs/slate/source/includes/_users.md @@ -1,7 +1,7 @@ # Users @@ -176,6 +176,82 @@ await octokit.request('GET /api/users/:login/is_pinned_projects/pin.json') ``` +## 用户近期活动统计 +用户近期活动统计, 默认显示近一周的数据 + +> 示例: + +```shell +curl -X GET http://localhost:3000/api/users/yystopf/statistics/activity.json +``` + +```javascript +await octokit.request('GET /api/users/:login/statistics/activity.json') +``` + +### HTTP 请求 +`GET /api/users/:login/statistics/activity.json` + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|dates |array |时间 | +|issues_count |array |易修数量| +|pull_requests_count |array |合并请求数量| +|commtis_count |array |贡献数量| + + +> 返回的JSON示例: + +```json +{ + "dates": [ + "2021.05.21", + "2021.05.22", + "2021.05.23", + "2021.05.24", + "2021.05.25", + "2021.05.26", + "2021.05.27", + "2021.05.28" + ], + "issues_count": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "pull_requests_count": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "commits_count": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] +} +``` + + + ## 获取用户贡献度 获取用户贡献度 @@ -192,6 +268,12 @@ await octokit.request('GET /api/users/:login/headmaps.json') ### HTTP 请求 `GET api/users/:login/headmaps.json` + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|year |string |年份 | + ### 返回字段说明: 参数 | 类型 | 字段说明 --------- | ----------- | ----------- @@ -207,87 +289,87 @@ await octokit.request('GET /api/users/:login/headmaps.json') "total_contributions": 139, "headmaps": [ { - "date": 1612627200, + "date": "2021-02-07", "contributions": 1 }, { - "date": 1613836800, + "date": "2021-02-21", "contributions": 13 }, { - "date": 1614182400, + "date": "2021-02-25", "contributions": 5 }, { - "date": 1614528000, + "date": "2021-03-01", "contributions": 2 }, { - "date": 1614787200, + "date": "2021-03-04", "contributions": 1 }, { - "date": 1615737600, + "date": "2021-03-15", "contributions": 9 }, { - "date": 1616342400, + "date": "2021-03-22", "contributions": 14 }, { - "date": 1616515200, + "date": "2021-03-24", "contributions": 1 }, { - "date": 1617033600, + "date": "2021-03-30", "contributions": 11 }, { - "date": 1617638400, + "date": "2021-04-06", "contributions": 1 }, { - "date": 1618156800, + "date": "2021-04-12", "contributions": 1 }, { - "date": 1618243200, + "date": "2021-04-13", "contributions": 2 }, { - "date": 1618761600, + "date": "2021-04-19", "contributions": 3 }, { - "date": 1619107200, + "date": "2021-04-23", "contributions": 37 }, { - "date": 1619280000, + "date": "2021-04-25", "contributions": 2 }, { - "date": 1619366400, + "date": "2021-04-26", "contributions": 6 }, { - "date": 1619539200, + "date": "2021-04-28", "contributions": 1 }, { - "date": 1619625600, + "date": "2021-04-29", "contributions": 18 }, { - "date": 1619712000, + "date": "2021-04-30", "contributions": 9 }, { - "date": 1620057600, + "date": "2021-05-04", "contributions": 1 }, { - "date": 1620230400, + "date": "2021-05-06", "contributions": 1 } ] @@ -297,6 +379,489 @@ await octokit.request('GET /api/users/:login/headmaps.json') Success Data. +## 获取用户动态 +获取用户动态 + +> 示例: + +```shell +curl -X GET http://localhost:3000/api/users/yystopf/project_trends.json +``` + +```javascript +await octokit.request('GET /api/users/:login/project_trends.json') +``` + +### HTTP 请求 +`GET api/users/:login/project_trends.json` + + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|date |string |日期,格式: 2021-05-28 | + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|total_count |int |所选时间内的总动态数 | +|project_trends.trend_type |string|动态类型,Issue:易修,VersionRelease:版本发布,PullRequest:合并请求| +|project_trends.action_type |string|操作类型| +|project_trends.trend_id |integer|动态id| +|project_trends.user_name |string|用户名称| +|project_trends.user_login |string|用户用户名| +|project_trends.user_avatar |string|用户头像| +|project_trends.action_time |string|操作时间| +|project_trends.name |string|动态标题| + +> 返回的JSON示例: + +```json +{ + "total_count": 16, + "project_trends": [ + { + "id": 27, + "trend_type": "Issue", + "action_type": "创建了工单", + "trend_id": 18, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "21天前", + "name": "31213123123", + "issue_type": "1", + "status_id": 2, + "priority_id": 4, + "created_at": "2021-05-07 15:39", + "updated_at": "2021-05-27 15:42", + "assign_user_name": "yystopf", + "assign_user_login": "yystopf", + "issue_journal_size": 1, + "issue_journals": [] + }, + { + "id": 8, + "trend_type": "VersionRelease", + "action_type": "创建了版本发布", + "trend_id": 8, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "24天前", + "name": "heihei1", + "tag_name": "v1.0", + "target_commitish": "master", + "tarball_url": "http://localhost:10080/forgeceshiorg1/ceshi1/archive/v1.0.tar.gz", + "zipball_url": "http://localhost:10080/forgeceshiorg1/ceshi1/archive/v1.0.zip", + "url": "http://localhost:10080/api/v1/repos/forgeceshiorg1/ceshi1/releases/84", + "version_gid": "84", + "created_at": "2021-05-04 12:04" + }, + { + "id": 25, + "trend_type": "PullRequest", + "action_type": "关闭了合并请求", + "trend_id": 14, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "28天前", + "name": "13", + "created_at": "2021-04-30 15:39" + }, + { + "id": 24, + "trend_type": "PullRequest", + "action_type": "创建了合并请求", + "trend_id": 13, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "28天前", + "name": "211212", + "created_at": "2021-04-30 15:37" + }, + { + "id": 23, + "trend_type": "PullRequest", + "action_type": "创建了合并请求", + "trend_id": 12, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "28天前", + "name": "奇偶哦iu", + "created_at": "2021-04-30 10:19" + }, + { + "id": 22, + "trend_type": "PullRequest", + "action_type": "创建了合并请求", + "trend_id": 11, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "28天前", + "name": "2112123", + "created_at": "2021-04-29 18:46" + }, + { + "id": 21, + "trend_type": "PullRequest", + "action_type": "关闭了合并请求", + "trend_id": 10, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "28天前", + "name": "23123", + "created_at": "2021-04-29 18:45" + }, + { + "id": 20, + "trend_type": "PullRequest", + "action_type": "创建了合并请求", + "trend_id": 9, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "28天前", + "name": "33", + "created_at": "2021-04-29 18:37" + }, + { + "id": 19, + "trend_type": "PullRequest", + "action_type": "关闭了合并请求", + "trend_id": 8, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "28天前", + "name": "gggg", + "created_at": "2021-04-29 17:51" + }, + { + "id": 16, + "trend_type": "Issue", + "action_type": "创建了工单", + "trend_id": 8, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "1个月前", + "name": "hjhkj", + "issue_type": "1", + "status_id": 1, + "priority_id": 2, + "created_at": "2021-04-19 10:52", + "updated_at": "2021-04-19 10:52", + "assign_user_name": null, + "assign_user_login": null, + "issue_journal_size": 0, + "issue_journals": [] + }, + { + "id": 7, + "trend_type": "VersionRelease", + "action_type": "创建了版本发布", + "trend_id": 7, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "1个月前", + "name": "v3.0.1", + "tag_name": "v3.0.1", + "target_commitish": "master", + "tarball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v3.0.1.tar.gz", + "zipball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v3.0.1.zip", + "url": "http://localhost:10080/api/v1/repos/yystopf/ceshirepo1/releases/78", + "version_gid": "78", + "created_at": "2021-03-30 15:51" + }, + { + "id": 6, + "trend_type": "VersionRelease", + "action_type": "创建了版本发布", + "trend_id": 6, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "1个月前", + "name": "v3.0.0", + "tag_name": "v3.0.0", + "target_commitish": "master", + "tarball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v3.0.0.tar.gz", + "zipball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v3.0.0.zip", + "url": "http://localhost:10080/api/v1/repos/yystopf/ceshirepo1/releases/77", + "version_gid": "77", + "created_at": "2021-03-30 15:33" + }, + { + "id": 5, + "trend_type": "VersionRelease", + "action_type": "创建了版本发布", + "trend_id": 5, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "1个月前", + "name": "v1.0.0", + "tag_name": "v1.0.0", + "target_commitish": "master", + "tarball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v1.0.0.tar.gz", + "zipball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v1.0.0.zip", + "url": "http://localhost:10080/api/v1/repos/yystopf/ceshirepo1/releases/76", + "version_gid": "76", + "created_at": "2021-03-30 15:27" + }, + { + "id": 2, + "trend_type": "VersionRelease", + "action_type": "创建了版本发布", + "trend_id": 2, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "2个月前", + "name": "vvvv", + "tag_name": "v1.1", + "target_commitish": "dev", + "tarball_url": "http://localhost:10080/yystopf/virus_blog/archive/v1.1.tar.gz", + "zipball_url": "http://localhost:10080/yystopf/virus_blog/archive/v1.1.zip", + "url": "http://localhost:10080/api/v1/repos/yystopf/virus_blog/releases/6", + "version_gid": "6", + "created_at": "2021-03-15 14:18" + }, + { + "id": 2, + "trend_type": "PullRequest", + "action_type": "创建了合并请求", + "trend_id": 2, + "user_name": "yystopf", + "user_login": "yystopf", + "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png", + "action_time": "3个月前", + "name": "444", + "created_at": "2021-02-25 17:31" + } + ] +} +``` + + +## 用户开发能力 +用户开发能力, 默认为所有时间下的开发能力 + +> 示例: + +```shell +curl -X GET http://localhost:3000/api/users/yystopf/statistics/develop.json +``` + +```javascript +await octokit.request('GET /api/users/:login/statistics/develop.json') +``` + +### HTTP 请求 +`GET /api/users/:login/statistics/develop.json` + + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|start_time |integer |时间戳,开始时间,格式:1621526400| +|end_time |integer |时间戳,结束时间,格式:1622131200| + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|influence |int |影响力 | +|contribution |int |贡献度| +|activity |int |活跃度| +|experience |int |项目经验| +|language |int |语言能力| +|languages_percent |float |语言百分比| +|each_language_score |int |各门语言分数| + + +> 返回的JSON示例: + +```json +{ + "platform": { + "influence": 61, + "contribution": 75, + "activity": 66, + "experience": 95, + "language": 87, + "languages_percent": { + "CSS": 0.03, + "C#": 0.13, + "Ruby": 0.04, + "Go": 0.05, + "C": 0.19, + "Java": 0.34, + "Python": 0.09, + "C+": 0.01, + "C++": 0.11, + "Scala": 0.01, + "HTML": 0.01 + }, + "each_language_score": { + "CSS": 71, + "C#": 86, + "Ruby": 75, + "Go": 77, + "C": 90, + "Java": 93, + "Python": 83, + "C+": 66, + "C++": 85, + "Scala": 66, + "HTML": 66 + } + }, + "user": { + "influence": 60, + "contribution": 72, + "activity": 65, + "experience": 88, + "language": 84, + "languages_percent": { + "C": 0.25, + "C#": 0.33, + "C++": 0.13, + "CSS": 0.08, + "Go": 0.04, + "HTML": 0.04, + "Java": 0.04, + "Ruby": 0.08 + }, + "each_language_score": { + "C": 81, + "C#": 84, + "C++": 75, + "CSS": 71, + "Go": 66, + "HTML": 66, + "Java": 66, + "Ruby": 71 + } + } +} +``` + + +## 用户角色定位 +用户角色定位,默认显示所有时间下的角色定位数据 + +> 示例: + +```shell +curl -X GET http://localhost:3000/api/users/yystopf/statistics/role.json +``` + +```javascript +await octokit.request('GET /api/users/:login/statistics/role.json') +``` + +### HTTP 请求 +`GET /api/users/:login/statistics/role.json` + + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|start_time |integer |时间戳,开始时间,格式:1621526400| +|end_time |integer |时间戳,结束时间,格式:1622131200| + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|total_projects_count |int |用户所有的项目数量 | +|role.object.count |int |用户该语言下的项目数量| +|role.object.percent |float |用户该语言下的项目占比| + +> 返回的JSON示例: + +```json +{ + "total_projects_count": 27, + "role": { + "owner": { + "count": 24, + "percent": 0.89 + }, + "manager": { + "count": 1, + "percent": 0.04 + }, + "developer": { + "count": 2, + "percent": 0.07 + }, + "reporter": { + "count": 0, + "percent": 0.0 + } + } +} +``` + + +## 用户专业定位 +用户专业定位,默认显示所有时间下的专业定位数据 + +> 示例: + +```shell +curl -X GET http://localhost:3000/api/users/yystopf/statistics/major.json +``` + +```javascript +await octokit.request('GET /api/users/:login/statistics/major.json') +``` + +### HTTP 请求 +`GET /api/users/:login/statistics/major.json` + + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|start_time |integer |时间戳,开始时间,格式:1621526400| +|end_time |integer |时间戳,结束时间,格式:1622131200| + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|categories |int |用户项目分类 | + +> 返回的JSON示例: + +```json +{ + "categories": [ + "大数据", + "机器学习", + "深度学习", + "人工智能", + "智慧医疗", + "云计算" + ] +} +``` + ## 待办事项-用户通知信息 待办事项-用户通知信息 diff --git a/public/docs/api.html b/public/docs/api.html index 9bd9bb6ea..616803e4e 100644 --- a/public/docs/api.html +++ b/public/docs/api.html @@ -337,9 +337,24 @@
  • 用户添加星标项目
  • +
  • + 用户近期活动统计 +
  • 获取用户贡献度
  • +
  • + 获取用户动态 +
  • +
  • + 用户开发能力 +
  • +
  • + 用户角色定位 +
  • +
  • + 用户专业定位 +
  • 待办事项-用户通知信息
  • @@ -596,7 +611,7 @@ Success — a happy kitten is an authenticated kitten!

    Users

    获取当前登陆用户信息

    @@ -886,7 +901,96 @@ Success — a happy kitten is an authenticated kitten! "status": 0, "message": "success" } -

    获取用户贡献度

    +

    用户近期活动统计

    +

    用户近期活动统计, 默认显示近一周的数据

    + +
    +

    示例:

    +
    +
    curl -X GET http://localhost:3000/api/users/yystopf/statistics/activity.json
    +
    await octokit.request('GET /api/users/:login/statistics/activity.json')
    +

    HTTP 请求

    +

    GET /api/users/:login/statistics/activity.json

    +

    返回字段说明:

    +
    参数
    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    参数类型字段说明
    datesarray时间
    issues_countarray易修数量
    pull_requests_countarray合并请求数量
    commtis_countarray贡献数量
    + +
    +

    返回的JSON示例:

    +
    +
    {
    +    "dates": [
    +        "2021.05.21",
    +        "2021.05.22",
    +        "2021.05.23",
    +        "2021.05.24",
    +        "2021.05.25",
    +        "2021.05.26",
    +        "2021.05.27",
    +        "2021.05.28"
    +    ],
    +    "issues_count": [
    +        0,
    +        0,
    +        0,
    +        0,
    +        0,
    +        0,
    +        0,
    +        0
    +    ],
    +    "pull_requests_count": [
    +        0,
    +        0,
    +        0,
    +        0,
    +        0,
    +        0,
    +        0,
    +        0
    +    ],
    +    "commits_count": [
    +        0,
    +        0,
    +        0,
    +        0,
    +        0,
    +        0,
    +        0,
    +        0
    +    ]
    +}
    +
    + +

    获取用户贡献度

    获取用户贡献度

    @@ -894,9 +998,23 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/headmaps.json
     
    await octokit.request('GET /api/users/:login/headmaps.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET api/users/:login/headmaps.json

    -

    返回字段说明:

    +

    请求字段说明:

    + + + + + + + + + + + + +
    参数类型字段说明
    yearstring年份
    +

    返回字段说明:

    @@ -928,87 +1046,87 @@ Success — a happy kitten is an authenticated kitten! "total_contributions": 139, "headmaps": [ { - "date": 1612627200, + "date": "2021-02-07", "contributions": 1 }, { - "date": 1613836800, + "date": "2021-02-21", "contributions": 13 }, { - "date": 1614182400, + "date": "2021-02-25", "contributions": 5 }, { - "date": 1614528000, + "date": "2021-03-01", "contributions": 2 }, { - "date": 1614787200, + "date": "2021-03-04", "contributions": 1 }, { - "date": 1615737600, + "date": "2021-03-15", "contributions": 9 }, { - "date": 1616342400, + "date": "2021-03-22", "contributions": 14 }, { - "date": 1616515200, + "date": "2021-03-24", "contributions": 1 }, { - "date": 1617033600, + "date": "2021-03-30", "contributions": 11 }, { - "date": 1617638400, + "date": "2021-04-06", "contributions": 1 }, { - "date": 1618156800, + "date": "2021-04-12", "contributions": 1 }, { - "date": 1618243200, + "date": "2021-04-13", "contributions": 2 }, { - "date": 1618761600, + "date": "2021-04-19", "contributions": 3 }, { - "date": 1619107200, + "date": "2021-04-23", "contributions": 37 }, { - "date": 1619280000, + "date": "2021-04-25", "contributions": 2 }, { - "date": 1619366400, + "date": "2021-04-26", "contributions": 6 }, { - "date": 1619539200, + "date": "2021-04-28", "contributions": 1 }, { - "date": 1619625600, + "date": "2021-04-29", "contributions": 18 }, { - "date": 1619712000, + "date": "2021-04-30", "contributions": 9 }, { - "date": 1620057600, + "date": "2021-05-04", "contributions": 1 }, { - "date": 1620230400, + "date": "2021-05-06", "contributions": 1 } ] @@ -1017,6 +1135,609 @@ Success — a happy kitten is an authenticated kitten! +

    获取用户动态

    +

    获取用户动态

    + +
    +

    示例:

    +
    +
    curl -X GET http://localhost:3000/api/users/yystopf/project_trends.json
    +
    await octokit.request('GET /api/users/:login/project_trends.json')
    +

    HTTP 请求

    +

    GET api/users/:login/project_trends.json

    +

    请求字段说明:

    +
    参数
    + + + + + + + + + + + +
    参数类型字段说明
    datestring日期,格式: 2021-05-28
    +

    返回字段说明:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    参数类型字段说明
    total_countint所选时间内的总动态数
    project_trends.trend_typestring动态类型,Issue:易修,VersionRelease:版本发布,PullRequest:合并请求
    project_trends.action_typestring操作类型
    project_trends.trend_idinteger动态id
    project_trends.user_namestring用户名称
    project_trends.user_loginstring用户用户名
    project_trends.user_avatarstring用户头像
    project_trends.action_timestring操作时间
    project_trends.namestring动态标题
    + +
    +

    返回的JSON示例:

    +
    +
    {
    +    "total_count": 16,
    +    "project_trends": [
    +        {
    +            "id": 27,
    +            "trend_type": "Issue",
    +            "action_type": "创建了工单",
    +            "trend_id": 18,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "21天前",
    +            "name": "31213123123",
    +            "issue_type": "1",
    +            "status_id": 2,
    +            "priority_id": 4,
    +            "created_at": "2021-05-07 15:39",
    +            "updated_at": "2021-05-27 15:42",
    +            "assign_user_name": "yystopf",
    +            "assign_user_login": "yystopf",
    +            "issue_journal_size": 1,
    +            "issue_journals": []
    +        },
    +        {
    +            "id": 8,
    +            "trend_type": "VersionRelease",
    +            "action_type": "创建了版本发布",
    +            "trend_id": 8,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "24天前",
    +            "name": "heihei1",
    +            "tag_name": "v1.0",
    +            "target_commitish": "master",
    +            "tarball_url": "http://localhost:10080/forgeceshiorg1/ceshi1/archive/v1.0.tar.gz",
    +            "zipball_url": "http://localhost:10080/forgeceshiorg1/ceshi1/archive/v1.0.zip",
    +            "url": "http://localhost:10080/api/v1/repos/forgeceshiorg1/ceshi1/releases/84",
    +            "version_gid": "84",
    +            "created_at": "2021-05-04 12:04"
    +        },
    +        {
    +            "id": 25,
    +            "trend_type": "PullRequest",
    +            "action_type": "关闭了合并请求",
    +            "trend_id": 14,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "28天前",
    +            "name": "13",
    +            "created_at": "2021-04-30 15:39"
    +        },
    +        {
    +            "id": 24,
    +            "trend_type": "PullRequest",
    +            "action_type": "创建了合并请求",
    +            "trend_id": 13,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "28天前",
    +            "name": "211212",
    +            "created_at": "2021-04-30 15:37"
    +        },
    +        {
    +            "id": 23,
    +            "trend_type": "PullRequest",
    +            "action_type": "创建了合并请求",
    +            "trend_id": 12,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "28天前",
    +            "name": "奇偶哦iu",
    +            "created_at": "2021-04-30 10:19"
    +        },
    +        {
    +            "id": 22,
    +            "trend_type": "PullRequest",
    +            "action_type": "创建了合并请求",
    +            "trend_id": 11,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "28天前",
    +            "name": "2112123",
    +            "created_at": "2021-04-29 18:46"
    +        },
    +        {
    +            "id": 21,
    +            "trend_type": "PullRequest",
    +            "action_type": "关闭了合并请求",
    +            "trend_id": 10,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "28天前",
    +            "name": "23123",
    +            "created_at": "2021-04-29 18:45"
    +        },
    +        {
    +            "id": 20,
    +            "trend_type": "PullRequest",
    +            "action_type": "创建了合并请求",
    +            "trend_id": 9,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "28天前",
    +            "name": "33",
    +            "created_at": "2021-04-29 18:37"
    +        },
    +        {
    +            "id": 19,
    +            "trend_type": "PullRequest",
    +            "action_type": "关闭了合并请求",
    +            "trend_id": 8,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "28天前",
    +            "name": "gggg",
    +            "created_at": "2021-04-29 17:51"
    +        },
    +        {
    +            "id": 16,
    +            "trend_type": "Issue",
    +            "action_type": "创建了工单",
    +            "trend_id": 8,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "1个月前",
    +            "name": "hjhkj",
    +            "issue_type": "1",
    +            "status_id": 1,
    +            "priority_id": 2,
    +            "created_at": "2021-04-19 10:52",
    +            "updated_at": "2021-04-19 10:52",
    +            "assign_user_name": null,
    +            "assign_user_login": null,
    +            "issue_journal_size": 0,
    +            "issue_journals": []
    +        },
    +        {
    +            "id": 7,
    +            "trend_type": "VersionRelease",
    +            "action_type": "创建了版本发布",
    +            "trend_id": 7,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "1个月前",
    +            "name": "v3.0.1",
    +            "tag_name": "v3.0.1",
    +            "target_commitish": "master",
    +            "tarball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v3.0.1.tar.gz",
    +            "zipball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v3.0.1.zip",
    +            "url": "http://localhost:10080/api/v1/repos/yystopf/ceshirepo1/releases/78",
    +            "version_gid": "78",
    +            "created_at": "2021-03-30 15:51"
    +        },
    +        {
    +            "id": 6,
    +            "trend_type": "VersionRelease",
    +            "action_type": "创建了版本发布",
    +            "trend_id": 6,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "1个月前",
    +            "name": "v3.0.0",
    +            "tag_name": "v3.0.0",
    +            "target_commitish": "master",
    +            "tarball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v3.0.0.tar.gz",
    +            "zipball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v3.0.0.zip",
    +            "url": "http://localhost:10080/api/v1/repos/yystopf/ceshirepo1/releases/77",
    +            "version_gid": "77",
    +            "created_at": "2021-03-30 15:33"
    +        },
    +        {
    +            "id": 5,
    +            "trend_type": "VersionRelease",
    +            "action_type": "创建了版本发布",
    +            "trend_id": 5,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "1个月前",
    +            "name": "v1.0.0",
    +            "tag_name": "v1.0.0",
    +            "target_commitish": "master",
    +            "tarball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v1.0.0.tar.gz",
    +            "zipball_url": "http://localhost:10080/yystopf/ceshirepo1/archive/v1.0.0.zip",
    +            "url": "http://localhost:10080/api/v1/repos/yystopf/ceshirepo1/releases/76",
    +            "version_gid": "76",
    +            "created_at": "2021-03-30 15:27"
    +        },
    +        {
    +            "id": 2,
    +            "trend_type": "VersionRelease",
    +            "action_type": "创建了版本发布",
    +            "trend_id": 2,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "2个月前",
    +            "name": "vvvv",
    +            "tag_name": "v1.1",
    +            "target_commitish": "dev",
    +            "tarball_url": "http://localhost:10080/yystopf/virus_blog/archive/v1.1.tar.gz",
    +            "zipball_url": "http://localhost:10080/yystopf/virus_blog/archive/v1.1.zip",
    +            "url": "http://localhost:10080/api/v1/repos/yystopf/virus_blog/releases/6",
    +            "version_gid": "6",
    +            "created_at": "2021-03-15 14:18"
    +        },
    +        {
    +            "id": 2,
    +            "trend_type": "PullRequest",
    +            "action_type": "创建了合并请求",
    +            "trend_id": 2,
    +            "user_name": "yystopf",
    +            "user_login": "yystopf",
    +            "user_avatar": "system/lets/letter_avatars/2/Y/241_125_89/120.png",
    +            "action_time": "3个月前",
    +            "name": "444",
    +            "created_at": "2021-02-25 17:31"
    +        }
    +    ]
    +}
    +
    + +

    用户开发能力

    +

    用户开发能力, 默认为所有时间下的开发能力

    + +
    +

    示例:

    +
    +
    curl -X GET http://localhost:3000/api/users/yystopf/statistics/develop.json
    +
    await octokit.request('GET /api/users/:login/statistics/develop.json')
    +

    HTTP 请求

    +

    GET /api/users/:login/statistics/develop.json

    +

    请求字段说明:

    + + + + + + + + + + + + + + + + + +
    参数类型字段说明
    start_timeinteger时间戳,开始时间,格式:1621526400
    end_timeinteger时间戳,结束时间,格式:1622131200
    +

    返回字段说明:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    参数类型字段说明
    influenceint影响力
    contributionint贡献度
    activityint活跃度
    experienceint项目经验
    languageint语言能力
    languages_percentfloat语言百分比
    each_language_scoreint各门语言分数
    + +
    +

    返回的JSON示例:

    +
    +
    {
    +    "platform": {
    +        "influence": 61,
    +        "contribution": 75,
    +        "activity": 66,
    +        "experience": 95,
    +        "language": 87,
    +        "languages_percent": {
    +            "CSS": 0.03,
    +            "C#": 0.13,
    +            "Ruby": 0.04,
    +            "Go": 0.05,
    +            "C": 0.19,
    +            "Java": 0.34,
    +            "Python": 0.09,
    +            "C+": 0.01,
    +            "C++": 0.11,
    +            "Scala": 0.01,
    +            "HTML": 0.01
    +        },
    +        "each_language_score": {
    +            "CSS": 71,
    +            "C#": 86,
    +            "Ruby": 75,
    +            "Go": 77,
    +            "C": 90,
    +            "Java": 93,
    +            "Python": 83,
    +            "C+": 66,
    +            "C++": 85,
    +            "Scala": 66,
    +            "HTML": 66
    +        }
    +    },
    +    "user": {
    +        "influence": 60,
    +        "contribution": 72,
    +        "activity": 65,
    +        "experience": 88,
    +        "language": 84,
    +        "languages_percent": {
    +            "C": 0.25,
    +            "C#": 0.33,
    +            "C++": 0.13,
    +            "CSS": 0.08,
    +            "Go": 0.04,
    +            "HTML": 0.04,
    +            "Java": 0.04,
    +            "Ruby": 0.08
    +        },
    +        "each_language_score": {
    +            "C": 81,
    +            "C#": 84,
    +            "C++": 75,
    +            "CSS": 71,
    +            "Go": 66,
    +            "HTML": 66,
    +            "Java": 66,
    +            "Ruby": 71
    +        }
    +    }
    +}
    +
    + +

    用户角色定位

    +

    用户角色定位,默认显示所有时间下的角色定位数据

    + +
    +

    示例:

    +
    +
    curl -X GET http://localhost:3000/api/users/yystopf/statistics/role.json
    +
    await octokit.request('GET /api/users/:login/statistics/role.json')
    +

    HTTP 请求

    +

    GET /api/users/:login/statistics/role.json

    +

    请求字段说明:

    + + + + + + + + + + + + + + + + + +
    参数类型字段说明
    start_timeinteger时间戳,开始时间,格式:1621526400
    end_timeinteger时间戳,结束时间,格式:1622131200
    +

    返回字段说明:

    + + + + + + + + + + + + + + + + + + + + + + +
    参数类型字段说明
    total_projects_countint用户所有的项目数量
    role.object.countint用户该语言下的项目数量
    role.object.percentfloat用户该语言下的项目占比
    + +
    +

    返回的JSON示例:

    +
    +
    {
    +    "total_projects_count": 27,
    +    "role": {
    +        "owner": {
    +            "count": 24,
    +            "percent": 0.89
    +        },
    +        "manager": {
    +            "count": 1,
    +            "percent": 0.04
    +        },
    +        "developer": {
    +            "count": 2,
    +            "percent": 0.07
    +        },
    +        "reporter": {
    +            "count": 0,
    +            "percent": 0.0
    +        }
    +    }
    +}
    +
    + +

    用户专业定位

    +

    用户专业定位,默认显示所有时间下的专业定位数据

    + +
    +

    示例:

    +
    +
    curl -X GET http://localhost:3000/api/users/yystopf/statistics/major.json
    +
    await octokit.request('GET /api/users/:login/statistics/major.json')
    +

    HTTP 请求

    +

    GET /api/users/:login/statistics/major.json

    +

    请求字段说明:

    + + + + + + + + + + + + + + + + + +
    参数类型字段说明
    start_timeinteger时间戳,开始时间,格式:1621526400
    end_timeinteger时间戳,结束时间,格式:1622131200
    +

    返回字段说明:

    + + + + + + + + + + + + +
    参数类型字段说明
    categoriesint用户项目分类
    + +
    +

    返回的JSON示例:

    +
    +
    {
    +    "categories": [
    +        "大数据",
    +        "机器学习",
    +        "深度学习",
    +        "人工智能",
    +        "智慧医疗",
    +        "云计算"
    +    ]
    +}
    +
    +

    待办事项-用户通知信息

    待办事项-用户通知信息

    @@ -1025,9 +1746,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/applied_messages.json
     
    await octokit.request('GET /api/users/:login/applied_messages.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_messages.json

    -

    请求字段说明:

    +

    请求字段说明:

    @@ -1041,7 +1762,7 @@ Success — a happy kitten is an authenticated kitten!
    参数用户标识
    -

    返回字段说明:

    +

    返回字段说明:

    @@ -1262,9 +1983,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/applied_transfer_projects.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1278,7 +1999,7 @@ Success — a happy kitten is an authenticated kitten!
    参数用户标识
    -

    返回字段说明:

    +

    返回字段说明:

    @@ -1454,9 +2175,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/accept.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/accept.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects/:id/accept.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1475,7 +2196,7 @@ Success — a happy kitten is an authenticated kitten!
    参数迁移id
    -

    返回字段说明:

    +

    返回字段说明:

    @@ -1645,9 +2366,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/refuse.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/refuse.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects/:id/refuse.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1666,7 +2387,7 @@ Success — a happy kitten is an authenticated kitten!
    参数迁移id
    -

    返回字段说明:

    +

    返回字段说明:

    From cdce7049ad07cb58820cbb925551398b7cc1c807 Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Fri, 28 May 2021 16:08:49 +0800 Subject: [PATCH 25/51] fix --- app/views/projects/_project_detail.json.jbuilder | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/_project_detail.json.jbuilder b/app/views/projects/_project_detail.json.jbuilder index da5d67473..c9e03fa22 100644 --- a/app/views/projects/_project_detail.json.jbuilder +++ b/app/views/projects/_project_detail.json.jbuilder @@ -17,7 +17,7 @@ json.time_ago time_from_now(project.updated_on) json.forked_from_project_id project.forked_from_project_id json.open_devops project.open_devops? json.platform project.platform -json.is_pinned @project.has_pinned_users.include?(current_user) +json.is_pinned project.has_pinned_users.include?(current_user) json.author do if project.educoder? project_educoder = project.project_educoder From 7fa1cdf73e9f76de973b2065d1b74c61f589cb21 Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Fri, 28 May 2021 16:53:37 +0800 Subject: [PATCH 26/51] add: user created time --- app/views/users/show.json.jbuilder | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/users/show.json.jbuilder b/app/views/users/show.json.jbuilder index e80ac7494..c529cf79f 100644 --- a/app/views/users/show.json.jbuilder +++ b/app/views/users/show.json.jbuilder @@ -17,4 +17,5 @@ json.user_composes_count @user_composes_count json.user_org_count @user_org_count json.common_projects_count @projects_common_count json.mirror_projects_count @projects_mirrior_count -json.sync_mirror_projects_count @projects_sync_mirrior_count \ No newline at end of file +json.sync_mirror_projects_count @projects_sync_mirrior_count +json.created_time format_time(@user.created_on) \ No newline at end of file From dc4c99c30596e5265d5884a0abfcbd750e5058df Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Fri, 28 May 2021 18:00:53 +0800 Subject: [PATCH 27/51] fix: psimple issue field --- app/views/issues/_simple_issue_item.json.jbuilder | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/views/issues/_simple_issue_item.json.jbuilder b/app/views/issues/_simple_issue_item.json.jbuilder index 3f9c22e9e..d21c9fcae 100644 --- a/app/views/issues/_simple_issue_item.json.jbuilder +++ b/app/views/issues/_simple_issue_item.json.jbuilder @@ -1,7 +1,10 @@ json.name issue.try(:subject) -json.issue_type issue.try(:issue_type) +json.issue_type issue.issue_type == "1" ? "普通" : "悬赏" json.status_id issue.try(:status_id) +json.issue_status issue.issue_status.try(:name) +json.priority issue.priority.try(:name) json.priority_id issue.try(:priority_id) +json.version issue.version.try(:name) json.created_at format_time(issue.try(:created_on)) json.updated_at format_time(issue.try(:updated_on)) json.assign_user_name issue&.get_assign_user.try(:show_real_name) From 86f0f2051d357a466fcf485d0ceac8e20da82081 Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Mon, 31 May 2021 18:39:49 +0800 Subject: [PATCH 28/51] add: update user_info --- app/controllers/users_controller.rb | 15 ++- app/docs/slate/source/includes/_users.md | 53 +++++++- app/models/user.rb | 2 +- app/models/user_extension.rb | 6 +- app/views/users/show.json.jbuilder | 7 +- ...531100250_add_fields_to_user_extensions.rb | 8 ++ public/docs/api.html | 124 ++++++++++++++---- 7 files changed, 180 insertions(+), 35 deletions(-) create mode 100644 db/migrate/20210531100250_add_fields_to_user_extensions.rb diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 3c62b1145..4cbb2cbdf 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -72,9 +72,13 @@ class UsersController < ApplicationController end def update - @user = User.find params[:id] - @user.update!(user_params) - render_ok + return render_not_found unless @user = User.find_by_id(params[:id]) || User.find_by(login: params[:id]) + @user.attributes = user_params + if @user.save + render_ok + else + render_error(@user.errors.full_messages.join(", ")) + end end def me @@ -274,11 +278,12 @@ class UsersController < ApplicationController end def user_params - params.require(:user).permit(:nickname, :lastname, :show_realname,:login,:mail, + params.require(:user).permit(:nickname, user_extension_attributes: [ :gender, :location, :location_city, :occupation, :technical_title, - :school_id, :department_id,:identity, :student_id, :description] + :school_id, :department_id, :province, :city, + :custom_department, :identity, :student_id, :description] ) end diff --git a/app/docs/slate/source/includes/_users.md b/app/docs/slate/source/includes/_users.md index d7e8ed488..573e171eb 100644 --- a/app/docs/slate/source/includes/_users.md +++ b/app/docs/slate/source/includes/_users.md @@ -1,7 +1,7 @@ # Users @@ -47,6 +47,57 @@ await octokit.request('GET /api/users/me.json') Success Data. +## 更改用户信息 +更改用户信息 + +> 示例: + +```shell +curl -X POST http://localhost:3000/api/users/yystopf.json +``` + +```javascript +await octokit.request('PATCH/PUT /api/users/:login.json') +``` + +### HTTP 请求 +`PATCH/PUT /api/users/:login.json` + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|user.nickname |string |用户昵称 | +|user.user_extension_attributes.gender |int |性别, 0男 1女 | +|user.user_extension_attributes.province |string |省份 | +|user.user_extension_attributes.city |string |城市 | +|user.user_extension_attributes.description |string |个性签名 | +|user.user_extension_attributes.custom_department|string |单位名称 | + +> 请求的JSON示例: + +```json +{ + "user": { + "nickname": "xxx", + "user_extension_attributes": { + "gender": 0, + "province": "湖南", + "city": "长沙", + "description": "个性签名", + "custom_department": "湖南智擎科技有限公司", + } + } +} +``` + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} +``` ## 获取用户星标项目 获取用户星标项目 diff --git a/app/models/user.rb b/app/models/user.rb index 56043f5f6..e190e82ea 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -181,7 +181,7 @@ class User < Owner attr_accessor :password, :password_confirmation - delegate :gender, :department_id, :school_id, :location, :location_city, :technical_title, to: :user_extension, allow_nil: true + delegate :description, :gender, :department_id, :school_id, :location, :location_city, :technical_title, :province, :city, :custom_department, to: :user_extension, allow_nil: true before_save :update_hashed_password after_create do diff --git a/app/models/user_extension.rb b/app/models/user_extension.rb index 4afd89bd5..56eed12bd 100644 --- a/app/models/user_extension.rb +++ b/app/models/user_extension.rb @@ -22,9 +22,9 @@ # school_id :integer # description :string(255) default("") # department_id :integer -# honor :text(65535) -# edu_background :integer -# edu_entry_year :integer +# province :string(255) +# city :string(255) +# custom_department :string(255) # # Indexes # diff --git a/app/views/users/show.json.jbuilder b/app/views/users/show.json.jbuilder index c529cf79f..560c207d6 100644 --- a/app/views/users/show.json.jbuilder +++ b/app/views/users/show.json.jbuilder @@ -18,4 +18,9 @@ json.user_org_count @user_org_count json.common_projects_count @projects_common_count json.mirror_projects_count @projects_mirrior_count json.sync_mirror_projects_count @projects_sync_mirrior_count -json.created_time format_time(@user.created_on) \ No newline at end of file +json.created_time format_time(@user.created_on) +json.email @user.mail +json.province @user.province +json.city @user.city +json.custom_department @user.custom_department +json.description @user.description \ No newline at end of file diff --git a/db/migrate/20210531100250_add_fields_to_user_extensions.rb b/db/migrate/20210531100250_add_fields_to_user_extensions.rb new file mode 100644 index 000000000..880438405 --- /dev/null +++ b/db/migrate/20210531100250_add_fields_to_user_extensions.rb @@ -0,0 +1,8 @@ +class AddFieldsToUserExtensions < ActiveRecord::Migration[5.2] + def change + add_column :user_extensions, :province, :string # 省份 + add_column :user_extensions, :city, :string # 城市 + add_column :user_extensions, :custom_department, :string #自己填写的单位名称 + remove_column :users, :description + end +end diff --git a/public/docs/api.html b/public/docs/api.html index 616803e4e..e713ea1d0 100644 --- a/public/docs/api.html +++ b/public/docs/api.html @@ -331,6 +331,9 @@
  • 获取当前登陆用户信息
  • +
  • + 更改用户信息 +
  • 获取用户星标项目
  • @@ -611,7 +614,7 @@ Success — a happy kitten is an authenticated kitten!

    Users

    获取当前登陆用户信息

    @@ -673,7 +676,80 @@ Success — a happy kitten is an authenticated kitten! -

    获取用户星标项目

    +

    更改用户信息

    +

    更改用户信息

    + +
    +

    示例:

    +
    +
    curl -X POST http://localhost:3000/api/users/yystopf.json
    +
    await octokit.request('PATCH/PUT /api/users/:login.json')
    +

    HTTP 请求

    +

    PATCH/PUT /api/users/:login.json

    +

    请求字段说明:

    +
    参数
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    参数类型字段说明
    user.nicknamestring用户昵称
    user.user_extension_attributes.genderint性别, 0男 1女
    user.user_extension_attributes.provincestring省份
    user.user_extension_attributes.citystring城市
    user.user_extension_attributes.descriptionstring个性签名
    user.user_extension_attributes.custom_departmentstring单位名称
    + +
    +

    请求的JSON示例:

    +
    +
    {
    +    "user": {
    +        "nickname": "xxx",
    +        "user_extension_attributes": {
    +            "gender": 0,
    +            "province": "湖南",
    +            "city": "长沙",
    +            "description": "个性签名",
    +            "custom_department": "湖南智擎科技有限公司",
    +        }
    +    }
    +}
    +
    +
    +

    返回的JSON示例:

    +
    +
    {
    +    "status": 0,
    +    "message": "success"
    +}
    +

    获取用户星标项目

    获取用户星标项目

    @@ -681,7 +757,7 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/is_pinned_projects.json
     
    await octokit.request('GET /api/users/:login/is_pinned_projects.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET api/users/:login/is_pinned_projects.json

    返回字段说明:

    @@ -863,9 +939,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X POST http://localhost:3000/api/users/yystopf/is_pinned_projects/pin.json
     
    await octokit.request('GET /api/users/:login/is_pinned_projects/pin.json')
    -

    HTTP 请求

    +

    HTTP 请求

    POST /api/users/:login/is_pinned_projects/pin.json

    -

    请求字段说明:

    同时设定多个星标项目

    +

    请求字段说明:

    同时设定多个星标项目

    @@ -909,7 +985,7 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/statistics/activity.json
     
    await octokit.request('GET /api/users/:login/statistics/activity.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/statistics/activity.json

    返回字段说明:

    参数
    @@ -998,9 +1074,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/headmaps.json
     
    await octokit.request('GET /api/users/:login/headmaps.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET api/users/:login/headmaps.json

    -

    请求字段说明:

    +

    请求字段说明:

    @@ -1143,9 +1219,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/project_trends.json
     
    await octokit.request('GET /api/users/:login/project_trends.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET api/users/:login/project_trends.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1460,9 +1536,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/statistics/develop.json
     
    await octokit.request('GET /api/users/:login/statistics/develop.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/statistics/develop.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1603,9 +1679,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/statistics/role.json
     
    await octokit.request('GET /api/users/:login/statistics/role.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/statistics/role.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1685,9 +1761,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/statistics/major.json
     
    await octokit.request('GET /api/users/:login/statistics/major.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/statistics/major.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1746,9 +1822,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/applied_messages.json
     
    await octokit.request('GET /api/users/:login/applied_messages.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_messages.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1983,9 +2059,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/applied_transfer_projects.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -2175,9 +2251,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/accept.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/accept.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects/:id/accept.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -2366,9 +2442,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/refuse.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/refuse.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects/:id/refuse.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    From dc91cd43461bd856a653b79d2a6f5abe7aa94ef4 Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Mon, 31 May 2021 18:46:39 +0800 Subject: [PATCH 29/51] fix --- db/migrate/20210531100250_add_fields_to_user_extensions.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/migrate/20210531100250_add_fields_to_user_extensions.rb b/db/migrate/20210531100250_add_fields_to_user_extensions.rb index 880438405..890cd35ae 100644 --- a/db/migrate/20210531100250_add_fields_to_user_extensions.rb +++ b/db/migrate/20210531100250_add_fields_to_user_extensions.rb @@ -3,6 +3,6 @@ class AddFieldsToUserExtensions < ActiveRecord::Migration[5.2] add_column :user_extensions, :province, :string # 省份 add_column :user_extensions, :city, :string # 城市 add_column :user_extensions, :custom_department, :string #自己填写的单位名称 - remove_column :users, :description + # remove_column :users, :description end end From 21d47513271f0e6c827a2b531c6a21b99a6b8cf8 Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Tue, 1 Jun 2021 10:07:01 +0800 Subject: [PATCH 30/51] add: update user image --- app/controllers/application_controller.rb | 19 +++++++++++++++++++ .../organizations/organizations_controller.rb | 19 ------------------- app/controllers/users_controller.rb | 6 ++++-- app/docs/slate/source/includes/_users.md | 3 ++- app/queries/projects/list_my_query.rb | 2 +- public/docs/api.html | 7 ++++++- 6 files changed, 32 insertions(+), 24 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 6875b8155..8536147ca 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -773,7 +773,26 @@ class ApplicationController < ActionController::Base def base_url request.base_url end + + def convert_image! + @image = params[:image] || user_params[:image] + return unless @image.present? + max_size = EduSetting.get('upload_avatar_max_size') || 2 * 1024 * 1024 # 2M + if @image.class == ActionDispatch::Http::UploadedFile + render_error('请上传文件') if @image.size.zero? + render_error('文件大小超过限制') if @image.size > max_size.to_i + else + image = @image.to_s.strip + return render_error('请上传正确的图片') if image.blank? + @image = Util.convert_base64_image(image, max_size: max_size.to_i) + end + rescue Base64ImageConverter::Error => ex + render_error(ex.message) + end + def avatar_path(object) + ApplicationController.helpers.disk_filename(object.class, object.id) + end private def object_not_found diff --git a/app/controllers/organizations/organizations_controller.rb b/app/controllers/organizations/organizations_controller.rb index 29cb15a6a..7be9390d7 100644 --- a/app/controllers/organizations/organizations_controller.rb +++ b/app/controllers/organizations/organizations_controller.rb @@ -70,25 +70,6 @@ class Organizations::OrganizationsController < Organizations::BaseController end private - def convert_image! - return unless params[:image].present? - max_size = EduSetting.get('upload_avatar_max_size') || 2 * 1024 * 1024 # 2M - if params[:image].class == ActionDispatch::Http::UploadedFile - @image = params[:image] - render_error('请上传文件') if @image.size.zero? - render_error('文件大小超过限制') if @image.size > max_size.to_i - else - image = params[:image].to_s.strip - return render_error('请上传正确的图片') if image.blank? - @image = Util.convert_base64_image(image, max_size: max_size.to_i) - end - rescue Base64ImageConverter::Error => ex - render_error(ex.message) - end - - def avatar_path(organization) - ApplicationController.helpers.disk_filename(organization.class, organization.id) - end def organization_params params.permit(:name, :description, :website, :location, diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 4cbb2cbdf..6c28271db 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -6,6 +6,7 @@ class UsersController < ApplicationController before_action :check_user_exist, only: [:show, :homepage_info,:projects, :watch_users, :fan_users, :hovercard] before_action :require_login, only: %i[me list sync_user_info] before_action :connect_to_ci_db, only: [:get_user_info] + before_action :convert_image!, only: [:update] skip_before_action :check_sign, only: [:attachment_show] def connect_to_ci_db(options={}) @@ -73,7 +74,8 @@ class UsersController < ApplicationController def update return render_not_found unless @user = User.find_by_id(params[:id]) || User.find_by(login: params[:id]) - @user.attributes = user_params + Util.write_file(@image, avatar_path(@user)) if user_params[:image].present? + @user.attributes = user_params.except(:image) if @user.save render_ok else @@ -278,7 +280,7 @@ class UsersController < ApplicationController end def user_params - params.require(:user).permit(:nickname, + params.require(:user).permit(:nickname, :image, user_extension_attributes: [ :gender, :location, :location_city, :occupation, :technical_title, diff --git a/app/docs/slate/source/includes/_users.md b/app/docs/slate/source/includes/_users.md index 573e171eb..b72ee0c12 100644 --- a/app/docs/slate/source/includes/_users.md +++ b/app/docs/slate/source/includes/_users.md @@ -1,7 +1,7 @@ # Users @@ -67,6 +67,7 @@ await octokit.request('PATCH/PUT /api/users/:login.json') 参数 | 类型 | 字段说明 --------- | ----------- | ----------- |user.nickname |string |用户昵称 | +|user.image |string/file |用户头像 | |user.user_extension_attributes.gender |int |性别, 0男 1女 | |user.user_extension_attributes.province |string |省份 | |user.user_extension_attributes.city |string |城市 | diff --git a/app/queries/projects/list_my_query.rb b/app/queries/projects/list_my_query.rb index 5bda56120..5c508c961 100644 --- a/app/queries/projects/list_my_query.rb +++ b/app/queries/projects/list_my_query.rb @@ -53,7 +53,7 @@ class Projects::ListMyQuery < ApplicationQuery q = projects.ransack(name_or_identifier_cont: params[:search]) - scope = q.result.includes(:project_category, :project_language,:owner, :repository) + scope = q.result.includes(:project_category, :project_language,:owner, :repository, :has_pinned_users) sort = params[:sort_by] || "updated_on" sort_direction = params[:sort_direction] || "desc" diff --git a/public/docs/api.html b/public/docs/api.html index e713ea1d0..71753c32b 100644 --- a/public/docs/api.html +++ b/public/docs/api.html @@ -614,7 +614,7 @@ Success — a happy kitten is an authenticated kitten!

    Users

    获取当前登陆用户信息

    @@ -700,6 +700,11 @@ Success — a happy kitten is an authenticated kitten!
    + + + + + From 7ba45bc86657b56557a05fcf5fed51052838fe5a Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Wed, 2 Jun 2021 15:29:00 +0800 Subject: [PATCH 31/51] fix: some bug --- app/views/project_trends/_detail.json.jbuilder | 4 ++-- app/views/users/_watch_user_detail.json.jbuilder | 2 +- app/views/users/watch_users.json.jbuilder | 2 +- config/locales/zh-CN.yml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/views/project_trends/_detail.json.jbuilder b/app/views/project_trends/_detail.json.jbuilder index 7ffa9f152..75bcf2237 100644 --- a/app/views/project_trends/_detail.json.jbuilder +++ b/app/views/project_trends/_detail.json.jbuilder @@ -12,6 +12,6 @@ if trend.trend_type == "Issue" elsif trend.trend_type == "VersionRelease" json.partial! "version_releases/simple_version_release", locals: {version: trend.trend} else - json.name trend.trend.title - json.created_at format_time(trend.trend.created_at) + json.name trend.trend&.title + json.created_at format_time(trend.trend&.created_at) end diff --git a/app/views/users/_watch_user_detail.json.jbuilder b/app/views/users/_watch_user_detail.json.jbuilder index 80a711626..8c4881bcc 100644 --- a/app/views/users/_watch_user_detail.json.jbuilder +++ b/app/views/users/_watch_user_detail.json.jbuilder @@ -3,7 +3,7 @@ json.format_time target.created_at.strftime("%Y-%m-%d") json.name user.try(:show_real_name) json.login user.try(:login) json.image_url url_to_avatar(user) -json.is_current_user current_user.try(:id) == target.user_id +json.is_current_user current_user.try(:id) == user.id json.is_watch current_user&.watched?(user) diff --git a/app/views/users/watch_users.json.jbuilder b/app/views/users/watch_users.json.jbuilder index b265e2e0a..ed2697f0c 100644 --- a/app/views/users/watch_users.json.jbuilder +++ b/app/views/users/watch_users.json.jbuilder @@ -1,7 +1,7 @@ json.count @watchers_count json.users do json.array! @watchers do |watcher| - json.partial! "/users/watch_user_detail", locals: {target: watcher, user: watcher.watchable} + json.partial! "/users/watch_user_detail", target: watcher, user: watcher.watchable end # json.partial! "/users/watch_user_detail", collection: @watchers, as: :target end \ No newline at end of file diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml index c040f9bd1..db1030163 100644 --- a/config/locales/zh-CN.yml +++ b/config/locales/zh-CN.yml @@ -15,7 +15,7 @@ zh-CN: 'refused': '已拒绝' 'agreed': '已同意' trend: - Issue: 工单 + Issue: 易修(Issue) PullRequest: 合并请求 VersionRelease: 版本发布 create: 创建了 From 16c293562ac284892c17b9b1a6fabfa2c7c2e0cf Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Wed, 2 Jun 2021 16:40:40 +0800 Subject: [PATCH 32/51] add: pinned projects order by position --- .../users/is_pinned_projects_controller.rb | 19 +++- app/docs/slate/source/includes/_users.md | 44 ++++++++- .../is_pinned_projects/index.json.jbuilder | 4 +- config/routes.rb | 2 +- public/docs/api.html | 91 ++++++++++++++----- 5 files changed, 134 insertions(+), 26 deletions(-) diff --git a/app/controllers/users/is_pinned_projects_controller.rb b/app/controllers/users/is_pinned_projects_controller.rb index 4f3f4e37e..1ddadd277 100644 --- a/app/controllers/users/is_pinned_projects_controller.rb +++ b/app/controllers/users/is_pinned_projects_controller.rb @@ -1,7 +1,7 @@ class Users::IsPinnedProjectsController < Users::BaseController before_action :private_user_resources!, only: [:pin] def index - @is_pinned_projects = observed_user.is_pinned_projects.includes(:project_category, :project_language, :repository).order(position: :desc) + @is_pinned_projects = observed_user.pinned_projects.order(position: :desc, created_at: :asc).includes(project: [:project_category, :project_language, :repository]).order(position: :desc) @is_pinned_projects = kaminari_paginate(@is_pinned_projects) end @@ -15,6 +15,19 @@ class Users::IsPinnedProjectsController < Users::BaseController tip_exception(e.message) end + def update + @pinned_project = PinnedProject.find_by_id(params[:id]) + @pinned_project.attributes = pinned_project_params + if @pinned_project.save + render_ok + else + render_error + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + private def is_pinned_project_ids if params[:is_pinned_project_ids].present? @@ -25,4 +38,8 @@ class Users::IsPinnedProjectsController < Users::BaseController return observed_user.is_pinned_project_ids.include?(params[:is_pinned_project_id].to_i) ? observed_user.is_pinned_project_ids : observed_user.is_pinned_project_ids.push(params[:is_pinned_project_id].to_i) end end + + def pinned_project_params + params.require(:pinned_project).permit(:position) + end end \ No newline at end of file diff --git a/app/docs/slate/source/includes/_users.md b/app/docs/slate/source/includes/_users.md index b72ee0c12..5771f757f 100644 --- a/app/docs/slate/source/includes/_users.md +++ b/app/docs/slate/source/includes/_users.md @@ -1,7 +1,7 @@ # Users @@ -53,7 +53,7 @@ await octokit.request('GET /api/users/me.json') > 示例: ```shell -curl -X POST http://localhost:3000/api/users/yystopf.json +curl -X PATCH/PUT http://localhost:3000/api/users/yystopf.json ``` ```javascript @@ -141,6 +141,7 @@ await octokit.request('GET /api/users/:login/is_pinned_projects.json') |author.image_url |string |项目拥有者头像| |category.name |string |项目分类名称| |language.name |string |项目语言名称| +|position |int |项目排序| > 返回的JSON示例: @@ -228,6 +229,45 @@ await octokit.request('GET /api/users/:login/is_pinned_projects/pin.json') ``` +## 星标项目展示排序 +星标项目展示排序 + +> 示例: + +```shell +curl -X PATCH http://localhost:3000/api/users/yystopf/is_pinned_projects/11.json +``` + +```javascript +await octokit.request('PATCH/PUT /api/users/:login/is_pinned_projects/:id.json') +``` + +### HTTP 请求 +`PATCH/PUT /api/users/:login/is_pinned_projects/:id.json` + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|pinned_projects.position |int |排序,数字越大排名越前 | + +> 请求的JSON示例: + +```json +{ + "pinned_project": { + "position": 1 + } +} +``` + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} +``` ## 用户近期活动统计 用户近期活动统计, 默认显示近一周的数据 diff --git a/app/views/users/is_pinned_projects/index.json.jbuilder b/app/views/users/is_pinned_projects/index.json.jbuilder index facc158b9..a96ecf986 100644 --- a/app/views/users/is_pinned_projects/index.json.jbuilder +++ b/app/views/users/is_pinned_projects/index.json.jbuilder @@ -1,4 +1,6 @@ json.total_count @is_pinned_projects.total_count json.projects @is_pinned_projects.each do |project| - json.partial! "projects/project_detail", project: project + json.partial! "projects/project_detail", project: project&.project + json.id project.id + json.position project.position end \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index cfadf4941..1160a4072 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -266,7 +266,7 @@ Rails.application.routes.draw do end end resources :headmaps, only: [:index] - resources :is_pinned_projects, only: [:index] do + resources :is_pinned_projects, only: [:index, :update] do collection do post :pin end diff --git a/public/docs/api.html b/public/docs/api.html index 71753c32b..c8fa29fa2 100644 --- a/public/docs/api.html +++ b/public/docs/api.html @@ -340,6 +340,9 @@
  • 用户添加星标项目
  • +
  • + 星标项目展示排序 +
  • 用户近期活动统计
  • @@ -614,7 +617,7 @@ Success — a happy kitten is an authenticated kitten!

    Users

    获取当前登陆用户信息

    @@ -682,7 +685,7 @@ Success — a happy kitten is an authenticated kitten!

    示例:

    -
    curl -X POST http://localhost:3000/api/users/yystopf.json
    +
    curl -X PATCH/PUT http://localhost:3000/api/users/yystopf.json
     
    await octokit.request('PATCH/PUT /api/users/:login.json')
     

    HTTP 请求

    PATCH/PUT /api/users/:login.json

    @@ -887,6 +890,11 @@ Success — a happy kitten is an authenticated kitten!
    + + + + +
    参数用户昵称
    user.imagestring/file用户头像
    user.user_extension_attributes.gender int 性别, 0男 1女string 项目语言名称
    positionint项目排序
    @@ -975,6 +983,47 @@ Success — a happy kitten is an authenticated kitten! +
    +

    返回的JSON示例:

    +
    +
    {
    +    "status": 0,
    +    "message": "success"
    +}
    +

    星标项目展示排序

    +

    星标项目展示排序

    + +
    +

    示例:

    +
    +
    curl -X PATCH http://localhost:3000/api/users/yystopf/is_pinned_projects/11.json
    +
    await octokit.request('PATCH/PUT /api/users/:login/is_pinned_projects/:id.json')
    +

    HTTP 请求

    +

    PATCH/PUT /api/users/:login/is_pinned_projects/:id.json

    +

    请求字段说明:

    + + + + + + + + + + + + +
    参数类型字段说明
    pinned_projects.positionint排序,数字越大排名越前
    + +
    +

    请求的JSON示例:

    +
    +
    {
    +    "pinned_project": {
    +        "position": 1
    +    }
    +}
    +

    返回的JSON示例:

    @@ -990,7 +1039,7 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/statistics/activity.json
     
    await octokit.request('GET /api/users/:login/statistics/activity.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/statistics/activity.json

    返回字段说明:

    @@ -1079,9 +1128,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/headmaps.json
     
    await octokit.request('GET /api/users/:login/headmaps.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET api/users/:login/headmaps.json

    -

    请求字段说明:

    +

    请求字段说明:

    @@ -1224,9 +1273,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/project_trends.json
     
    await octokit.request('GET /api/users/:login/project_trends.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET api/users/:login/project_trends.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1541,9 +1590,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/statistics/develop.json
     
    await octokit.request('GET /api/users/:login/statistics/develop.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/statistics/develop.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1684,9 +1733,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/statistics/role.json
     
    await octokit.request('GET /api/users/:login/statistics/role.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/statistics/role.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1766,9 +1815,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/statistics/major.json
     
    await octokit.request('GET /api/users/:login/statistics/major.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/statistics/major.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -1827,9 +1876,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/applied_messages.json
     
    await octokit.request('GET /api/users/:login/applied_messages.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_messages.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -2064,9 +2113,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X GET http://localhost:3000/api/users/yystopf/applied_transfer_projects.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -2256,9 +2305,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/accept.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/accept.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects/:id/accept.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    @@ -2447,9 +2496,9 @@ Success — a happy kitten is an authenticated kitten!
    curl -X POST http://localhost:3000/api/users/yystopf/applied_transfer_projects/2/refuse.json
     
    await octokit.request('GET /api/users/:login/applied_transfer_projects/:id/refuse.json')
    -

    HTTP 请求

    +

    HTTP 请求

    GET /api/users/:login/applied_transfer_projects/:id/refuse.json

    -

    请求字段说明:

    +

    请求字段说明:

    参数
    From fff790bb1935b58ae7b650ea03eb1cc3d16b7d52 Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Wed, 2 Jun 2021 17:29:11 +0800 Subject: [PATCH 33/51] add: pinned projects project_id --- app/views/users/is_pinned_projects/index.json.jbuilder | 1 + 1 file changed, 1 insertion(+) diff --git a/app/views/users/is_pinned_projects/index.json.jbuilder b/app/views/users/is_pinned_projects/index.json.jbuilder index a96ecf986..7790607d6 100644 --- a/app/views/users/is_pinned_projects/index.json.jbuilder +++ b/app/views/users/is_pinned_projects/index.json.jbuilder @@ -3,4 +3,5 @@ json.projects @is_pinned_projects.each do |project| json.partial! "projects/project_detail", project: project&.project json.id project.id json.position project.position + json.project_id project.project_id end \ No newline at end of file From 0368c0321f7be39c868fb2e1541034e089155b12 Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Thu, 3 Jun 2021 09:48:58 +0800 Subject: [PATCH 34/51] fix: org transfer bug --- app/services/projects/transfer_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb index a2da34f09..0b4f1d998 100644 --- a/app/services/projects/transfer_service.rb +++ b/app/services/projects/transfer_service.rb @@ -34,7 +34,7 @@ class Projects::TransferService < ApplicationService def update_visit_teams if new_owner.is_a?(Organization) # 为包含组织所有项目的团队创建项目访问权限 - new_owner.build_permit_team_projects(project.id) + new_owner.build_permit_team_projects!(project.id) else project.team_projects.each(&:destroy!) end From 7dc21ff38840907d7ec673f8cf93c3dc181fc82b Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Thu, 3 Jun 2021 10:19:33 +0800 Subject: [PATCH 35/51] add: update user more info --- app/controllers/users_controller.rb | 3 ++- app/docs/slate/source/includes/_users.md | 12 ++++++--- app/models/user.rb | 4 ++- app/models/user_extension.rb | 3 +++ app/views/users/show.json.jbuilder | 8 +++--- ...7_add_show_condition_to_user_extensions.rb | 7 +++++ public/docs/api.html | 26 ++++++++++++++++--- 7 files changed, 50 insertions(+), 13 deletions(-) create mode 100644 db/migrate/20210603020327_add_show_condition_to_user_extensions.rb diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 6c28271db..3f7cd4170 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -285,7 +285,8 @@ class UsersController < ApplicationController :gender, :location, :location_city, :occupation, :technical_title, :school_id, :department_id, :province, :city, - :custom_department, :identity, :student_id, :description] + :custom_department, :identity, :student_id, :description, + :show_email, :show_location, :show_department] ) end diff --git a/app/docs/slate/source/includes/_users.md b/app/docs/slate/source/includes/_users.md index 5771f757f..72bf724a5 100644 --- a/app/docs/slate/source/includes/_users.md +++ b/app/docs/slate/source/includes/_users.md @@ -1,7 +1,7 @@ # Users @@ -66,13 +66,17 @@ await octokit.request('PATCH/PUT /api/users/:login.json') ### 请求字段说明: 参数 | 类型 | 字段说明 --------- | ----------- | ----------- -|user.nickname |string |用户昵称 | -|user.image |string/file |用户头像 | +|user.nickname |string |用户昵称 | +|user.image |base64/file |用户头像 | |user.user_extension_attributes.gender |int |性别, 0男 1女 | |user.user_extension_attributes.province |string |省份 | |user.user_extension_attributes.city |string |城市 | -|user.user_extension_attributes.description |string |个性签名 | +|user.user_extension_attributes.description |string |简介 | |user.user_extension_attributes.custom_department|string |单位名称 | +|user.user_extension_attributes.technical_title |string |职业 | +|user.user_extension_attributes.show_email |bool |是否展示邮箱 | +|user.user_extension_attributes.show_location |bool |是否展示位置 | +|user.user_extension_attributes.show_department |bool |是否展示公司 | > 请求的JSON示例: diff --git a/app/models/user.rb b/app/models/user.rb index e190e82ea..09880b8cd 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -181,7 +181,9 @@ class User < Owner attr_accessor :password, :password_confirmation - delegate :description, :gender, :department_id, :school_id, :location, :location_city, :technical_title, :province, :city, :custom_department, to: :user_extension, allow_nil: true + delegate :description, :gender, :department_id, :school_id, :location, :location_city, + :show_email, :show_location, :show_department, + :technical_title, :province, :city, :custom_department, to: :user_extension, allow_nil: true before_save :update_hashed_password after_create do diff --git a/app/models/user_extension.rb b/app/models/user_extension.rb index 56eed12bd..47b27c08b 100644 --- a/app/models/user_extension.rb +++ b/app/models/user_extension.rb @@ -25,6 +25,9 @@ # province :string(255) # city :string(255) # custom_department :string(255) +# show_email :boolean default("0") +# show_location :boolean default("0") +# show_department :boolean default("0") # # Indexes # diff --git a/app/views/users/show.json.jbuilder b/app/views/users/show.json.jbuilder index 560c207d6..06fab129f 100644 --- a/app/views/users/show.json.jbuilder +++ b/app/views/users/show.json.jbuilder @@ -19,8 +19,8 @@ json.common_projects_count @projects_common_count json.mirror_projects_count @projects_mirrior_count json.sync_mirror_projects_count @projects_sync_mirrior_count json.created_time format_time(@user.created_on) -json.email @user.mail -json.province @user.province -json.city @user.city -json.custom_department @user.custom_department +json.email @user.show_email ? @user.mail : nil +json.province @user.show_location ? @user.province : nil +json.city @user.show_location ? @user.city : nil +json.custom_department @user.show_department ? @user.custom_department : nil json.description @user.description \ No newline at end of file diff --git a/db/migrate/20210603020327_add_show_condition_to_user_extensions.rb b/db/migrate/20210603020327_add_show_condition_to_user_extensions.rb new file mode 100644 index 000000000..e64da0b71 --- /dev/null +++ b/db/migrate/20210603020327_add_show_condition_to_user_extensions.rb @@ -0,0 +1,7 @@ +class AddShowConditionToUserExtensions < ActiveRecord::Migration[5.2] + def change + add_column :user_extensions, :show_email, :boolean, default: false + add_column :user_extensions, :show_location, :boolean, default: false + add_column :user_extensions, :show_department, :boolean, default: false + end +end diff --git a/public/docs/api.html b/public/docs/api.html index c8fa29fa2..0cf007cf1 100644 --- a/public/docs/api.html +++ b/public/docs/api.html @@ -617,7 +617,7 @@ Success — a happy kitten is an authenticated kitten!

    Users

    获取当前登陆用户信息

    @@ -704,7 +704,7 @@ Success — a happy kitten is an authenticated kitten!
    - + @@ -725,13 +725,33 @@ Success — a happy kitten is an authenticated kitten! - + + + + + + + + + + + + + + + + + + + + +
    参数
    user.imagestring/filebase64/file 用户头像
    user.user_extension_attributes.description string个性签名简介
    user.user_extension_attributes.custom_department string 单位名称
    user.user_extension_attributes.technical_titlestring职业
    user.user_extension_attributes.show_emailbool是否展示邮箱
    user.user_extension_attributes.show_locationbool是否展示位置
    user.user_extension_attributes.show_departmentbool是否展示公司
    From c58b074173a5c99157ca116319ebf9ec472409b3 Mon Sep 17 00:00:00 2001 From: viletyy Date: Thu, 3 Jun 2021 11:26:14 +0800 Subject: [PATCH 36/51] fix: init project --- app/models/attachment.rb | 8 +- app/models/ci/user.rb | 13 ++- app/models/issue.rb | 5 +- app/models/laboratory.rb | 1 - app/models/organization.rb | 13 ++- app/models/project.rb | 133 +++++++++++++--------------- app/models/project_category.rb | 5 ++ app/models/pull_request.rb | 5 -- app/models/repository.rb | 1 + app/models/user.rb | 13 ++- app/models/user_action.rb | 4 +- app/models/user_agent.rb | 5 +- app/models/user_extension.rb | 6 -- db/init_data.sql | 95 ++++++++++++++++++++ db/structure.sql | 95 -------------------- lib/tasks/sync_table_structure.rake | 18 ++++ 16 files changed, 204 insertions(+), 216 deletions(-) create mode 100644 db/init_data.sql diff --git a/app/models/attachment.rb b/app/models/attachment.rb index 1ca173458..461c835fe 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -17,7 +17,7 @@ # disk_directory :string(255) # attachtype :integer default("1") # is_public :integer default("1") -# copy_from :string(255) +# copy_from :integer # quotes :integer default("0") # is_publish :integer default("1") # publish_time :datetime @@ -26,15 +26,15 @@ # cloud_url :string(255) default("") # course_second_category_id :integer default("0") # delay_publish :boolean default("0") -# link :string(255) -# clone_id :integer # # Indexes # # index_attachments_on_author_id (author_id) -# index_attachments_on_clone_id (clone_id) # index_attachments_on_container_id_and_container_type (container_id,container_type) +# index_attachments_on_course_second_category_id (course_second_category_id) # index_attachments_on_created_on (created_on) +# index_attachments_on_is_public (is_public) +# index_attachments_on_quotes (quotes) # class Attachment < ApplicationRecord diff --git a/app/models/ci/user.rb b/app/models/ci/user.rb index e4a4d0623..cd6246753 100644 --- a/app/models/ci/user.rb +++ b/app/models/ci/user.rb @@ -39,15 +39,13 @@ # business :boolean default("0") # profile_completed :boolean default("0") # laboratory_id :integer -# is_shixun_marker :boolean default("0") -# admin_visitable :boolean default("0") -# collaborator :boolean default("0") +# platform :string(255) default("0") +# gitea_token :string(255) # gitea_uid :integer +# is_shixun_marker :boolean default("0") # is_sync_pwd :boolean default("1") # watchers_count :integer default("0") # devops_step :integer default("0") -# gitea_token :string(255) -# platform :string(255) # # Indexes # @@ -55,9 +53,8 @@ # index_users_on_homepage_engineer (homepage_engineer) # index_users_on_homepage_teacher (homepage_teacher) # index_users_on_laboratory_id (laboratory_id) -# index_users_on_login (login) UNIQUE -# index_users_on_mail (mail) UNIQUE -# index_users_on_phone (phone) UNIQUE +# index_users_on_login (login) +# index_users_on_mail (mail) # index_users_on_type (type) # diff --git a/app/models/issue.rb b/app/models/issue.rb index 69de1eae2..58607ebdd 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -6,7 +6,7 @@ # tracker_id :integer not null # project_id :integer not null # subject :string(255) default(""), not null -# description :text(4294967295) +# description :text(65535) # due_date :date # category_id :integer # status_id :integer not null @@ -14,6 +14,7 @@ # priority_id :integer not null # fixed_version_id :integer # author_id :integer not null +# lock_version :integer default("0"), not null # created_on :datetime # updated_on :datetime # start_date :date @@ -27,7 +28,7 @@ # closed_on :datetime # project_issues_index :integer # issue_type :string(255) -# token :integer default("0") +# token :string(255) # issue_tags_value :string(255) # is_lock :boolean default("0") # issue_classify :string(255) diff --git a/app/models/laboratory.rb b/app/models/laboratory.rb index 9d3ca07dd..699800c92 100644 --- a/app/models/laboratory.rb +++ b/app/models/laboratory.rb @@ -10,7 +10,6 @@ # sync_course :boolean default("0") # sync_subject :boolean default("0") # sync_shixun :boolean default("0") -# is_local :boolean default("0") # # Indexes # diff --git a/app/models/organization.rb b/app/models/organization.rb index 444938e72..988ecd7fb 100644 --- a/app/models/organization.rb +++ b/app/models/organization.rb @@ -39,15 +39,13 @@ # business :boolean default("0") # profile_completed :boolean default("0") # laboratory_id :integer -# is_shixun_marker :boolean default("0") -# admin_visitable :boolean default("0") -# collaborator :boolean default("0") +# platform :string(255) default("0") +# gitea_token :string(255) # gitea_uid :integer +# is_shixun_marker :boolean default("0") # is_sync_pwd :boolean default("1") # watchers_count :integer default("0") # devops_step :integer default("0") -# gitea_token :string(255) -# platform :string(255) # # Indexes # @@ -55,9 +53,8 @@ # index_users_on_homepage_engineer (homepage_engineer) # index_users_on_homepage_teacher (homepage_teacher) # index_users_on_laboratory_id (laboratory_id) -# index_users_on_login (login) UNIQUE -# index_users_on_mail (mail) UNIQUE -# index_users_on_phone (phone) UNIQUE +# index_users_on_login (login) +# index_users_on_mail (mail) # index_users_on_type (type) # diff --git a/app/models/project.rb b/app/models/project.rb index 8141a56bf..19739f93d 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1,75 +1,64 @@ -# == Schema Information -# -# Table name: projects -# -# id :integer not null, primary key -# name :string(255) default(""), not null -# description :text(4294967295) -# homepage :string(255) default("") -# is_public :boolean default("1"), not null -# parent_id :integer -# created_on :datetime -# updated_on :datetime -# identifier :string(255) -# status :integer default("1"), not null -# lft :integer -# rgt :integer -# inherit_members :boolean default("0"), not null -# project_type :integer default("0") -# hidden_repo :boolean default("0"), not null -# attachmenttype :integer default("1") -# user_id :integer -# dts_test :integer default("0") -# enterprise_name :string(255) -# organization_id :integer -# project_new_type :integer -# gpid :integer -# forked_from_project_id :integer -# forked_count :integer default("0") -# publish_resource :integer default("0") -# visits :integer default("0") -# hot :integer default("0") -# invite_code :string(255) -# qrcode :string(255) -# qrcode_expiretime :integer default("0") -# script :text(65535) -# training_status :integer default("0") -# rep_identifier :string(255) -# project_category_id :integer -# project_language_id :integer -# praises_count :integer default("0") -# watchers_count :integer default("0") -# issues_count :integer default("0") -# pull_requests_count :integer default("0") -# language :string(255) -# versions_count :integer default("0") -# issue_tags_count :integer default("0") -# closed_issues_count :integer default("0") -# open_devops :boolean default("0") -# gitea_webhook_id :integer -# open_devops_count :integer default("0") -# recommend :boolean default("0") -# platform :integer default("0") -# license_id :integer -# ignore_id :integer -# default_branch :string(255) default("master") -# website :string(255) -# lesson_url :string(255) -# -# Indexes -# -# index_projects_on_forked_from_project_id (forked_from_project_id) -# index_projects_on_identifier (identifier) -# index_projects_on_is_public (is_public) -# index_projects_on_lft (lft) -# index_projects_on_name (name) -# index_projects_on_platform (platform) -# index_projects_on_project_type (project_type) -# index_projects_on_recommend (recommend) -# index_projects_on_rgt (rgt) -# index_projects_on_status (status) -# index_projects_on_updated_on (updated_on) -# +# == Schema Information +# +# Table name: projects +# +# id :integer not null, primary key +# name :string(255) default(""), not null +# description :text(65535) +# 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") +# +# 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 diff --git a/app/models/project_category.rb b/app/models/project_category.rb index 67b802998..3a9819816 100644 --- a/app/models/project_category.rb +++ b/app/models/project_category.rb @@ -8,6 +8,11 @@ # projects_count :integer default("0") # created_at :datetime not null # updated_at :datetime not null +# ancestry :string(255) +# +# Indexes +# +# index_project_categories_on_ancestry (ancestry) # class ProjectCategory < ApplicationRecord diff --git a/app/models/pull_request.rb b/app/models/pull_request.rb index 62d6c3cc6..c3eefb0db 100644 --- a/app/models/pull_request.rb +++ b/app/models/pull_request.rb @@ -16,11 +16,6 @@ # head :string(255) # base :string(255) # issue_id :integer -# fork_project_id :integer -# is_original :boolean default("0") -# comments_count :integer default("0") -# commits_count :integer default("0") -# files_count :integer default("0") # class PullRequest < ApplicationRecord diff --git a/app/models/repository.rb b/app/models/repository.rb index 0daa4b916..a58dec900 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -27,6 +27,7 @@ # # Indexes # +# index_repositories_on_identifier (identifier) # index_repositories_on_project_id (project_id) # index_repositories_on_user_id (user_id) # diff --git a/app/models/user.rb b/app/models/user.rb index 09880b8cd..99b1e7cd7 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -39,15 +39,13 @@ # business :boolean default("0") # profile_completed :boolean default("0") # laboratory_id :integer -# is_shixun_marker :boolean default("0") -# admin_visitable :boolean default("0") -# collaborator :boolean default("0") +# platform :string(255) default("0") +# gitea_token :string(255) # gitea_uid :integer +# is_shixun_marker :boolean default("0") # is_sync_pwd :boolean default("1") # watchers_count :integer default("0") # devops_step :integer default("0") -# gitea_token :string(255) -# platform :string(255) # # Indexes # @@ -55,9 +53,8 @@ # index_users_on_homepage_engineer (homepage_engineer) # index_users_on_homepage_teacher (homepage_teacher) # index_users_on_laboratory_id (laboratory_id) -# index_users_on_login (login) UNIQUE -# index_users_on_mail (mail) UNIQUE -# index_users_on_phone (phone) UNIQUE +# index_users_on_login (login) +# index_users_on_mail (mail) # index_users_on_type (type) # diff --git a/app/models/user_action.rb b/app/models/user_action.rb index 179359695..3ad8010ea 100644 --- a/app/models/user_action.rb +++ b/app/models/user_action.rb @@ -12,9 +12,7 @@ # # Indexes # -# index_user_actions_on_ip (ip) -# index_user_actions_on_user_id (user_id) -# index_user_actions_on_user_id_and_action_type (user_id,action_type) +# index_user_actions_on_ip (ip) # class UserAction < ApplicationRecord diff --git a/app/models/user_agent.rb b/app/models/user_agent.rb index ba519d6fb..49d7b35a1 100644 --- a/app/models/user_agent.rb +++ b/app/models/user_agent.rb @@ -10,13 +10,10 @@ # updated_at :datetime not null # register_status :integer default("0") # action_status :integer default("0") -# is_delete :boolean default("0") -# user_id :integer # # Indexes # -# index_user_agents_on_ip (ip) -# index_user_agents_on_user_id (user_id) +# index_user_agents_on_ip (ip) UNIQUE # class UserAgent < ApplicationRecord diff --git a/app/models/user_extension.rb b/app/models/user_extension.rb index 47b27c08b..20e2b5c4f 100644 --- a/app/models/user_extension.rb +++ b/app/models/user_extension.rb @@ -22,12 +22,6 @@ # school_id :integer # description :string(255) default("") # department_id :integer -# province :string(255) -# city :string(255) -# custom_department :string(255) -# show_email :boolean default("0") -# show_location :boolean default("0") -# show_department :boolean default("0") # # Indexes # diff --git a/db/init_data.sql b/db/init_data.sql new file mode 100644 index 000000000..33288736a --- /dev/null +++ b/db/init_data.sql @@ -0,0 +1,95 @@ + +-- ---------------------------- +-- Records of roles +-- ---------------------------- +BEGIN; +INSERT INTO `roles` (`id`, `name`, `position`, `assignable`, `builtin`, `permissions`, `issues_visibility`) VALUES +(1, 'Non member', 1, 1, 1, '---\n- :upload_attachments\n- :memos_attachments_download\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :course_attachments_download\n- :view_course_files\n- :add_messages\n- :delete_own_messages\n- :view_calendar\n- :view_documents\n- :view_files\n- :view_gantt\n- :view_issues\n- :save_queries\n- :comment_news\n- :browse_repository\n- :view_changesets\n- :view_time_entries\n- :view_wiki_pages\n- :view_wiki_edits\n', 'default'), +(2, 'Anonymous', 2, 1, 2, '---\n- :memos_attachments_download\n- :view_course_files\n- :view_calendar\n- :view_documents\n- :view_files\n- :view_gantt\n- :view_issues\n- :browse_repository\n- :view_changesets\n- :view_time_entries\n- :view_wiki_pages\n- :view_wiki_edits\n', 'default'), +(3, 'Manager', 3, 1, 0, '---\n- :add_project\n- :edit_project\n- :close_project\n- :select_project_modules\n- :manage_members\n- :manage_versions\n- :add_subprojects\n- :is_manager\n- :projects_attachments_download\n- :as_teacher\n- :add_course\n- :edit_course\n- :close_course\n- :select_course_modules\n- :view_course_journals_for_messages\n- :course_attachments_download\n- :view_course_files\n- :view_homework_attaches\n- :quote_project\n- :manage_boards\n- :add_messages\n- :edit_messages\n- :edit_own_messages\n- :delete_messages\n- :delete_own_messages\n- :view_calendar\n- :view_code_review\n- :add_code_review\n- :edit_code_review\n- :delete_code_review\n- :assign_code_review\n- :code_review_setting\n- :add_documents\n- :edit_documents\n- :delete_documents\n- :view_documents\n- :manage_files\n- :view_files\n- :view_gantt\n- :manage_categories\n- :view_issues\n- :add_issues\n- :edit_issues\n- :manage_issue_relations\n- :manage_subtasks\n- :set_issues_private\n- :set_own_issues_private\n- :add_issue_notes\n- :edit_issue_notes\n- :edit_own_issue_notes\n- :view_private_notes\n- :set_notes_private\n- :move_issues\n- :delete_issues\n- :manage_public_queries\n- :save_queries\n- :view_issue_watchers\n- :add_issue_watchers\n- :delete_issue_watchers\n- :manage_news\n- :comment_news\n- :manage_repository\n- :browse_repository\n- :view_changesets\n- :commit_access\n- :manage_related_issues\n- :log_time\n- :view_time_entries\n- :edit_time_entries\n- :edit_own_time_entries\n- :manage_project_activities\n- :manage_wiki\n- :rename_wiki_pages\n- :delete_wiki_pages\n- :view_wiki_pages\n- :export_wiki_pages\n- :view_wiki_edits\n- :edit_wiki_pages\n- :delete_wiki_pages_attachments\n- :protect_wiki_pages\n', 'all'), +(4, 'Developer', 5, 1, 0, '---\n- :add_project\n- :manage_versions\n- :projects_attachments_download\n- :add_course\n- :edit_course\n- :close_course\n- :select_course_modules\n- :view_course_journals_for_messages\n- :course_attachments_download\n- :view_course_files\n- :view_homework_attaches\n- :paret_in_homework\n- :select_contest_modules\n- :quote_project\n- :contest_attachments_download\n- :manage_contestnotifications\n- :notificationcomment_contestnotifications\n- :manage_boards\n- :add_messages\n- :edit_own_messages\n- :delete_own_messages\n- :view_calendar\n- :manage_files\n- :view_files\n- :view_gantt\n- :manage_categories\n- :view_issues\n- :add_issues\n- :edit_issues\n- :manage_issue_relations\n- :manage_subtasks\n- :set_issues_private\n- :set_own_issues_private\n- :add_issue_notes\n- :edit_issue_notes\n- :edit_own_issue_notes\n- :view_private_notes\n- :set_notes_private\n- :move_issues\n- :delete_issues\n- :manage_public_queries\n- :save_queries\n- :view_issue_watchers\n- :add_issue_watchers\n- :delete_issue_watchers\n- :manage_repository\n- :browse_repository\n- :view_changesets\n- :commit_access\n- :manage_related_issues\n', 'all'), +(5, 'Reporter', 4, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :edit_course\n- :close_course\n- :select_course_modules\n- :view_course_journals_for_messages\n- :course_attachments_download\n- :view_course_files\n- :view_homework_attaches\n- :manage_boards\n- :add_messages\n- :edit_own_messages\n- :delete_own_messages\n- :view_calendar\n- :view_code_review\n- :manage_files\n- :view_files\n- :view_gantt\n- :view_issues\n- :add_issues\n- :edit_issues\n- :add_issue_notes\n- :edit_own_issue_notes\n- :save_queries\n- :comment_news\n- :browse_repository\n- :view_wiki_pages\n- :export_wiki_pages\n- :view_wiki_edits\n- :edit_wiki_pages\n- :delete_wiki_pages_attachments\n', 'all'), +(7, 'TeachingAsistant', 6, 1, 0, '---\n- :add_project\n- :edit_project\n- :manage_members\n- :projects_attachments_download\n- :as_teacher\n- :add_course\n- :edit_course\n- :close_course\n- :select_course_modules\n- :view_course_journals_for_messages\n- :course_attachments_download\n- :view_course_files\n- :view_homework_attaches\n- :manage_boards\n- :add_messages\n- :edit_own_messages\n- :delete_messages\n- :delete_own_messages\n- :view_calendar\n- :view_documents\n- :manage_files\n- :view_files\n- :view_gantt\n- :view_issues\n- :add_issues\n- :add_issue_notes\n- :save_queries\n- :manage_news\n- :comment_news\n- :browse_repository\n- :view_changesets\n- :view_time_entries\n- :view_wiki_pages\n- :export_wiki_pages\n- :view_wiki_edits\n- :edit_wiki_pages\n- :delete_wiki_pages_attachments\n', 'default'), +(9, 'Teacher', 7, 1, 0, '---\n- :upload_attachments\n- :memos_attachments_download\n- :add_project\n- :edit_project\n- :close_project\n- :select_project_modules\n- :manage_members\n- :manage_versions\n- :add_subprojects\n- :projects_attachments_download\n- :as_teacher\n- :add_course\n- :edit_course\n- :close_course\n- :select_course_modules\n- :view_course_journals_for_messages\n- :course_attachments_download\n- :view_course_files\n- :view_homework_attaches\n- :manage_boards\n- :add_messages\n- :edit_messages\n- :edit_own_messages\n- :delete_messages\n- :delete_own_messages\n- :view_calendar\n- :add_documents\n- :edit_documents\n- :delete_documents\n- :view_documents\n- :manage_files\n- :view_files\n- :view_gantt\n- :manage_categories\n- :view_issues\n- :add_issues\n- :edit_issues\n- :manage_issue_relations\n- :manage_subtasks\n- :set_issues_private\n- :set_own_issues_private\n- :add_issue_notes\n- :edit_own_issue_notes\n- :view_private_notes\n- :set_notes_private\n- :move_issues\n- :delete_issues\n- :manage_public_queries\n- :save_queries\n- :view_issue_watchers\n- :add_issue_watchers\n- :delete_issue_watchers\n- :manage_news\n- :comment_news\n- :manage_repository\n- :browse_repository\n- :view_changesets\n- :commit_access\n- :manage_related_issues\n- :log_time\n- :view_time_entries\n- :edit_time_entries\n- :edit_own_time_entries\n- :manage_project_activities\n- :manage_wiki\n- :rename_wiki_pages\n- :delete_wiki_pages\n- :view_wiki_pages\n- :export_wiki_pages\n- :view_wiki_edits\n- :edit_wiki_pages\n- :delete_wiki_pages_attachments\n- :protect_wiki_pages\n', 'default'), +(10, 'Student', 9, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :as_student\n- :add_course\n- :edit_course\n- :close_course\n- :select_course_modules\n- :view_course_journals_for_messages\n- :course_attachments_download\n- :view_course_files\n- :view_homework_attaches\n- :paret_in_homework\n- :manage_boards\n- :add_messages\n- :edit_own_messages\n- :delete_own_messages\n- :view_calendar\n- :view_documents\n- :manage_files\n- :view_files\n- :view_gantt\n- :view_issues\n- :add_issues\n- :add_issue_notes\n- :save_queries\n- :comment_news\n- :browse_repository\n- :view_changesets\n- :view_time_entries\n- :view_wiki_pages\n- :view_wiki_edits\n', 'default'), +(11, 'orgManager', 8, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :course_attachments_download\n- :view_course_files\n- :add_messages\n- :delete_own_messages\n- :view_calendar\n- :view_documents\n- :view_files\n- :view_gantt\n- :view_issues\n- :save_queries\n- :comment_news\n- :browse_repository\n- :view_changesets\n- :view_time_entries\n- :view_wiki_pages\n- :view_wiki_edits\n', 'default'), +(12, 'orgMember', 10, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :course_attachments_download\n- :view_course_files\n- :add_messages\n- :delete_own_messages\n- :view_calendar\n- :view_documents\n- :view_files\n- :view_gantt\n- :view_issues\n- :save_queries\n- :comment_news\n- :browse_repository\n- :view_changesets\n- :view_time_entries\n- :view_wiki_pages\n- :view_wiki_edits\n', 'default'), +(13, 'ContestManager', 11, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :course_attachments_download\n- :view_course_files\n- :select_contest_modules\n- :quote_project\n- :contest_attachments_download\n- :manage_contestnotifications\n- :notificationcomment_contestnotifications\n- :manage_boards\n- :add_messages\n- :edit_messages\n- :edit_own_messages\n- :delete_messages\n- :delete_own_messages\n- :view_calendar\n- :view_files\n- :view_gantt\n- :view_issues\n- :save_queries\n- :browse_repository\n- :view_changesets\n', 'default'), +(14, 'Judge', 12, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :course_attachments_download\n- :view_course_files\n- :select_contest_modules\n- :quote_project\n- :contest_attachments_download\n- :manage_contestnotifications\n- :notificationcomment_contestnotifications\n- :manage_boards\n- :add_messages\n- :edit_messages\n- :edit_own_messages\n- :delete_own_messages\n- :view_calendar\n- :manage_files\n- :view_files\n- :view_gantt\n- :view_issues\n- :save_queries\n- :browse_repository\n- :view_changesets\n', 'default'), +(15, 'Contestant', 13, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :course_attachments_download\n- :view_course_files\n- :select_contest_modules\n- :quote_project\n- :contest_attachments_download\n- :notificationcomment_contestnotifications\n- :add_messages\n- :edit_own_messages\n- :delete_own_messages\n- :view_calendar\n- :manage_files\n- :view_files\n- :view_gantt\n- :view_issues\n- :save_queries\n- :browse_repository\n- :view_changesets\n', 'default'); +COMMIT; + + +-- ---------------------------- +-- Records of ci_languages +-- ---------------------------- +BEGIN; +INSERT INTO `ci_languages` (`id`, `name`, `content`, `usage_amount`, `created_at`, `updated_at`, `cover_id`) VALUES +(1, 'C', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGdjYwogIGNvbW1hbmRzOgogIC0gLi9jb25maWd1cmUKICAtIG1h\na2UKICAtIG1ha2UgdGVzdA==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(2, 'C++', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGdjYwogIGNvbW1hbmRzOgogIC0gLi9jb25maWd1cmUKICAtIG1h\na2UKICAtIG1ha2UgdGVzdA==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(3, 'Docker', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGRvY2tlcjpkaW5kCiAgdm9sdW1lczoKICAtIG5hbWU6IGRvY2tl\ncnNvY2sKICAgIHBhdGg6IC92YXIvcnVuL2RvY2tlci5zb2NrCiAgICBjb21t\nYW5kczoKICAgIC0gZG9ja2VyIHBzIC1hCgp2b2x1bWVzOgotIG5hbWU6IGRv\nY2tlcnNvY2sKICBob3N0OgogICAgcGF0aDogL3Zhci9ydW4vZG9ja2VyLnNv\nY2s=\n', 0, '2020-10-21 10:14:22', '2020-11-26 01:35:20', 351688), +(4, 'Java', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IG1hdmVuOjMtamRrLTEwCiAgY29tbWFuZHM6CiAgLSBtdm4gaW5z\ndGFsbCAtRHNraXBUZXN0cz10cnVlIC1EbWF2ZW4uamF2YWRvYy5za2lwPXRy\ndWUgLUIgLVYKICAtIG12biB0ZXN0IC1C\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(5, 'R', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHItYmFzZQogIGNvbW1hbmRzOgogIC0gUiAtZSAnaW5zdGFsbC5w\nYWNrYWdlcyhjKCdwYWNrYWdlMScsJ3BhY2thZ2UyJykpJwogIC0gUiBDTUQg\nYnVpbGQgLg==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(6, 'Ruby', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHJ1YnkKICBjb21tYW5kczoKICAtIGJ1bmRsZSBpbnN0YWxsIC0t\nam9icz0zIC0tcmV0cnk9MwogIC0gcmFrZQ==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(7, 'PHP', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiBpbnN0YWxs\nCiAgaW1hZ2U6IGNvbXBvc2VyCiAgY29tbWFuZHM6CiAgLSBjb21wb3NlciBp\nbnN0YWxsCgotIG5hbWU6IHRlc3QKICBpbWFnZTogcGhwOjcKICBjb21tYW5k\nczoKICAtIHZlbmRvci9iaW4vcGhwdW5pdCAtLWNvbmZpZ3VyYXRpb24gY29u\nZmlnLnhtbA==\n', 0, '2020-10-21 10:14:22', '2020-11-26 01:37:04', 351690), +(8, 'Python', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHB5dGhvbgogIGNvbW1hbmRzOgogIC0gcGlwIGluc3RhbGwgLXIg\ncmVxdWlyZW1lbnRzLnR4dAogIC0gcHl0ZXN0\n', 0, '2020-10-21 10:14:22', '2020-11-26 01:40:00', 351693), +(9, 'MySQL', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IG15c3FsCiAgY29tbWFuZHM6CiAgLSBzbGVlcCAxNQogIC0gbXlz\ncWwgLXUgcm9vdCAtaCBkYXRhYmFzZSAtLWV4ZWN1dGU9J1NFTEVDVCBWRVJT\nSU9OKCk7JwoKc2VydmljZXM6Ci0gbmFtZTogZGF0YWJhc2UKICBpbWFnZTog\nbXlzcWwKICBlbnZpcm9ubWVudDoKICAgIE1ZU1FMX0FMTE9XX0VNUFRZX1BB\nU1NXT1JEOiAneWVzJwogICAgTVlTUUxfREFUQUJBU0U6IHRlc3Q=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(10, 'MongoDB', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiBwaW5nCiAg\naW1hZ2U6IG1vbmdvOjQKICBjb21tYW5kczoKICAtIHNsZWVwIDUKICAtIG1v\nbmdvIC0taG9zdCBtb25nbyAtLWV2YWwgJ2RiLnZlcnNpb24oKScKCnNlcnZp\nY2VzOgotIG5hbWU6IG1vbmdvCiAgaW1hZ2U6IG1vbmdvOjQKICBjb21tYW5k\nOiBbIC0tc21hbGxmaWxlcyBd\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(11, 'Clojure', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGNsb2p1cmUKICBjb21tYW5kczoKICAtIGxlaW4gdGVzdA==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(12, 'CouchDB', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGNvdWNoZGI6Mi4yCiAgY29tbWFuZHM6CiAgLSBzbGVlcCAxNQog\nIC0gY3VybCBodHRwOi8vZGF0YWJhc2U6NTk4NAoKc2VydmljZXM6Ci0gbmFt\nZTogZGF0YWJhc2UKICBpbWFnZTogY291Y2hkYjoyLjI=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(13, 'Crystal', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGNyeXN0YWxsYW5nL2NyeXN0YWwKICBjb21tYW5kczoKICAtIHNo\nYXJkcyBpbnN0YWxsCiAgLSBjcnlzdGFsIHNwZWMuMg==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(14, 'D', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGRsYW5ndWFnZS9kbWQKICBjb21tYW5kczoKICAtIGR1YiB0ZXN0\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(15, 'Dart', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGdvb2dsZS9kYXJ0CiAgY29tbWFuZHM6CiAgLSBwdWIgZ2V0CiAg\nLSBwdWIgcnVuIHRlc3Q=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(16, 'Docker (dind)', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGRvY2tlcjpkaW5kCiAgdm9sdW1lczoKICAtIG5hbWU6IGRvY2tl\ncnNvY2sKICAgIHBhdGg6IC92YXIvcnVuCiAgICBjb21tYW5kczoKICAgIC0g\nc2xlZXAgNSAjIGdpdmUgZG9ja2VyIGVub3VnaCB0aW1lIHRvIHN0YXJ0CiAg\nICAtIGRvY2tlciBwcyAtYQoKc2VydmljZXM6Ci0gbmFtZTogZG9ja2VyCiAg\naW1hZ2U6IGRvY2tlcjpkaW5kCiAgcHJpdmlsZWdlZDogdHJ1ZQogIHZvbHVt\nZXM6CiAgLSBuYW1lOiBkb2NrZXJzb2NrCiAgICBwYXRoOiAvdmFyL3J1bgoK\ndm9sdW1lczoKLSBuYW1lOiBkb2NrZXJzb2NrCiAgdGVtcDoge30=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(17, 'Elasticsearch', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGFscGluZTozLjgKICBjb21tYW5kczoKICAtIGFwayBhZGQgY3Vy\nbAogIC0gc2xlZXAgNDUKICAtIGN1cmwgaHR0cDovL2RhdGFiYXNlOjkyMDAK\nCnNlcnZpY2VzOgotIG5hbWU6IGRhdGFiYXNlCiAgaW1hZ2U6IGVsYXN0aWNz\nZWFyY2g6NS1hbHBpbmU=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(18, 'Elixir', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGVsaXhpcjoxLjUKICBjb21tYW5kczoKICAtIG1peCBsb2NhbC5y\nZWJhciAtLWZvcmNlCiAgLSBtaXggbG9jYWwuaGV4IC0tZm9yY2UKICAtIG1p\neCBkZXBzLmdldAogIC0gbWl4IHRlc3Q=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(19, 'Erlang', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGVybGFuZzoyMQogIGNvbW1hbmRzOgogIC0gcmViYXIgZ2V0LWRl\ncHMKICAtIHJlYmFyIGNvbXBpbGUKICAtIHJlYmFyIHNraXBfZGVwcz10cnVl\nIGV1bml0\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(20, '20.Go (with Gopath)', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0Cgp3b3Jrc3BhY2U6CiAgYmFzZTogL2dv\nCiAgcGF0aDogc3JjL2hlbGxvLXdvcmxkCgpzdGVwczoKLSBuYW1lOiB0ZXN0\nCiAgaW1hZ2U6IGdvbGFuZwogIGNvbW1hbmRzOgogIC0gZ28gZ2V0CiAgLSBn\nbyB0ZXN0\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(21, '21.Go (with Modules)', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGdvbGFuZwogIGNvbW1hbmRzOgogIC0gZ28gdGVzdAogIC0gZ28g\nYnVpbGQ=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(22, 'Gradle', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGdyYWRsZTpqZGsxMAogIGNvbW1hbmRzOgogIC0gZ3JhZGxlIGFz\nc2VtYmxlCiAgLSBncmFkbGUgY2hlY2s=\n', 0, '2020-10-21 10:14:22', '2020-11-26 01:36:17', 351689), +(23, 'Groovy', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGdyYWRsZToyLjUtamRrOAogIGNvbW1hbmRzOgogIC0gLi9ncmFk\nbGV3IGFzc2VtYmxlCiAgLSAuL2dyYWRsZXcgY2hlY2s=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(24, 'Haskell', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGhhc2tlbGwKICBjb21tYW5kczoKICAtIGNhYmFsIGluc3RhbGwg\nLS1vbmx5LWRlcGVuZGVuY2llcyAtLWVuYWJsZS10ZXN0cwogIC0gY2FiYWwg\nY29uZmlndXJlIC0tZW5hYmxlLXRlc3RzCiAgLSBjYWJhbCBidWlsZAogIC0g\nY2FiYWwgdGVzdA==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(25, 'Haxe', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGhheGUKICBjb21tYW5kczoKICAtIGhheGVsaWIgaW5zdGFsbCBi\ndWlsZC5oeG1sCiAgLSBoYXhlIGJ1aWxkLmh4bWw=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(26, 'MariaDB', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IG1hcmlhZGIKICBjb21tYW5kczoKICAtIHNsZWVwIDE1CiAgLSBt\neXNxbCAtdSByb290IC1oIGRhdGFiYXNlIC0tZXhlY3V0ZT0nU0VMRUNUIFZF\nUlNJT04oKTsnCgpzZXJ2aWNlczoKLSBuYW1lOiBkYXRhYmFzZQogIGltYWdl\nOiBtYXJpYWRiCiAgZW52aXJvbm1lbnQ6CiAgICBNWVNRTF9BTExPV19FTVBU\nWV9QQVNTV09SRDogJ3llcycKICAgIE1ZU1FMX0RBVEFCQVNFOiB0ZXN0\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(27, 'Maven', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IG1hdmVuOjMtamRrLTEwCiAgY29tbWFuZHM6CiAgLSBtdm4gaW5z\ndGFsbCAtRHNraXBUZXN0cz10cnVlIC1EbWF2ZW4uamF2YWRvYy5za2lwPXRy\ndWUgLUIgLVYKICAtIG12biB0ZXN0IC1C\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(28, 'Memcached', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHVidW50dQogIGNvbW1hbmRzOgogIC0gYXB0LWdldCB1cGRhdGUg\nLXFxCiAgLSBhcHQtZ2V0IGluc3RhbGwgLXkgLXFxIHRlbG5ldCA+IC9kZXYv\nbnVsbAogIC0gKHNsZWVwIDE7IGVjaG8gJ3N0YXRzJzsgc2xlZXAgMjsgZWNo\nbyAncXVpdCc7KSB8IHRlbG5ldCBjYWNoZSAxMTIxMSB8fCB0cnVlCgpzZXJ2\naWNlczoKLSBuYW1lOiBjYWNoZQogIGltYWdlOiBtZW1jYWNoZWQ6YWxwaW5l\nCiAgY29tbWFuZDogWyAtdnYgXQ==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(29, 'Nats', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHJ1Ynk6MgogIGNvbW1hbmRzOgogIC0gZ2VtIGluc3RhbGwgbmF0\ncwogIC0gbmF0cy1wdWIgLXMgdGNwOi8vbmF0czo0MjIyIGdyZWV0aW5nICdo\nZWxsbycKICAtIG5hdHMtcHViIC1zIHRjcDovL25hdHM6NDIyMiBncmVldGlu\nZyAnd29ybGQnCgpzZXJ2aWNlczoKLSBuYW1lOiBuYXRzCiAgaW1hZ2U6IG5h\ndHM6MS4zLjA=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(30, 'Node', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IG5vZGUKICBjb21tYW5kczoKICAtIG5wbSBpbnN0YWxsCiAgLSBu\ncG0gdGVzdA==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(31, 'Perl', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHBlcmwKICBjb21tYW5kczoKICAtIGNwYW5tIC0tcXVpZXQgLS1p\nbnN0YWxsZGVwcyAtLW5vdGVzdCAuCiAgLSBwZXJsIEJ1aWxkLlBMCiAgLSAu\nL0J1aWxkIHRlc3Q=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(32, 'Postgres', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHBvc3RncmVzOjktYWxwaW5lCiAgY29tbWFuZHM6CiAgLSBwc3Fs\nIC1VIHBvc3RncmVzIC1kIHRlc3QgLWggZGF0YWJhc2UKCnNlcnZpY2VzOgot\nIG5hbWU6IGRhdGFiYXNlCiAgaW1hZ2U6IHBvc3RncmVzOjktYWxwaW5lCiAg\nZW52aXJvbm1lbnQ6CiAgICBQT1NUR1JFU19VU0VSOiBwb3N0Z3JlcwogICAg\nUE9TVEdSRVNfREI6IHRlc3Q=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(33, 'Redis', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHJlZGlzCiAgY29tbWFuZHM6CiAgLSBzbGVlcCA1CiAgLSByZWRp\ncy1jbGkgLWggcmVkaXMgcGluZwogIC0gcmVkaXMtY2xpIC1oIHJlZGlzIHNl\ndCBGT08gYmFyCiAgLSByZWRpcy1jbGkgLWggcmVkaXMgZ2V0IEZPTwoKc2Vy\ndmljZXM6Ci0gbmFtZTogcmVkaXMKICBpbWFnZTogcmVkaXM=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(34, 'RethinkDB', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IG5vZGU6OQogIGNvbW1hbmRzOgogIC0gbnBtIGluc3RhbGwgLXMg\nLWcgcmVjbGkKICAtIHJlY2xpIC1oIGRhdGFiYXNlIC1qICdyLmRiKCdyZXRo\naW5rZGInKS50YWJsZSgnc3RhdHMnKScKCnNlcnZpY2VzOgotIG5hbWU6IGRh\ndGFiYXNlCiAgaW1hZ2U6IHJldGhpbmtkYjoyCiAgY29tbWFuZDogWyByZXRo\naW5rZGIsIC0tYmluZCwgYWxsIF0=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(35, 'Rust', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHJ1c3Q6MS4zMAogIGNvbW1hbmRzOgogIC0gY2FyZ28gYnVpbGQg\nLS12ZXJib3NlIC0tYWxsCiAgLSBjYXJnbyB0ZXN0IC0tdmVyYm9zZSAtLWFs\nbA==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(36, 'Swift', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHN3aWZ0OjQKICBjb21tYW5kczoKICAtIHN3aWZ0IGJ1aWxkCiAg\nLSBzd2lmdCB0ZXN0\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), +(37, 'Vault', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHZhdWx0OjEuMC4wLWJldGEyCiAgZW52aXJvbm1lbnQ6CiAgICBW\nQVVMVF9BRERSOiBodHRwOi8vdmF1bHQ6ODIwMAogICAgVkFVTFRfVE9LRU46\nIGR1bW15CiBjb21tYW5kczoKIC0gc2xlZXAgNQogLSB2YXVsdCBrdiBwdXQg\nc2VjcmV0L215LXNlY3JldCBteS12YWx1ZT1zM2NyM3QKIC0gdmF1bHQga3Yg\nZ2V0IHNlY3JldC9teS1zZWNyZXQKCnNlcnZpY2VzOgotIG5hbWU6IHZhdWx0\nCiAgaW1hZ2U6IHZhdWx0OjEuMC4wLWJldGEyCiAgZW52aXJvbm1lbnQ6CiAg\nICBWQVVMVF9ERVZfUk9PVF9UT0tFTl9JRDogZHVtbXk=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL); +COMMIT; + +-- ---------------------------- +-- Records of ci_templates +-- ---------------------------- +BEGIN; +INSERT INTO `ci_templates` (`id`, `template_name`, `stage_type`, `category`, `content`, `created_at`, `updated_at`, `parent_category`, `login`) VALUES +(2, 'linux/amd64', 'init', '初始化', 'kind: pipeline\r\ntype: docker\r\nname: {name}\r\nplatform:\r\n os: linux\r\n arch: amd64', '2021-01-12 02:44:23', '2021-02-02 10:51:36', '初始化', 'admin'), +(3, 'linux/arm64', 'init', '初始化', 'kind: pipeline\r\ntype: docker\r\nname: {name}\r\nplatform:\r\n os: linux\r\n arch: arm64', '2021-01-12 02:45:17', '2021-02-02 10:51:47', '初始化', 'admin'), +(4, 'maven', 'build', 'Java', '- name: maven\r\n image: maven:3-jdk-10\r\n commands:\r\n - mvn install -DskipTests=true', '2021-01-12 02:53:29', '2021-01-12 02:53:29', '编译构建', 'admin'), +(5, 'maven单元测试', 'customize', 'Java', '- name: maven\r\n image: maven:3-jdk-10\r\n commands:\r\n - mvn test', '2021-01-12 02:53:29', '2021-01-12 02:53:29', '单元测试', 'admin'), +(6, 'golang单元测试', 'customize', 'Golang', '- name: golang单元测试\r\n image: golang\r\n commands:\r\n - go test', '2021-01-12 03:03:35', '2021-01-12 03:03:35', '单元测试', 'admin'), +(8, 'gradle', 'build', 'Java', '- name: gradle\r\n image: gradle:jdk10\r\n commands:\r\n - gradle build -x test', '2021-01-12 03:05:33', '2021-01-12 03:05:33', '编译构建', 'admin'), +(9, 'gradle单元测试', 'customize', 'Java', '- name: gradle\r\n image: gradle:jdk10\r\n commands:\r\n - gradle test', '2021-01-12 03:05:33', '2021-01-12 03:05:33', '单元测试', 'admin'), +(10, '远程主机部署', 'deploy', '部署', '# 需要将软件包与部署脚本提前上传到远程主机(见文件上传模板)\r\n# host、username、password可在参数管理中配置\r\n- name: 远程主机部署\r\n image: appleboy/drone-ssh\r\n settings:\r\n host: \r\n from_secret: ip\r\n username: \r\n from_secret: name\r\n password: \r\n from_secret: pwd\r\n port: 22\r\n script:\r\n - chmod +x /home/deploy.sh\r\n - ./home/deploy.sh', '2021-01-12 03:32:46', '2021-03-05 06:22:02', '部署', 'admin'), +(11, '远程命令', 'customize', '其他', '# host、username、password可在参数管理中配置\r\n- name: 远程命令\r\n image: appleboy/drone-ssh\r\n settings:\r\n host: \r\n from_secret: ip\r\n username: \r\n from_secret: name\r\n password: \r\n from_secret: pwd\r\n port: 22\r\n script:\r\n - echo ''hello world!''', '2021-01-12 03:40:38', '2021-03-05 06:19:44', '其他', 'admin'), +(12, '上传文件', 'customize', '其他', '# 本模板示例为上传软件包和部署脚本到home目录\r\n# host、username、password可在参数管理中配置\r\n- name: 上传文件\r\n image: appleboy/drone-scp\r\n settings:\r\n host: \r\n from_secret: ip\r\n username: \r\n from_secret: name\r\n password: \r\n from_secret: pwd\r\n port: 22\r\n target: /home\r\n source: \r\n - target/*.jar\r\n - deploy.sh', '2021-01-12 03:40:55', '2021-03-05 06:22:22', '其他', 'admin'), +(17, 'make-c', 'build', 'C', '- name: 编译\r\n image: gcc\r\n commands:\r\n - ./configure\r\n - make', '2021-01-15 01:19:38', '2021-02-02 10:52:15', '编译构建', 'admin'), +(19, 'make-c++', 'build', 'C++', '- name: 编译构建\r\n image: gcc\r\n commands:\r\n - ./configure\r\n - make', '2021-01-15 01:21:05', '2021-01-15 01:21:05', '编译构建', 'admin'), +(20, 'python', 'build', 'Python', '- name: 编译构建\r\n image: python\r\n commands:\r\n - pip install -r requirements.txt', '2021-01-15 01:22:36', '2021-01-15 01:22:36', '编译构建', 'admin'), +(21, 'Docker', 'build', 'Docker', '# 构建Docker镜像并推送到仓库\r\n# 定义镜像Hub路径以及账号密码\r\n- name: Docker镜像构建\r\n image: plugins/docker\r\n settings:\r\n username: username\r\n password: pwd\r\n repo: repoUrl\r\n tags: latest', '2021-01-15 01:23:16', '2021-02-03 03:40:49', '编译构建', 'admin'), +(22, '空白模板', 'customize', 'customize', '', '2021-01-15 02:53:02', '2021-01-15 02:53:02', '其他', 'admin'), +(25, 'Go (with Gopath)', 'build', 'Go', '- name: golang\r\n image: golang\r\n commands:\r\n - go get\r\n - go test', '2021-02-03 00:57:32', '2021-02-03 03:36:15', '编译构建', 'admin'), +(26, 'PHP', 'build', 'PHP', '- name: install\r\n image: composer\r\n commands:\r\n - composer install', '2021-02-03 00:59:15', '2021-02-03 00:59:15', '编译构建', 'admin'), +(27, 'Ruby', 'build', 'Ruby', '- name: ruby\r\n image: ruby\r\n commands:\r\n - bundle install --jobs=3 --retry=3\r\n - rake', '2021-02-03 00:59:52', '2021-02-03 00:59:52', '编译构建', 'admin'), +(29, 'Go (with Modules)', 'build', 'Go', '- name: test\r\n image: golang\r\n commands:\r\n - go test\r\n - go build', '2021-02-03 03:35:45', '2021-02-03 03:35:45', '编译构建', 'admin'), +(30, 'Node', 'build', 'Node', '- name: Node编译\r\n image: node\r\n commands:\r\n - npm install\r\n - npm test', '2021-02-03 03:37:31', '2021-02-03 03:37:31', '编译构建', 'admin'), +(31, 'Perl ', 'build', 'Perl', '- name: perl\r\n image: perl\r\n commands:\r\n - cpanm --quiet --installdeps --notest .\r\n - perl Build.PL\r\n - ./Build test', '2021-02-03 03:38:06', '2021-02-03 03:38:06', '编译构建', 'admin'), +(32, 'Rust ', 'build', 'Rust', '- name: rust\r\n image: rust:1.30\r\n commands:\r\n - cargo build --verbose --all\r\n - cargo test --verbose --all', '2021-02-03 03:38:37', '2021-02-03 03:38:37', '编译构建', 'admin'), +(33, 'test', 'init', '初始化', 'qqqq', '2021-02-04 09:02:42', '2021-02-04 09:02:42', '初始化', 'admin'); +COMMIT; diff --git a/db/structure.sql b/db/structure.sql index 26208e576..3b1b437eb 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -3424,98 +3424,3 @@ COMMIT; BEGIN; INSERT INTO `laboratory_settings` VALUES (1, 1, '{\"name\":\"EduCoder\",\"navbar\":[{\"name\":\"实践课程\",\"link\":\"/paths\",\"hidden\":false},{\"name\":\"翻转课堂\",\"link\":\"/courses\",\"hidden\":false},{\"name\":\"实现项目\",\"link\":\"/shixuns\",\"hidden\":false},{\"name\":\"在线竞赛\",\"link\":\"/competitions\",\"hidden\":false},{\"name\":\"教学案例\",\"link\":\"/moop_cases\",\"hidden\":false},{\"name\":\"交流问答\",\"link\":\"/forums\",\"hidden\":false}],\"footer\":\"\\n\\u003cp class=\\\"footer_con-p inline lineh-30 font-14\\\"\\u003e\\n \\u003cspan class=\\\"font-18 fl\\\"\\u003e©\\u003c/span\\u003e\\u0026nbsp;2019\\u0026nbsp;EduCoder\\n \\u003ca target=\\\"_blank\\\" href=\\\"http://beian.miit.gov.cn/\\\" class=\\\"ml15 mr15\\\" style=\\\"color: rgb(136, 136, 136);\\\"\\u003e湘ICP备17009477号\\u003c/a\\u003e\\n \\u003ca target=\\\"_blank\\\" href=\\\"http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=43019002000962\\\" class=\\\"mr15\\\" style=\\\"color: rgb(136, 136, 136);\\\"\\u003e\\n \\u003cimg class=\\\"vertical4\\\" src=\\\"https://ali-cdn.educoder.net/react/build/static/media/beian.d0289dc0.png\\\"\\u003e湘公网安备43019002000962号\\n \\u003c/a\\u003e\\n \\u003ca href=\\\"https://team.trustie.net\\\" target=\\\"_blank\\\" style=\\\"color: rgb(136, 136, 136);\\\"\\u003eTrustie\\u003c/a\\u003e\\n \\u0026nbsp;\\u0026nbsp;\\u0026nbsp;\\u0026amp;\\u0026nbsp;\\u0026nbsp;\\u0026nbsp;IntelliDE inside.\\n \\u003cspan class=\\\"mr15\\\"\\u003e版权所有 湖南智擎科技有限公司\\u003c/span\\u003e\\u003c/p\\u003e\\n \"}'); COMMIT; - --- ---------------------------- --- Records of roles --- ---------------------------- -BEGIN; -INSERT INTO `roles` (`id`, `name`, `position`, `assignable`, `builtin`, `permissions`, `issues_visibility`) VALUES -(1, 'Non member', 1, 1, 1, '---\n- :upload_attachments\n- :memos_attachments_download\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :course_attachments_download\n- :view_course_files\n- :add_messages\n- :delete_own_messages\n- :view_calendar\n- :view_documents\n- :view_files\n- :view_gantt\n- :view_issues\n- :save_queries\n- :comment_news\n- :browse_repository\n- :view_changesets\n- :view_time_entries\n- :view_wiki_pages\n- :view_wiki_edits\n', 'default'), -(2, 'Anonymous', 2, 1, 2, '---\n- :memos_attachments_download\n- :view_course_files\n- :view_calendar\n- :view_documents\n- :view_files\n- :view_gantt\n- :view_issues\n- :browse_repository\n- :view_changesets\n- :view_time_entries\n- :view_wiki_pages\n- :view_wiki_edits\n', 'default'), -(3, 'Manager', 3, 1, 0, '---\n- :add_project\n- :edit_project\n- :close_project\n- :select_project_modules\n- :manage_members\n- :manage_versions\n- :add_subprojects\n- :is_manager\n- :projects_attachments_download\n- :as_teacher\n- :add_course\n- :edit_course\n- :close_course\n- :select_course_modules\n- :view_course_journals_for_messages\n- :course_attachments_download\n- :view_course_files\n- :view_homework_attaches\n- :quote_project\n- :manage_boards\n- :add_messages\n- :edit_messages\n- :edit_own_messages\n- :delete_messages\n- :delete_own_messages\n- :view_calendar\n- :view_code_review\n- :add_code_review\n- :edit_code_review\n- :delete_code_review\n- :assign_code_review\n- :code_review_setting\n- :add_documents\n- :edit_documents\n- :delete_documents\n- :view_documents\n- :manage_files\n- :view_files\n- :view_gantt\n- :manage_categories\n- :view_issues\n- :add_issues\n- :edit_issues\n- :manage_issue_relations\n- :manage_subtasks\n- :set_issues_private\n- :set_own_issues_private\n- :add_issue_notes\n- :edit_issue_notes\n- :edit_own_issue_notes\n- :view_private_notes\n- :set_notes_private\n- :move_issues\n- :delete_issues\n- :manage_public_queries\n- :save_queries\n- :view_issue_watchers\n- :add_issue_watchers\n- :delete_issue_watchers\n- :manage_news\n- :comment_news\n- :manage_repository\n- :browse_repository\n- :view_changesets\n- :commit_access\n- :manage_related_issues\n- :log_time\n- :view_time_entries\n- :edit_time_entries\n- :edit_own_time_entries\n- :manage_project_activities\n- :manage_wiki\n- :rename_wiki_pages\n- :delete_wiki_pages\n- :view_wiki_pages\n- :export_wiki_pages\n- :view_wiki_edits\n- :edit_wiki_pages\n- :delete_wiki_pages_attachments\n- :protect_wiki_pages\n', 'all'), -(4, 'Developer', 5, 1, 0, '---\n- :add_project\n- :manage_versions\n- :projects_attachments_download\n- :add_course\n- :edit_course\n- :close_course\n- :select_course_modules\n- :view_course_journals_for_messages\n- :course_attachments_download\n- :view_course_files\n- :view_homework_attaches\n- :paret_in_homework\n- :select_contest_modules\n- :quote_project\n- :contest_attachments_download\n- :manage_contestnotifications\n- :notificationcomment_contestnotifications\n- :manage_boards\n- :add_messages\n- :edit_own_messages\n- :delete_own_messages\n- :view_calendar\n- :manage_files\n- :view_files\n- :view_gantt\n- :manage_categories\n- :view_issues\n- :add_issues\n- :edit_issues\n- :manage_issue_relations\n- :manage_subtasks\n- :set_issues_private\n- :set_own_issues_private\n- :add_issue_notes\n- :edit_issue_notes\n- :edit_own_issue_notes\n- :view_private_notes\n- :set_notes_private\n- :move_issues\n- :delete_issues\n- :manage_public_queries\n- :save_queries\n- :view_issue_watchers\n- :add_issue_watchers\n- :delete_issue_watchers\n- :manage_repository\n- :browse_repository\n- :view_changesets\n- :commit_access\n- :manage_related_issues\n', 'all'), -(5, 'Reporter', 4, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :edit_course\n- :close_course\n- :select_course_modules\n- :view_course_journals_for_messages\n- :course_attachments_download\n- :view_course_files\n- :view_homework_attaches\n- :manage_boards\n- :add_messages\n- :edit_own_messages\n- :delete_own_messages\n- :view_calendar\n- :view_code_review\n- :manage_files\n- :view_files\n- :view_gantt\n- :view_issues\n- :add_issues\n- :edit_issues\n- :add_issue_notes\n- :edit_own_issue_notes\n- :save_queries\n- :comment_news\n- :browse_repository\n- :view_wiki_pages\n- :export_wiki_pages\n- :view_wiki_edits\n- :edit_wiki_pages\n- :delete_wiki_pages_attachments\n', 'all'), -(7, 'TeachingAsistant', 6, 1, 0, '---\n- :add_project\n- :edit_project\n- :manage_members\n- :projects_attachments_download\n- :as_teacher\n- :add_course\n- :edit_course\n- :close_course\n- :select_course_modules\n- :view_course_journals_for_messages\n- :course_attachments_download\n- :view_course_files\n- :view_homework_attaches\n- :manage_boards\n- :add_messages\n- :edit_own_messages\n- :delete_messages\n- :delete_own_messages\n- :view_calendar\n- :view_documents\n- :manage_files\n- :view_files\n- :view_gantt\n- :view_issues\n- :add_issues\n- :add_issue_notes\n- :save_queries\n- :manage_news\n- :comment_news\n- :browse_repository\n- :view_changesets\n- :view_time_entries\n- :view_wiki_pages\n- :export_wiki_pages\n- :view_wiki_edits\n- :edit_wiki_pages\n- :delete_wiki_pages_attachments\n', 'default'), -(9, 'Teacher', 7, 1, 0, '---\n- :upload_attachments\n- :memos_attachments_download\n- :add_project\n- :edit_project\n- :close_project\n- :select_project_modules\n- :manage_members\n- :manage_versions\n- :add_subprojects\n- :projects_attachments_download\n- :as_teacher\n- :add_course\n- :edit_course\n- :close_course\n- :select_course_modules\n- :view_course_journals_for_messages\n- :course_attachments_download\n- :view_course_files\n- :view_homework_attaches\n- :manage_boards\n- :add_messages\n- :edit_messages\n- :edit_own_messages\n- :delete_messages\n- :delete_own_messages\n- :view_calendar\n- :add_documents\n- :edit_documents\n- :delete_documents\n- :view_documents\n- :manage_files\n- :view_files\n- :view_gantt\n- :manage_categories\n- :view_issues\n- :add_issues\n- :edit_issues\n- :manage_issue_relations\n- :manage_subtasks\n- :set_issues_private\n- :set_own_issues_private\n- :add_issue_notes\n- :edit_own_issue_notes\n- :view_private_notes\n- :set_notes_private\n- :move_issues\n- :delete_issues\n- :manage_public_queries\n- :save_queries\n- :view_issue_watchers\n- :add_issue_watchers\n- :delete_issue_watchers\n- :manage_news\n- :comment_news\n- :manage_repository\n- :browse_repository\n- :view_changesets\n- :commit_access\n- :manage_related_issues\n- :log_time\n- :view_time_entries\n- :edit_time_entries\n- :edit_own_time_entries\n- :manage_project_activities\n- :manage_wiki\n- :rename_wiki_pages\n- :delete_wiki_pages\n- :view_wiki_pages\n- :export_wiki_pages\n- :view_wiki_edits\n- :edit_wiki_pages\n- :delete_wiki_pages_attachments\n- :protect_wiki_pages\n', 'default'), -(10, 'Student', 9, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :as_student\n- :add_course\n- :edit_course\n- :close_course\n- :select_course_modules\n- :view_course_journals_for_messages\n- :course_attachments_download\n- :view_course_files\n- :view_homework_attaches\n- :paret_in_homework\n- :manage_boards\n- :add_messages\n- :edit_own_messages\n- :delete_own_messages\n- :view_calendar\n- :view_documents\n- :manage_files\n- :view_files\n- :view_gantt\n- :view_issues\n- :add_issues\n- :add_issue_notes\n- :save_queries\n- :comment_news\n- :browse_repository\n- :view_changesets\n- :view_time_entries\n- :view_wiki_pages\n- :view_wiki_edits\n', 'default'), -(11, 'orgManager', 8, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :course_attachments_download\n- :view_course_files\n- :add_messages\n- :delete_own_messages\n- :view_calendar\n- :view_documents\n- :view_files\n- :view_gantt\n- :view_issues\n- :save_queries\n- :comment_news\n- :browse_repository\n- :view_changesets\n- :view_time_entries\n- :view_wiki_pages\n- :view_wiki_edits\n', 'default'), -(12, 'orgMember', 10, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :course_attachments_download\n- :view_course_files\n- :add_messages\n- :delete_own_messages\n- :view_calendar\n- :view_documents\n- :view_files\n- :view_gantt\n- :view_issues\n- :save_queries\n- :comment_news\n- :browse_repository\n- :view_changesets\n- :view_time_entries\n- :view_wiki_pages\n- :view_wiki_edits\n', 'default'), -(13, 'ContestManager', 11, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :course_attachments_download\n- :view_course_files\n- :select_contest_modules\n- :quote_project\n- :contest_attachments_download\n- :manage_contestnotifications\n- :notificationcomment_contestnotifications\n- :manage_boards\n- :add_messages\n- :edit_messages\n- :edit_own_messages\n- :delete_messages\n- :delete_own_messages\n- :view_calendar\n- :view_files\n- :view_gantt\n- :view_issues\n- :save_queries\n- :browse_repository\n- :view_changesets\n', 'default'), -(14, 'Judge', 12, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :course_attachments_download\n- :view_course_files\n- :select_contest_modules\n- :quote_project\n- :contest_attachments_download\n- :manage_contestnotifications\n- :notificationcomment_contestnotifications\n- :manage_boards\n- :add_messages\n- :edit_messages\n- :edit_own_messages\n- :delete_own_messages\n- :view_calendar\n- :manage_files\n- :view_files\n- :view_gantt\n- :view_issues\n- :save_queries\n- :browse_repository\n- :view_changesets\n', 'default'), -(15, 'Contestant', 13, 1, 0, '---\n- :add_project\n- :projects_attachments_download\n- :add_course\n- :course_attachments_download\n- :view_course_files\n- :select_contest_modules\n- :quote_project\n- :contest_attachments_download\n- :notificationcomment_contestnotifications\n- :add_messages\n- :edit_own_messages\n- :delete_own_messages\n- :view_calendar\n- :manage_files\n- :view_files\n- :view_gantt\n- :view_issues\n- :save_queries\n- :browse_repository\n- :view_changesets\n', 'default'); -COMMIT; - - --- ---------------------------- --- Records of ci_languages --- ---------------------------- -BEGIN; -INSERT INTO `ci_languages` (`id`, `name`, `content`, `usage_amount`, `created_at`, `updated_at`, `cover_id`) VALUES -(1, 'C', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGdjYwogIGNvbW1hbmRzOgogIC0gLi9jb25maWd1cmUKICAtIG1h\na2UKICAtIG1ha2UgdGVzdA==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(2, 'C++', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGdjYwogIGNvbW1hbmRzOgogIC0gLi9jb25maWd1cmUKICAtIG1h\na2UKICAtIG1ha2UgdGVzdA==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(3, 'Docker', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGRvY2tlcjpkaW5kCiAgdm9sdW1lczoKICAtIG5hbWU6IGRvY2tl\ncnNvY2sKICAgIHBhdGg6IC92YXIvcnVuL2RvY2tlci5zb2NrCiAgICBjb21t\nYW5kczoKICAgIC0gZG9ja2VyIHBzIC1hCgp2b2x1bWVzOgotIG5hbWU6IGRv\nY2tlcnNvY2sKICBob3N0OgogICAgcGF0aDogL3Zhci9ydW4vZG9ja2VyLnNv\nY2s=\n', 0, '2020-10-21 10:14:22', '2020-11-26 01:35:20', 351688), -(4, 'Java', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IG1hdmVuOjMtamRrLTEwCiAgY29tbWFuZHM6CiAgLSBtdm4gaW5z\ndGFsbCAtRHNraXBUZXN0cz10cnVlIC1EbWF2ZW4uamF2YWRvYy5za2lwPXRy\ndWUgLUIgLVYKICAtIG12biB0ZXN0IC1C\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(5, 'R', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHItYmFzZQogIGNvbW1hbmRzOgogIC0gUiAtZSAnaW5zdGFsbC5w\nYWNrYWdlcyhjKCdwYWNrYWdlMScsJ3BhY2thZ2UyJykpJwogIC0gUiBDTUQg\nYnVpbGQgLg==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(6, 'Ruby', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHJ1YnkKICBjb21tYW5kczoKICAtIGJ1bmRsZSBpbnN0YWxsIC0t\nam9icz0zIC0tcmV0cnk9MwogIC0gcmFrZQ==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(7, 'PHP', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiBpbnN0YWxs\nCiAgaW1hZ2U6IGNvbXBvc2VyCiAgY29tbWFuZHM6CiAgLSBjb21wb3NlciBp\nbnN0YWxsCgotIG5hbWU6IHRlc3QKICBpbWFnZTogcGhwOjcKICBjb21tYW5k\nczoKICAtIHZlbmRvci9iaW4vcGhwdW5pdCAtLWNvbmZpZ3VyYXRpb24gY29u\nZmlnLnhtbA==\n', 0, '2020-10-21 10:14:22', '2020-11-26 01:37:04', 351690), -(8, 'Python', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHB5dGhvbgogIGNvbW1hbmRzOgogIC0gcGlwIGluc3RhbGwgLXIg\ncmVxdWlyZW1lbnRzLnR4dAogIC0gcHl0ZXN0\n', 0, '2020-10-21 10:14:22', '2020-11-26 01:40:00', 351693), -(9, 'MySQL', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IG15c3FsCiAgY29tbWFuZHM6CiAgLSBzbGVlcCAxNQogIC0gbXlz\ncWwgLXUgcm9vdCAtaCBkYXRhYmFzZSAtLWV4ZWN1dGU9J1NFTEVDVCBWRVJT\nSU9OKCk7JwoKc2VydmljZXM6Ci0gbmFtZTogZGF0YWJhc2UKICBpbWFnZTog\nbXlzcWwKICBlbnZpcm9ubWVudDoKICAgIE1ZU1FMX0FMTE9XX0VNUFRZX1BB\nU1NXT1JEOiAneWVzJwogICAgTVlTUUxfREFUQUJBU0U6IHRlc3Q=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(10, 'MongoDB', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiBwaW5nCiAg\naW1hZ2U6IG1vbmdvOjQKICBjb21tYW5kczoKICAtIHNsZWVwIDUKICAtIG1v\nbmdvIC0taG9zdCBtb25nbyAtLWV2YWwgJ2RiLnZlcnNpb24oKScKCnNlcnZp\nY2VzOgotIG5hbWU6IG1vbmdvCiAgaW1hZ2U6IG1vbmdvOjQKICBjb21tYW5k\nOiBbIC0tc21hbGxmaWxlcyBd\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(11, 'Clojure', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGNsb2p1cmUKICBjb21tYW5kczoKICAtIGxlaW4gdGVzdA==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(12, 'CouchDB', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGNvdWNoZGI6Mi4yCiAgY29tbWFuZHM6CiAgLSBzbGVlcCAxNQog\nIC0gY3VybCBodHRwOi8vZGF0YWJhc2U6NTk4NAoKc2VydmljZXM6Ci0gbmFt\nZTogZGF0YWJhc2UKICBpbWFnZTogY291Y2hkYjoyLjI=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(13, 'Crystal', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGNyeXN0YWxsYW5nL2NyeXN0YWwKICBjb21tYW5kczoKICAtIHNo\nYXJkcyBpbnN0YWxsCiAgLSBjcnlzdGFsIHNwZWMuMg==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(14, 'D', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGRsYW5ndWFnZS9kbWQKICBjb21tYW5kczoKICAtIGR1YiB0ZXN0\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(15, 'Dart', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGdvb2dsZS9kYXJ0CiAgY29tbWFuZHM6CiAgLSBwdWIgZ2V0CiAg\nLSBwdWIgcnVuIHRlc3Q=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(16, 'Docker (dind)', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGRvY2tlcjpkaW5kCiAgdm9sdW1lczoKICAtIG5hbWU6IGRvY2tl\ncnNvY2sKICAgIHBhdGg6IC92YXIvcnVuCiAgICBjb21tYW5kczoKICAgIC0g\nc2xlZXAgNSAjIGdpdmUgZG9ja2VyIGVub3VnaCB0aW1lIHRvIHN0YXJ0CiAg\nICAtIGRvY2tlciBwcyAtYQoKc2VydmljZXM6Ci0gbmFtZTogZG9ja2VyCiAg\naW1hZ2U6IGRvY2tlcjpkaW5kCiAgcHJpdmlsZWdlZDogdHJ1ZQogIHZvbHVt\nZXM6CiAgLSBuYW1lOiBkb2NrZXJzb2NrCiAgICBwYXRoOiAvdmFyL3J1bgoK\ndm9sdW1lczoKLSBuYW1lOiBkb2NrZXJzb2NrCiAgdGVtcDoge30=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(17, 'Elasticsearch', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGFscGluZTozLjgKICBjb21tYW5kczoKICAtIGFwayBhZGQgY3Vy\nbAogIC0gc2xlZXAgNDUKICAtIGN1cmwgaHR0cDovL2RhdGFiYXNlOjkyMDAK\nCnNlcnZpY2VzOgotIG5hbWU6IGRhdGFiYXNlCiAgaW1hZ2U6IGVsYXN0aWNz\nZWFyY2g6NS1hbHBpbmU=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(18, 'Elixir', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGVsaXhpcjoxLjUKICBjb21tYW5kczoKICAtIG1peCBsb2NhbC5y\nZWJhciAtLWZvcmNlCiAgLSBtaXggbG9jYWwuaGV4IC0tZm9yY2UKICAtIG1p\neCBkZXBzLmdldAogIC0gbWl4IHRlc3Q=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(19, 'Erlang', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGVybGFuZzoyMQogIGNvbW1hbmRzOgogIC0gcmViYXIgZ2V0LWRl\ncHMKICAtIHJlYmFyIGNvbXBpbGUKICAtIHJlYmFyIHNraXBfZGVwcz10cnVl\nIGV1bml0\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(20, '20.Go (with Gopath)', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0Cgp3b3Jrc3BhY2U6CiAgYmFzZTogL2dv\nCiAgcGF0aDogc3JjL2hlbGxvLXdvcmxkCgpzdGVwczoKLSBuYW1lOiB0ZXN0\nCiAgaW1hZ2U6IGdvbGFuZwogIGNvbW1hbmRzOgogIC0gZ28gZ2V0CiAgLSBn\nbyB0ZXN0\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(21, '21.Go (with Modules)', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGdvbGFuZwogIGNvbW1hbmRzOgogIC0gZ28gdGVzdAogIC0gZ28g\nYnVpbGQ=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(22, 'Gradle', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGdyYWRsZTpqZGsxMAogIGNvbW1hbmRzOgogIC0gZ3JhZGxlIGFz\nc2VtYmxlCiAgLSBncmFkbGUgY2hlY2s=\n', 0, '2020-10-21 10:14:22', '2020-11-26 01:36:17', 351689), -(23, 'Groovy', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGdyYWRsZToyLjUtamRrOAogIGNvbW1hbmRzOgogIC0gLi9ncmFk\nbGV3IGFzc2VtYmxlCiAgLSAuL2dyYWRsZXcgY2hlY2s=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(24, 'Haskell', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGhhc2tlbGwKICBjb21tYW5kczoKICAtIGNhYmFsIGluc3RhbGwg\nLS1vbmx5LWRlcGVuZGVuY2llcyAtLWVuYWJsZS10ZXN0cwogIC0gY2FiYWwg\nY29uZmlndXJlIC0tZW5hYmxlLXRlc3RzCiAgLSBjYWJhbCBidWlsZAogIC0g\nY2FiYWwgdGVzdA==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(25, 'Haxe', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IGhheGUKICBjb21tYW5kczoKICAtIGhheGVsaWIgaW5zdGFsbCBi\ndWlsZC5oeG1sCiAgLSBoYXhlIGJ1aWxkLmh4bWw=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(26, 'MariaDB', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IG1hcmlhZGIKICBjb21tYW5kczoKICAtIHNsZWVwIDE1CiAgLSBt\neXNxbCAtdSByb290IC1oIGRhdGFiYXNlIC0tZXhlY3V0ZT0nU0VMRUNUIFZF\nUlNJT04oKTsnCgpzZXJ2aWNlczoKLSBuYW1lOiBkYXRhYmFzZQogIGltYWdl\nOiBtYXJpYWRiCiAgZW52aXJvbm1lbnQ6CiAgICBNWVNRTF9BTExPV19FTVBU\nWV9QQVNTV09SRDogJ3llcycKICAgIE1ZU1FMX0RBVEFCQVNFOiB0ZXN0\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(27, 'Maven', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IG1hdmVuOjMtamRrLTEwCiAgY29tbWFuZHM6CiAgLSBtdm4gaW5z\ndGFsbCAtRHNraXBUZXN0cz10cnVlIC1EbWF2ZW4uamF2YWRvYy5za2lwPXRy\ndWUgLUIgLVYKICAtIG12biB0ZXN0IC1C\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(28, 'Memcached', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHVidW50dQogIGNvbW1hbmRzOgogIC0gYXB0LWdldCB1cGRhdGUg\nLXFxCiAgLSBhcHQtZ2V0IGluc3RhbGwgLXkgLXFxIHRlbG5ldCA+IC9kZXYv\nbnVsbAogIC0gKHNsZWVwIDE7IGVjaG8gJ3N0YXRzJzsgc2xlZXAgMjsgZWNo\nbyAncXVpdCc7KSB8IHRlbG5ldCBjYWNoZSAxMTIxMSB8fCB0cnVlCgpzZXJ2\naWNlczoKLSBuYW1lOiBjYWNoZQogIGltYWdlOiBtZW1jYWNoZWQ6YWxwaW5l\nCiAgY29tbWFuZDogWyAtdnYgXQ==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(29, 'Nats', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHJ1Ynk6MgogIGNvbW1hbmRzOgogIC0gZ2VtIGluc3RhbGwgbmF0\ncwogIC0gbmF0cy1wdWIgLXMgdGNwOi8vbmF0czo0MjIyIGdyZWV0aW5nICdo\nZWxsbycKICAtIG5hdHMtcHViIC1zIHRjcDovL25hdHM6NDIyMiBncmVldGlu\nZyAnd29ybGQnCgpzZXJ2aWNlczoKLSBuYW1lOiBuYXRzCiAgaW1hZ2U6IG5h\ndHM6MS4zLjA=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(30, 'Node', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IG5vZGUKICBjb21tYW5kczoKICAtIG5wbSBpbnN0YWxsCiAgLSBu\ncG0gdGVzdA==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(31, 'Perl', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHBlcmwKICBjb21tYW5kczoKICAtIGNwYW5tIC0tcXVpZXQgLS1p\nbnN0YWxsZGVwcyAtLW5vdGVzdCAuCiAgLSBwZXJsIEJ1aWxkLlBMCiAgLSAu\nL0J1aWxkIHRlc3Q=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(32, 'Postgres', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHBvc3RncmVzOjktYWxwaW5lCiAgY29tbWFuZHM6CiAgLSBwc3Fs\nIC1VIHBvc3RncmVzIC1kIHRlc3QgLWggZGF0YWJhc2UKCnNlcnZpY2VzOgot\nIG5hbWU6IGRhdGFiYXNlCiAgaW1hZ2U6IHBvc3RncmVzOjktYWxwaW5lCiAg\nZW52aXJvbm1lbnQ6CiAgICBQT1NUR1JFU19VU0VSOiBwb3N0Z3JlcwogICAg\nUE9TVEdSRVNfREI6IHRlc3Q=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(33, 'Redis', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHJlZGlzCiAgY29tbWFuZHM6CiAgLSBzbGVlcCA1CiAgLSByZWRp\ncy1jbGkgLWggcmVkaXMgcGluZwogIC0gcmVkaXMtY2xpIC1oIHJlZGlzIHNl\ndCBGT08gYmFyCiAgLSByZWRpcy1jbGkgLWggcmVkaXMgZ2V0IEZPTwoKc2Vy\ndmljZXM6Ci0gbmFtZTogcmVkaXMKICBpbWFnZTogcmVkaXM=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(34, 'RethinkDB', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IG5vZGU6OQogIGNvbW1hbmRzOgogIC0gbnBtIGluc3RhbGwgLXMg\nLWcgcmVjbGkKICAtIHJlY2xpIC1oIGRhdGFiYXNlIC1qICdyLmRiKCdyZXRo\naW5rZGInKS50YWJsZSgnc3RhdHMnKScKCnNlcnZpY2VzOgotIG5hbWU6IGRh\ndGFiYXNlCiAgaW1hZ2U6IHJldGhpbmtkYjoyCiAgY29tbWFuZDogWyByZXRo\naW5rZGIsIC0tYmluZCwgYWxsIF0=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(35, 'Rust', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHJ1c3Q6MS4zMAogIGNvbW1hbmRzOgogIC0gY2FyZ28gYnVpbGQg\nLS12ZXJib3NlIC0tYWxsCiAgLSBjYXJnbyB0ZXN0IC0tdmVyYm9zZSAtLWFs\nbA==\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(36, 'Swift', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHN3aWZ0OjQKICBjb21tYW5kczoKICAtIHN3aWZ0IGJ1aWxkCiAg\nLSBzd2lmdCB0ZXN0\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL), -(37, 'Vault', 'CmtpbmQ6IHBpcGVsaW5lCm5hbWU6IGRlZmF1bHQKCnBsYXRmb3JtOgogIG9z\nOiBsaW51eAogIGFyY2g6IGFybTY0CgpzdGVwczoKLSBuYW1lOiB0ZXN0CiAg\naW1hZ2U6IHZhdWx0OjEuMC4wLWJldGEyCiAgZW52aXJvbm1lbnQ6CiAgICBW\nQVVMVF9BRERSOiBodHRwOi8vdmF1bHQ6ODIwMAogICAgVkFVTFRfVE9LRU46\nIGR1bW15CiBjb21tYW5kczoKIC0gc2xlZXAgNQogLSB2YXVsdCBrdiBwdXQg\nc2VjcmV0L215LXNlY3JldCBteS12YWx1ZT1zM2NyM3QKIC0gdmF1bHQga3Yg\nZ2V0IHNlY3JldC9teS1zZWNyZXQKCnNlcnZpY2VzOgotIG5hbWU6IHZhdWx0\nCiAgaW1hZ2U6IHZhdWx0OjEuMC4wLWJldGEyCiAgZW52aXJvbm1lbnQ6CiAg\nICBWQVVMVF9ERVZfUk9PVF9UT0tFTl9JRDogZHVtbXk=\n', 0, '2020-10-21 10:14:22', '2020-10-21 10:14:22', NULL); -COMMIT; - --- ---------------------------- --- Records of ci_templates --- ---------------------------- -BEGIN; -INSERT INTO `ci_templates` (`id`, `template_name`, `stage_type`, `category`, `content`, `created_at`, `updated_at`, `parent_category`, `login`) VALUES -(2, 'linux/amd64', 'init', '初始化', 'kind: pipeline\r\ntype: docker\r\nname: {name}\r\nplatform:\r\n os: linux\r\n arch: amd64', '2021-01-12 02:44:23', '2021-02-02 10:51:36', '初始化', 'admin'), -(3, 'linux/arm64', 'init', '初始化', 'kind: pipeline\r\ntype: docker\r\nname: {name}\r\nplatform:\r\n os: linux\r\n arch: arm64', '2021-01-12 02:45:17', '2021-02-02 10:51:47', '初始化', 'admin'), -(4, 'maven', 'build', 'Java', '- name: maven\r\n image: maven:3-jdk-10\r\n commands:\r\n - mvn install -DskipTests=true', '2021-01-12 02:53:29', '2021-01-12 02:53:29', '编译构建', 'admin'), -(5, 'maven单元测试', 'customize', 'Java', '- name: maven\r\n image: maven:3-jdk-10\r\n commands:\r\n - mvn test', '2021-01-12 02:53:29', '2021-01-12 02:53:29', '单元测试', 'admin'), -(6, 'golang单元测试', 'customize', 'Golang', '- name: golang单元测试\r\n image: golang\r\n commands:\r\n - go test', '2021-01-12 03:03:35', '2021-01-12 03:03:35', '单元测试', 'admin'), -(8, 'gradle', 'build', 'Java', '- name: gradle\r\n image: gradle:jdk10\r\n commands:\r\n - gradle build -x test', '2021-01-12 03:05:33', '2021-01-12 03:05:33', '编译构建', 'admin'), -(9, 'gradle单元测试', 'customize', 'Java', '- name: gradle\r\n image: gradle:jdk10\r\n commands:\r\n - gradle test', '2021-01-12 03:05:33', '2021-01-12 03:05:33', '单元测试', 'admin'), -(10, '远程主机部署', 'deploy', '部署', '# 需要将软件包与部署脚本提前上传到远程主机(见文件上传模板)\r\n# host、username、password可在参数管理中配置\r\n- name: 远程主机部署\r\n image: appleboy/drone-ssh\r\n settings:\r\n host: \r\n from_secret: ip\r\n username: \r\n from_secret: name\r\n password: \r\n from_secret: pwd\r\n port: 22\r\n script:\r\n - chmod +x /home/deploy.sh\r\n - ./home/deploy.sh', '2021-01-12 03:32:46', '2021-03-05 06:22:02', '部署', 'admin'), -(11, '远程命令', 'customize', '其他', '# host、username、password可在参数管理中配置\r\n- name: 远程命令\r\n image: appleboy/drone-ssh\r\n settings:\r\n host: \r\n from_secret: ip\r\n username: \r\n from_secret: name\r\n password: \r\n from_secret: pwd\r\n port: 22\r\n script:\r\n - echo ''hello world!''', '2021-01-12 03:40:38', '2021-03-05 06:19:44', '其他', 'admin'), -(12, '上传文件', 'customize', '其他', '# 本模板示例为上传软件包和部署脚本到home目录\r\n# host、username、password可在参数管理中配置\r\n- name: 上传文件\r\n image: appleboy/drone-scp\r\n settings:\r\n host: \r\n from_secret: ip\r\n username: \r\n from_secret: name\r\n password: \r\n from_secret: pwd\r\n port: 22\r\n target: /home\r\n source: \r\n - target/*.jar\r\n - deploy.sh', '2021-01-12 03:40:55', '2021-03-05 06:22:22', '其他', 'admin'), -(17, 'make-c', 'build', 'C', '- name: 编译\r\n image: gcc\r\n commands:\r\n - ./configure\r\n - make', '2021-01-15 01:19:38', '2021-02-02 10:52:15', '编译构建', 'admin'), -(19, 'make-c++', 'build', 'C++', '- name: 编译构建\r\n image: gcc\r\n commands:\r\n - ./configure\r\n - make', '2021-01-15 01:21:05', '2021-01-15 01:21:05', '编译构建', 'admin'), -(20, 'python', 'build', 'Python', '- name: 编译构建\r\n image: python\r\n commands:\r\n - pip install -r requirements.txt', '2021-01-15 01:22:36', '2021-01-15 01:22:36', '编译构建', 'admin'), -(21, 'Docker', 'build', 'Docker', '# 构建Docker镜像并推送到仓库\r\n# 定义镜像Hub路径以及账号密码\r\n- name: Docker镜像构建\r\n image: plugins/docker\r\n settings:\r\n username: username\r\n password: pwd\r\n repo: repoUrl\r\n tags: latest', '2021-01-15 01:23:16', '2021-02-03 03:40:49', '编译构建', 'admin'), -(22, '空白模板', 'customize', 'customize', '', '2021-01-15 02:53:02', '2021-01-15 02:53:02', '其他', 'admin'), -(25, 'Go (with Gopath)', 'build', 'Go', '- name: golang\r\n image: golang\r\n commands:\r\n - go get\r\n - go test', '2021-02-03 00:57:32', '2021-02-03 03:36:15', '编译构建', 'admin'), -(26, 'PHP', 'build', 'PHP', '- name: install\r\n image: composer\r\n commands:\r\n - composer install', '2021-02-03 00:59:15', '2021-02-03 00:59:15', '编译构建', 'admin'), -(27, 'Ruby', 'build', 'Ruby', '- name: ruby\r\n image: ruby\r\n commands:\r\n - bundle install --jobs=3 --retry=3\r\n - rake', '2021-02-03 00:59:52', '2021-02-03 00:59:52', '编译构建', 'admin'), -(29, 'Go (with Modules)', 'build', 'Go', '- name: test\r\n image: golang\r\n commands:\r\n - go test\r\n - go build', '2021-02-03 03:35:45', '2021-02-03 03:35:45', '编译构建', 'admin'), -(30, 'Node', 'build', 'Node', '- name: Node编译\r\n image: node\r\n commands:\r\n - npm install\r\n - npm test', '2021-02-03 03:37:31', '2021-02-03 03:37:31', '编译构建', 'admin'), -(31, 'Perl ', 'build', 'Perl', '- name: perl\r\n image: perl\r\n commands:\r\n - cpanm --quiet --installdeps --notest .\r\n - perl Build.PL\r\n - ./Build test', '2021-02-03 03:38:06', '2021-02-03 03:38:06', '编译构建', 'admin'), -(32, 'Rust ', 'build', 'Rust', '- name: rust\r\n image: rust:1.30\r\n commands:\r\n - cargo build --verbose --all\r\n - cargo test --verbose --all', '2021-02-03 03:38:37', '2021-02-03 03:38:37', '编译构建', 'admin'), -(33, 'test', 'init', '初始化', 'qqqq', '2021-02-04 09:02:42', '2021-02-04 09:02:42', '初始化', 'admin'); -COMMIT; diff --git a/lib/tasks/sync_table_structure.rake b/lib/tasks/sync_table_structure.rake index 026d52140..4cf5f8912 100644 --- a/lib/tasks/sync_table_structure.rake +++ b/lib/tasks/sync_table_structure.rake @@ -18,4 +18,22 @@ namespace :sync_table_structure do puts "init success" end + + task data: :environment do + puts "init table data......." + + database_config = Rails.configuration.database_configuration + + database = database_config[Rails.env]["database"] + database_username = database_config[Rails.env]["username"] + database_password = database_config[Rails.env]["password"] + database_host = database_config[Rails.env]["host"] + database_port = database_config[Rails.env]["port"] || 3306 + + puts "bash: mysql -u#{database_username} -p#{database_password} -P#{database_port} -h#{database_host} #{database}" + + system "mysql -u#{database_username} -p#{database_password} -P#{database_port} -h#{database_host} #{database} < #{Rails.root}/db/init_data.sql" + + puts "init success" + end end From 317c211de918042a6b3c9f77b85a7c36107d2f75 Mon Sep 17 00:00:00 2001 From: viletyy Date: Thu, 3 Jun 2021 11:56:32 +0800 Subject: [PATCH 37/51] add: user info add show field --- Gemfile.lock | 4 +++- app/views/users/get_user_info.json.jbuilder | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 015c0a515..b1dc2cca7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -176,7 +176,9 @@ GEM mimemagic (~> 0.3.2) maruku (0.7.3) method_source (0.9.2) - mimemagic (0.3.4) + mimemagic (0.3.10) + nokogiri (~> 1) + rake mini_mime (1.0.2) mini_portile2 (2.4.0) minitest (5.14.0) diff --git a/app/views/users/get_user_info.json.jbuilder b/app/views/users/get_user_info.json.jbuilder index d9aa44025..fd74b780e 100644 --- a/app/views/users/get_user_info.json.jbuilder +++ b/app/views/users/get_user_info.json.jbuilder @@ -14,3 +14,9 @@ json.profile_completed @user.profile_completed? json.professional_certification @user.professional_certification json.devops_step @user.devops_step json.ci_certification @user.ci_certification? +json.email @user.mail +json.province @user.province +json.city @user.city +json.custom_department @user.custom_department +json.description @user.description +json.(@user, :show_email, :show_department, :show_location) \ No newline at end of file From 6b436acfaf942b9cabfdba3e0fee998fe718e01f Mon Sep 17 00:00:00 2001 From: viletyy Date: Thu, 3 Jun 2021 15:22:08 +0800 Subject: [PATCH 38/51] add: user info add gender --- app/views/users/get_user_info.json.jbuilder | 1 + app/views/users/show.json.jbuilder | 1 + 2 files changed, 2 insertions(+) diff --git a/app/views/users/get_user_info.json.jbuilder b/app/views/users/get_user_info.json.jbuilder index fd74b780e..50296f524 100644 --- a/app/views/users/get_user_info.json.jbuilder +++ b/app/views/users/get_user_info.json.jbuilder @@ -1,5 +1,6 @@ json.username @user.full_name json.real_name @user.real_name +json.gender @user.gender json.login @user.login json.user_id @user.id json.image_url url_to_avatar(@user) diff --git a/app/views/users/show.json.jbuilder b/app/views/users/show.json.jbuilder index 06fab129f..aee46cb01 100644 --- a/app/views/users/show.json.jbuilder +++ b/app/views/users/show.json.jbuilder @@ -2,6 +2,7 @@ json.username @user.full_name json.real_name @user.real_name +json.gender @user.gender json.login @user.login json.user_id @user.id json.image_url url_to_avatar(@user) From 93169f8c9621e4e21addb50f1d4e07a07eb6df57 Mon Sep 17 00:00:00 2001 From: viletyy Date: Thu, 3 Jun 2021 15:43:36 +0800 Subject: [PATCH 39/51] fix: user update return info --- app/controllers/users_controller.rb | 5 ++--- app/views/users/_user.json.jbuilder | 21 +++++++++++++++++---- app/views/users/show.json.jbuilder | 22 ++-------------------- app/views/users/update.json.jbuilder | 1 + 4 files changed, 22 insertions(+), 27 deletions(-) create mode 100644 app/views/users/update.json.jbuilder diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 3f7cd4170..237ce9e6a 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -74,11 +74,10 @@ class UsersController < ApplicationController def update return render_not_found unless @user = User.find_by_id(params[:id]) || User.find_by(login: params[:id]) + return render_forbidden unless User.current.logged? && (current_user&.admin? || current_user.id == @user.id) Util.write_file(@image, avatar_path(@user)) if user_params[:image].present? @user.attributes = user_params.except(:image) - if @user.save - render_ok - else + unless @user.save render_error(@user.errors.full_messages.join(", ")) end end diff --git a/app/views/users/_user.json.jbuilder b/app/views/users/_user.json.jbuilder index 96299c7eb..dc43d6bc8 100644 --- a/app/views/users/_user.json.jbuilder +++ b/app/views/users/_user.json.jbuilder @@ -1,7 +1,20 @@ json.user_id user.id -json.login user.login json.name user.full_name +json.username @user.full_name +json.real_name @user.real_name json.grade user.grade -json.identity user&.user_extension&.identity -# json.email user.mail # 邮箱原则上不暴露的,如果实在需要的话只能对某些具体的接口公开 -json.image_url url_to_avatar(user) +json.gender @user.gender +json.login @user.login +json.user_id @user.id +json.image_url url_to_avatar(@user) +json.admin @user.admin? +json.user_identity @user.identity +json.is_watch current_user&.watched?(@user) +json.watched_count @user.fan_count #粉丝 +json.watching_count @user.follow_count #关注数 +json.created_time format_time(@user.created_on) +json.email @user.show_email ? @user.mail : nil +json.province @user.show_location ? @user.province : nil +json.city @user.show_location ? @user.city : nil +json.custom_department @user.show_department ? @user.custom_department : nil +json.description @user.description \ No newline at end of file diff --git a/app/views/users/show.json.jbuilder b/app/views/users/show.json.jbuilder index aee46cb01..0bbd915bb 100644 --- a/app/views/users/show.json.jbuilder +++ b/app/views/users/show.json.jbuilder @@ -1,16 +1,4 @@ -# json.partial! 'users/user', locals: { user: @user } - -json.username @user.full_name -json.real_name @user.real_name -json.gender @user.gender -json.login @user.login -json.user_id @user.id -json.image_url url_to_avatar(@user) -json.admin @user.admin? -json.user_identity @user.identity -json.is_watch current_user&.watched?(@user) -json.watched_count @user.fan_count #粉丝 -json.watching_count @user.follow_count #关注数 +json.partial! 'users/user', locals: { user: @user } json.undo_messages @waiting_applied_messages.size json.undo_transfer_projects @common_applied_transfer_projects.size json.undo_events @undo_events @@ -18,10 +6,4 @@ json.user_composes_count @user_composes_count json.user_org_count @user_org_count json.common_projects_count @projects_common_count json.mirror_projects_count @projects_mirrior_count -json.sync_mirror_projects_count @projects_sync_mirrior_count -json.created_time format_time(@user.created_on) -json.email @user.show_email ? @user.mail : nil -json.province @user.show_location ? @user.province : nil -json.city @user.show_location ? @user.city : nil -json.custom_department @user.show_department ? @user.custom_department : nil -json.description @user.description \ No newline at end of file +json.sync_mirror_projects_count @projects_sync_mirrior_count \ No newline at end of file diff --git a/app/views/users/update.json.jbuilder b/app/views/users/update.json.jbuilder new file mode 100644 index 000000000..2b31e1826 --- /dev/null +++ b/app/views/users/update.json.jbuilder @@ -0,0 +1 @@ +json.partial! 'users/user', locals: { user: @user } From 2b82b2c4f509b91f52999ecada66c84225497b42 Mon Sep 17 00:00:00 2001 From: jasder Date: Thu, 3 Jun 2021 16:56:54 +0800 Subject: [PATCH 40/51] =?UTF-8?q?FIX=20=20[bug]=E6=96=B0=E5=BB=BA=E6=98=93?= =?UTF-8?q?=E4=BF=AEapi=E4=B8=AD=20=E6=9B=B4=E6=96=B0=E7=9B=B8=E5=85=B3cac?= =?UTF-8?q?he=20key?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/helpers/tag_chosen_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/tag_chosen_helper.rb b/app/helpers/tag_chosen_helper.rb index 348062c77..5193c9ab4 100644 --- a/app/helpers/tag_chosen_helper.rb +++ b/app/helpers/tag_chosen_helper.rb @@ -109,7 +109,7 @@ module TagChosenHelper end def render_cache_milestones(project) - cache_key = "project-#{project.id}/all_milestones/size-#{project.version}/#{project.versions.maximum('updated_on')}" + cache_key = "project-#{project.id}/all_milestones/size-#{project.versions.size}/#{project.versions.maximum('updated_on')}" Rails.cache.fetch(cache_key) do project.versions.select(:id, :name, :status).collect do |event| From fcf8033fbfbde3bc2bd08861b0d12807fb6bd608 Mon Sep 17 00:00:00 2001 From: jasder Date: Thu, 3 Jun 2021 17:04:22 +0800 Subject: [PATCH 41/51] =?UTF-8?q?FIX=20=E8=A7=A3=E5=86=B3=E9=95=9C?= =?UTF-8?q?=E5=83=8F=E9=A1=B9=E7=9B=AE=E6=89=8B=E5=8A=A8=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E9=95=9C=E5=83=8F=E4=B8=8D=E6=88=90=E5=8A=9F=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/jobs/sync_mirrored_repository_job.rb | 22 ++++- app/models/repository.rb | 3 + .../gitea/accelerator/base_service.rb | 96 ++++++++++++++++++ .../gitea/accelerator/migrate_service.rb | 97 +------------------ .../accelerator/sync_mirrored_service.rb | 31 ++++++ 5 files changed, 153 insertions(+), 96 deletions(-) create mode 100644 app/services/gitea/accelerator/base_service.rb create mode 100644 app/services/gitea/accelerator/sync_mirrored_service.rb diff --git a/app/jobs/sync_mirrored_repository_job.rb b/app/jobs/sync_mirrored_repository_job.rb index f0617146a..a1408153f 100644 --- a/app/jobs/sync_mirrored_repository_job.rb +++ b/app/jobs/sync_mirrored_repository_job.rb @@ -5,7 +5,27 @@ class SyncMirroredRepositoryJob < ApplicationJob repo = Repository.find_by(id: repo_id) current_user = User.find_by(id: user_id) return if repo.blank? || current_user.blank? - result = Gitea::Repository::SyncMirroredService.new(repo.owner.login, repo.identifier, token: current_user.gitea_token).call + + # TODO + # 先同步镜像库 + if repo.config_accelerator? + puts "[gitea-accelerator]: ###### 镜像库开始同步 ######" + result = Gitea::Accelerator::SyncMirroredService.call(repo.identifier) + puts "[gitea-accelerator]: ###### 镜像库同步状态为 #{result[:status]}" + + # TODO 暂时解决从镜像库镜像动作时间先执行的问题 + # 避免了Gitea::Repository::SyncMirroredService先执行后,加速器Gitea::Accelerator::SyncMirroredService + # 再执行的导致Gitea::Repository::SyncMirroredService执行镜像不是最新代码的问题 + sleep 3.seconds + end + + sync_common!(repo, current_user) + end + + def sync_common!(repo, user) + result = Gitea::Repository::SyncMirroredService.call(repo.owner.login, + repo.identifier, token: user.gitea_token) repo&.mirror.set_status! if result[:status] === 200 end + end diff --git a/app/models/repository.rb b/app/models/repository.rb index 0daa4b916..a012b449a 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -82,5 +82,8 @@ class Repository < ApplicationRecord source_clone_url.blank? ? mirror_url : source_clone_url end + def config_accelerator? + !source_clone_url.blank? + end end diff --git a/app/services/gitea/accelerator/base_service.rb b/app/services/gitea/accelerator/base_service.rb new file mode 100644 index 000000000..e63d77aab --- /dev/null +++ b/app/services/gitea/accelerator/base_service.rb @@ -0,0 +1,96 @@ +class Gitea::Accelerator::BaseService < ApplicationService + + def post(url, params) + puts "[gitea] request params: #{params}" + puts "[gitea] access_username: #{access_username}" + puts "[gitea] access_password: #{access_password}" + conn.post do |req| + req.url full_url(url) + req.body = params.to_json + end + end + + private + def conn + @client ||= begin + Faraday.new(url: domain) do |req| + req.request :url_encoded + req.headers['Content-Type'] = 'application/json' + req.response :logger # 显示日志 + req.adapter Faraday.default_adapter + req.basic_auth(access_username, access_password) + end + end + @client + end + + def base_url + accelerator["base_url"] + end + + def domain + accelerator["domain"] + end + + def api_url + [domain, base_url].join('') + end + + def full_url(api_rest, action='post') + url = [api_url, api_rest].join('').freeze + url = action === 'get' ? url : URI.escape(url) + puts "[gitea] request url: #{url}" + url + end + + def access_username + accelerator["access_key_id"] + end + + def access_password + accelerator["access_key_secret"] + end + + def access_uid + accelerator["access_admin_uid"] + end + + def accelerator + Gitea.gitea_config[:accelerator] + end + + def render_status(response) + puts "[gitea] response status: #{response.status}" + puts "[gitea] response body: #{response.body}" + case response.status + when 201 + success + when 403 + error('APIForbiddenError') + when 422 + error('APIValidationError') + else + error("MigrateError") + end + end + + def error(message) + { + status: :error, + message: message, + data: nil + } + end + + def success(data=nil) + { + status: :success, + message: nil, + data: data + } + end + + def check_accelerator! + accelerator.blank? || access_username.blank? || access_password.blank? || domain.blank? + end +end \ No newline at end of file diff --git a/app/services/gitea/accelerator/migrate_service.rb b/app/services/gitea/accelerator/migrate_service.rb index 015a09b16..26541b48e 100644 --- a/app/services/gitea/accelerator/migrate_service.rb +++ b/app/services/gitea/accelerator/migrate_service.rb @@ -1,4 +1,4 @@ -class Gitea::Accelerator::MigrateService < ApplicationService +class Gitea::Accelerator::MigrateService < Gitea::Accelerator::BaseService attr_reader :params # params description: @@ -36,8 +36,8 @@ class Gitea::Accelerator::MigrateService < ApplicationService render_status(response) end - private + private def request_params { uid: access_uid, @@ -52,97 +52,4 @@ class Gitea::Accelerator::MigrateService < ApplicationService def url "/repos/migrate".freeze end - - def post(url, params) - puts "[gitea] request params: #{params}" - puts "[gitea] access_username: #{access_username}" - puts "[gitea] access_password: #{access_password}" - conn.post do |req| - req.url full_url(url) - req.body = params.to_json - end - end - - def conn - @client ||= begin - Faraday.new(url: domain) do |req| - req.request :url_encoded - req.headers['Content-Type'] = 'application/json' - req.response :logger # 显示日志 - req.adapter Faraday.default_adapter - req.basic_auth(access_username, access_password) - end - end - @client - end - - def base_url - accelerator["base_url"] - end - - def domain - accelerator["domain"] - end - - def api_url - [domain, base_url].join('') - end - - def full_url(api_rest, action='post') - url = [api_url, api_rest].join('').freeze - url = action === 'get' ? url : URI.escape(url) - puts "[gitea] request url: #{url}" - url - end - - def access_username - accelerator["access_key_id"] - end - - def access_password - accelerator["access_key_secret"] - end - - def access_uid - accelerator["access_admin_uid"] - end - - def accelerator - Gitea.gitea_config[:accelerator] - end - - def render_status(response) - puts "[gitea] response status: #{response.status}" - puts "[gitea] response body: #{response.body}" - case response.status - when 201 - success - when 403 - error('APIForbiddenError') - when 422 - error('APIValidationError') - else - error("MigrateError") - end - end - - def error(message) - { - status: :error, - message: message, - data: nil - } - end - - def success(data=nil) - { - status: :success, - message: nil, - data: data - } - end - - def check_accelerator! - accelerator.blank? || access_username.blank? || access_password.blank? || domain.blank? - end end \ No newline at end of file diff --git a/app/services/gitea/accelerator/sync_mirrored_service.rb b/app/services/gitea/accelerator/sync_mirrored_service.rb new file mode 100644 index 000000000..0e0a7ca94 --- /dev/null +++ b/app/services/gitea/accelerator/sync_mirrored_service.rb @@ -0,0 +1,31 @@ +# Sync a mirrored repository +class Gitea::Accelerator::SyncMirroredService < Gitea::Accelerator::BaseService + attr_reader :repo, :token + + # repo * + # name of the repo to sync + # example: + # Gitea::Accelerator::SyncMirroredService.call(repo.identifier) + def initialize(repo, token=nil) + @repo = repo + @token = token + end + + def call + return error('[gitea:] accelerator config missing') if check_accelerator! + + response = post(url, request_params) + + {status: response.status} + end + + private + + def request_params + Hash.new.merge(token: token).compact + end + + def url + "/repos/#{access_username}/#{repo}/mirror-sync".freeze + end +end From ed8d646d479bdcd84784909a024949bb8e4f093f Mon Sep 17 00:00:00 2001 From: viletyy Date: Thu, 3 Jun 2021 17:12:27 +0800 Subject: [PATCH 42/51] add: user update password --- app/controllers/accounts_controller.rb | 19 +++++++++++++++++++ config/routes.rb | 1 + 2 files changed, 20 insertions(+) diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 09dfdbdb7..0745726b9 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -196,6 +196,25 @@ class AccountsController < ApplicationController # session[:user_id] = @user.id end + def change_password + @user = User.find_by(login: params[:login]) + return render_error("未找到相关用户!") if @user.blank? + return render_error("旧密码不正确") unless @user.check_password?(params[:old_password]) + + sync_params = { + password: params[:password].to_s, + email: @user.mail + } + + interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params) + if interactor.success? + @user.update_attribute(:password, params[:password]) + render_ok + else + render_error(interactor.error) + end + end + # 忘记密码 def reset_password begin diff --git a/config/routes.rb b/config/routes.rb index 1160a4072..9796f774e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -190,6 +190,7 @@ Rails.application.routes.draw do post :remote_update post :remote_login post :remote_password + post :change_password end end From 8133fcd37a890466adde458fde426bb151656e1b Mon Sep 17 00:00:00 2001 From: jasder Date: Fri, 4 Jun 2021 11:33:21 +0800 Subject: [PATCH 43/51] =?UTF-8?q?FIX=20=E6=9B=B4=E6=94=B9=E6=8E=A8?= =?UTF-8?q?=E8=8D=90=E9=A1=B9=E7=9B=AE=E6=8E=92=E5=BA=8F=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/projects_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 7612003f2..3e40619c5 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -177,7 +177,7 @@ class ProjectsController < ApplicationController end def recommend - @projects = Project.recommend.includes(:repository, :project_category, :owner).order(id: :desc) + @projects = Project.recommend.includes(:repository, :project_category, :owner).order(visits: :desc) end def about From 2ea9fcd4d7a86b0f1fa0f615a47973baee774aaa Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Fri, 4 Jun 2021 18:35:35 +0800 Subject: [PATCH 44/51] add: projects filter choosed --- app/queries/projects/list_my_query.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/queries/projects/list_my_query.rb b/app/queries/projects/list_my_query.rb index 5c508c961..c9f4544df 100644 --- a/app/queries/projects/list_my_query.rb +++ b/app/queries/projects/list_my_query.rb @@ -57,6 +57,11 @@ class Projects::ListMyQuery < ApplicationQuery sort = params[:sort_by] || "updated_on" sort_direction = params[:sort_direction] || "desc" - scope.order("projects.#{sort} #{sort_direction}") + + if params[:choosed].present? && params[:choosed].is_a?(Array) + scope.order("FIELD(id, #{params[:choosed].reverse.join(",")}) desc") + else + scope.order("projects.#{sort} #{sort_direction}") + end end end From c211c38d8721bbe04ebcc9ba7d77fbce4b3f9262 Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Fri, 4 Jun 2021 18:41:19 +0800 Subject: [PATCH 45/51] fix --- app/models/project.rb | 82 ++---------------------------------- app/models/user_extension.rb | 47 ++++++++++----------- 2 files changed, 25 insertions(+), 104 deletions(-) diff --git a/app/models/project.rb b/app/models/project.rb index 46adf9d7a..f41e980d7 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1,11 +1,10 @@ -<<<<<<< HEAD # == Schema Information # # Table name: projects # # id :integer not null, primary key # name :string(255) default(""), not null -# description :text(4294967295) +# description :text(65535) # homepage :string(255) default("") # is_public :boolean default("1"), not null # parent_id :integer @@ -38,24 +37,12 @@ # 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") -# license_id :integer -# ignore_id :integer -# default_branch :string(255) default("master") -# website :string(255) -# lesson_url :string(255) # # Indexes # @@ -72,69 +59,6 @@ # 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(65535) -# 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") -# -# 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) -# - ->>>>>>> ed8d646d479bdcd84784909a024949bb8e4f093f class Project < ApplicationRecord diff --git a/app/models/user_extension.rb b/app/models/user_extension.rb index 6d6ed13b9..0749d1f79 100644 --- a/app/models/user_extension.rb +++ b/app/models/user_extension.rb @@ -22,15 +22,12 @@ # school_id :integer # description :string(255) default("") # department_id :integer -<<<<<<< HEAD # province :string(255) # city :string(255) # custom_department :string(255) # show_email :boolean default("0") # show_location :boolean default("0") # show_department :boolean default("0") -======= ->>>>>>> ed8d646d479bdcd84784909a024949bb8e4f093f # # Indexes # @@ -39,25 +36,25 @@ # index_user_extensions_on_user_id (user_id) # -class UserExtension < ApplicationRecord - # identity 0: 教师教授 1: 学生, 2: 专业人士, 3: 开发者 - enum identity: { teacher: 0, student: 1, professional: 2, developer: 3, enterprise: 4, unselect: -1 } - - belongs_to :user, touch: true - belongs_to :school, optional: true - # belongs_to :department, optional: true - - # before_save :set_laboratory_school - - def identity_text - I18n.t("user.identity.#{identity}") - end - - private - - def set_laboratory_school - # return unless new_record? - - # self.school_id = Laboratory.current.school_id if school_id.blank? && !Laboratory.current.main_site? - end -end +class UserExtension < ApplicationRecord + # identity 0: 教师教授 1: 学生, 2: 专业人士, 3: 开发者 + enum identity: { teacher: 0, student: 1, professional: 2, developer: 3, enterprise: 4, unselect: -1 } + + belongs_to :user, touch: true + belongs_to :school, optional: true + # belongs_to :department, optional: true + + # before_save :set_laboratory_school + + def identity_text + I18n.t("user.identity.#{identity}") + end + + private + + def set_laboratory_school + # return unless new_record? + + # self.school_id = Laboratory.current.school_id if school_id.blank? && !Laboratory.current.main_site? + end +end From e8f4b3f17c28dfc0471ec168c56ed5a7217afe3c Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Fri, 4 Jun 2021 18:43:12 +0800 Subject: [PATCH 46/51] fix --- app/controllers/users_controller.rb | 8 -------- 1 file changed, 8 deletions(-) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index e2efb7cf8..237ce9e6a 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -74,18 +74,10 @@ class UsersController < ApplicationController def update return render_not_found unless @user = User.find_by_id(params[:id]) || User.find_by(login: params[:id]) -<<<<<<< HEAD - Util.write_file(@image, avatar_path(@user)) if user_params[:image].present? - @user.attributes = user_params.except(:image) - if @user.save - render_ok - else -======= return render_forbidden unless User.current.logged? && (current_user&.admin? || current_user.id == @user.id) Util.write_file(@image, avatar_path(@user)) if user_params[:image].present? @user.attributes = user_params.except(:image) unless @user.save ->>>>>>> ed8d646d479bdcd84784909a024949bb8e4f093f render_error(@user.errors.full_messages.join(", ")) end end From d5a65112ca46edb72be908970af58cd95c205c59 Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Mon, 7 Jun 2021 14:17:12 +0800 Subject: [PATCH 47/51] fix: statistics develop load slowly --- .../users/statistics_controller.rb | 145 +++++++++++++++--- 1 file changed, 121 insertions(+), 24 deletions(-) diff --git a/app/controllers/users/statistics_controller.rb b/app/controllers/users/statistics_controller.rb index d508176e2..255f0e948 100644 --- a/app/controllers/users/statistics_controller.rb +++ b/app/controllers/users/statistics_controller.rb @@ -162,29 +162,126 @@ class Users::StatisticsController < Users::BaseController end def preload_develop_data - # 用户被follow数量 - @follow_count = time_filter(Watcher.where(watchable: observed_user), 'created_at').count - @platform_follow_count = time_filter(Watcher.where(watchable_type: 'User'), 'created_at').count - # 用户pr数量 - @pullrequest_count = time_filter(PullRequest.where(user_id: observed_user.id), 'created_at').count - @platform_pullrequest_count = time_filter(PullRequest, 'created_at').count - # 用户issue数量 - @issues_count = time_filter(Issue.where(author_id: observed_user.id), 'created_on').count - @platform_issues_count = time_filter(Issue, 'created_on').count - # 用户总项目数 @fork_count + @project_watchers_count + @project_praises_count - @project_count = filter_member_projects_by_role("Owner").count - @platform_project_count = time_filter(Project, 'created_on').count - # 用户项目被fork数量 - @fork_count = filter_member_projects_by_role("Owner").sum("forked_count") - @platform_fork_count = time_filter(Project, 'created_on').sum("forked_count") - # 用户项目关注数 - @project_watchers_count = filter_member_projects_by_role("Owner").sum("watchers_count") - @platform_project_watchers_count = time_filter(Project, 'created_on').sum("watchers_count") - # 用户项目点赞数 - @project_praises_count = filter_member_projects_by_role("Owner").sum("praises_count") - @platform_project_praises_count = time_filter(Project, 'created_on').sum("praises_count") - # 用户不同语言项目数量 - @project_languages_count = filter_member_projects_by_role("Owner").joins(:project_language).group("project_languages.name").count - @platform_project_languages_count = time_filter(Project, 'created_on').joins(:project_language).group("project_languages.name").count + if params[:start_time].present? && params[:end_time].present? + # 用户被follow数量 + @follow_count = Rails.cache.fetch("user-follow-count-#{observed_user.id}-start:#{params[:start_time]}-end:#{params[:end_time]}-#{Watcher.where(watchable: observed_user).maximum('created_at').to_i}") do + time_filter(Watcher.where(watchable: observed_user), 'created_at').count + end + @platform_follow_count = Rails.cache.fetch("platform-follow-count-start:#{params[:start_time]}-end:#{params[:end_time]}-#{Watcher.where(watchable_type: 'User').maximum('created_at').to_i}") do + time_filter(Watcher.where(watchable_type: 'User'), 'created_at').count + end + # 用户pr数量 + @pullrequest_count = Rails.cache.fetch("user-pullrequest-count-#{observed_user.id}-start:#{params[:start_time]}-end:#{params[:end_time]}-#{PullRequest.where(user_id: observed_user.id).maximum('created_at').to_i}") do + time_filter(PullRequest.where(user_id: observed_user.id), 'created_at').count + end + @platform_pullrequest_count = Rails.cache.fetch("platform-pullrequest-count-start:#{params[:start_time]}-end:#{params[:end_time]}-#{PullRequest.maximum('created_at').to_i}") do + time_filter(PullRequest, 'created_at').count + end + # 用户issue数量 + @issues_count = Rails.cache.fetch("user-issue-count-#{observed_user.id}-start:#{params[:start_time]}-end:#{params[:end_time]}-#{Issue.where(author_id: observed_user.id).maximum('created_on').to_i}") do + time_filter(Issue.where(author_id: observed_user.id), 'created_on').count + end + @platform_issues_count = Rails.cache.fetch("platform-issue-count-start:#{params[:start_time]}-end:#{params[:end_time]}-#{Issue.maximum('created_on').to_i}") do + time_filter(Issue, 'created_on').count + end + # 用户总项目数 + @project_count = Rails.cache.fetch("user-project-count-#{observed_user.id}-start:#{params[:start_time]}-end:#{params[:end_time]}-#{Project.where(user_id:observed_user.id).maximum('created_on').to_i}") do + time_filter(Project.where(user_id:observed_user.id), 'created_on').count + end + @platform_project_count = Rails.cache.fetch("platform-project-count-start:#{params[:start_time]}-end:#{params[:end_time]}-#{Project.maximum('created_on').to_i}") do + time_filter(Project, 'created_on').count + end + # 用户项目被fork数量 + @fork_count = Rails.cache.fetch("user-fork-count-#{observed_user.id}-start:#{params[:start_time]}-end:#{params[:end_time]}-#{ForkUser.joins(:project).where(projects: {user_id: observed_user.id}).maximum('created_at').to_i}") do + time_filter(Project.where(user_id:observed_user.id), 'created_on').sum("forked_count") + end + @platform_fork_count = Rails.cache.fetch("platform-fork-count-start:#{params[:start_time]}-end:#{params[:end_time]}-#{ForkUser.maximum('created_at').to_i}") do + time_filter(Project, 'created_on').sum("forked_count") + end + + # 用户项目关注数 + @project_watchers_count = Rails.cache.fetch("user-watchers-count-start:#{params[:start_time]}-end:#{params[:end_time]}-#{observed_user.id}-#{Watcher.where(watchable_type: 'Project', watchable_id: observed_user.projects).maximum('created_at').to_i}") do + time_filter(Project.where(user_id: observed_user.id), 'created_on').sum("watchers_count") + end + @platform_project_watchers_count = Rails.cache.fetch("platform-watchers-count-start:#{params[:start_time]}-end:#{params[:end_time]}-#{Watcher.where(watchable_type: 'Project').maximum('created_at').to_i}") do + time_filter(Project, 'created_on').sum("watchers_count") + end + + # 用户项目点赞数 + @project_praises_count = Rails.cache.fetch("user-praises-count-#{observed_user.id}-start:#{params[:start_time]}-end:#{params[:end_time]}-#{PraiseTread.where(praise_tread_object_type: 'Project', praise_tread_object_id: observed_user.projects).maximum('created_at').to_i}") do + time_filter(Project.where(user_id: observed_user.id), 'created_on').sum("praises_count") + end + @platform_project_praises_count = Rails.cache.fetch("user-praises-count-#{observed_user.id}-start:#{params[:start_time]}-end:#{params[:end_time]}-#{PraiseTread.where(praise_tread_object_type: 'Project', praise_tread_object_id: observed_user.projects).maximum('created_at').to_i}") do + time_filter(Project, 'created_on').sum("praises_count") + end + + # 用户不同语言项目数量 + @project_languages_count = Rails.cache.fetch("user-languages-count-#{observed_user.id}-start:#{params[:start_time]}-end:#{params[:end_time]}-#{Project.where(user_id:observed_user.id).maximum('created_on').to_i}") do + time_filter(Project.where(user_id: observed_user.id), 'created_on').joins(:project_language).group("project_languages.name").count + end + @platform_project_languages_count = Rails.cache.fetch("platform-languages-count-start:#{params[:start_time]}-end:#{params[:end_time]}-#{Project.maximum('created_on').to_i}") do + time_filter(Project, 'created_on').joins(:project_language).group("project_languages.name").count + end + else + # 用户被follow数量 + @follow_count = Rails.cache.fetch("user-follow-count-#{observed_user.id}-#{Watcher.where(watchable: observed_user).maximum('created_at').to_i}") do + time_filter(Watcher.where(watchable: observed_user), 'created_at').count + end + @platform_follow_count = Rails.cache.fetch("platform-follow-count-#{Watcher.where(watchable_type: 'User').maximum('created_at').to_i}") do + time_filter(Watcher.where(watchable_type: 'User'), 'created_at').count + end + # 用户pr数量 + @pullrequest_count = Rails.cache.fetch("user-pullrequest-count-#{observed_user.id}-#{PullRequest.where(user_id: observed_user.id).maximum('created_at').to_i}") do + time_filter(PullRequest.where(user_id: observed_user.id), 'created_at').count + end + @platform_pullrequest_count = Rails.cache.fetch("platform-pullrequest-count-#{PullRequest.maximum('created_at').to_i}") do + time_filter(PullRequest, 'created_at').count + end + # 用户issue数量 + @issues_count = Rails.cache.fetch("user-issue-count-#{observed_user.id}-#{Issue.where(author_id: observed_user.id).maximum('created_on').to_i}") do + time_filter(Issue.where(author_id: observed_user.id), 'created_on').count + end + @platform_issues_count = Rails.cache.fetch("platform-issue-count-#{Issue.maximum('created_on').to_i}") do + time_filter(Issue, 'created_on').count + end + # 用户总项目数 + @project_count = Rails.cache.fetch("user-project-count-#{observed_user.id}-#{Project.where(user_id:observed_user.id).maximum('created_on').to_i}") do + time_filter(Project.where(user_id:observed_user.id), 'created_on').count + end + @platform_project_count = Rails.cache.fetch("platform-project-count-#{Project.maximum('created_on').to_i}") do + time_filter(Project, 'created_on').count + end + # 用户项目被fork数量 + @fork_count = Rails.cache.fetch("user-fork-count-#{observed_user.id}-#{ForkUser.joins(:project).where(projects: {user_id: observed_user.id}).maximum('created_at').to_i}") do + time_filter(Project.where(user_id:observed_user.id), 'created_on').sum("forked_count") + end + @platform_fork_count = Rails.cache.fetch("platform-fork-count-#{ForkUser.maximum('created_at').to_i}") do + time_filter(Project, 'created_on').sum("forked_count") + end + + # 用户项目关注数 + @project_watchers_count = Rails.cache.fetch("user-watchers-count-#{observed_user.id}-#{Watcher.where(watchable_type: 'Project', watchable_id: observed_user.projects).maximum('created_at').to_i}") do + time_filter(Project.where(user_id: observed_user.id), 'created_on').sum("watchers_count") + end + @platform_project_watchers_count = Rails.cache.fetch("platform-watchers-count-#{Watcher.where(watchable_type: 'Project').maximum('created_at').to_i}") do + time_filter(Project, 'created_on').sum("watchers_count") + end + + # 用户项目点赞数 + @project_praises_count = Rails.cache.fetch("user-praises-count-#{observed_user.id}-#{PraiseTread.where(praise_tread_object_type: 'Project', praise_tread_object_id: observed_user.projects).maximum('created_at').to_i}") do + time_filter(Project.where(user_id: observed_user.id), 'created_on').sum("praises_count") + end + @platform_project_praises_count = Rails.cache.fetch("user-praises-count-#{observed_user.id}-#{PraiseTread.where(praise_tread_object_type: 'Project', praise_tread_object_id: observed_user.projects).maximum('created_at').to_i}") do + time_filter(Project, 'created_on').sum("praises_count") + end + + # 用户不同语言项目数量 + @project_languages_count = Rails.cache.fetch("user-languages-count-#{observed_user.id}-#{Project.where(user_id:observed_user.id).maximum('created_on').to_i}") do + time_filter(Project.where(user_id: observed_user.id), 'created_on').joins(:project_language).group("project_languages.name").count + end + @platform_project_languages_count = Rails.cache.fetch("platform-languages-count-#{Project.maximum('created_on').to_i}") do + time_filter(Project, 'created_on').joins(:project_language).group("project_languages.name").count + end + end end end \ No newline at end of file From a5b98bcad442a3c7fa6137c27ec4fad0df73134c Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Mon, 7 Jun 2021 14:34:51 +0800 Subject: [PATCH 48/51] fix: concat nickname --- .../admins/auth_schools_controller.rb | 2 +- .../admins/laboratories_controller.rb | 4 +- app/controllers/members_controller.rb | 2 +- .../organization_users_controller.rb | 2 +- app/controllers/users_controller.rb | 2 +- .../users_for_private_messages_controller.rb | 2 +- app/controllers/weapps/courses_controller.rb | 4 +- app/controllers/zips_controller.rb | 4 +- app/models/attachment.rb | 80 +++++++++---------- app/models/user.rb | 2 +- app/queries/admins/apply_item_bank_query.rb | 2 +- .../admins/apply_user_authentication_query.rb | 2 +- app/queries/admins/course_list_query.rb | 2 +- app/queries/admins/course_query.rb | 2 +- app/queries/admins/laboratory_shixun_query.rb | 2 +- .../admins/laboratory_subject_query.rb | 2 +- app/queries/admins/subject_query.rb | 2 +- app/queries/admins/user_query.rb | 4 +- app/queries/user_query.rb | 2 +- app/services/admins/import_user_service.rb | 2 +- 20 files changed, 63 insertions(+), 63 deletions(-) diff --git a/app/controllers/admins/auth_schools_controller.rb b/app/controllers/admins/auth_schools_controller.rb index e7c0253b6..825c04cdc 100644 --- a/app/controllers/admins/auth_schools_controller.rb +++ b/app/controllers/admins/auth_schools_controller.rb @@ -32,7 +32,7 @@ class Admins::AuthSchoolsController < Admins::BaseController def search_manager school = School.find_by(id: params[:school_id]) user_ids = school&.ec_school_users&.pluck(:user_id) - @users = User.where.not(id: user_ids).where("concat(lastname, firstname) like ?", "%#{params[:name].strip.to_s}%").limit(10) + @users = User.where.not(id: user_ids).where("CONCAT_WS(lastname, firstname, nickname) like ?", "%#{params[:name].strip.to_s}%").limit(10) end # 添加认证学校管理员 diff --git a/app/controllers/admins/laboratories_controller.rb b/app/controllers/admins/laboratories_controller.rb index f397b0f34..46463fed0 100644 --- a/app/controllers/admins/laboratories_controller.rb +++ b/app/controllers/admins/laboratories_controller.rb @@ -32,7 +32,7 @@ class Admins::LaboratoriesController < Admins::BaseController keyword = params[:keyword].to_s.strip if keyword.present? - like_sql = 'shixuns.name LIKE :keyword OR CONCAT(users.lastname, users.firstname) LIKE :keyword '\ + like_sql = 'shixuns.name LIKE :keyword OR CONCAT_WS(users.lastname, users.firstname, users.nickname) LIKE :keyword '\ 'OR mirror_repositories.name LIKE :keyword' shixuns = shixuns.joins(:user, :mirror_repositories).where(like_sql, keyword: "%#{keyword}%") end @@ -48,7 +48,7 @@ class Admins::LaboratoriesController < Admins::BaseController keyword = params[:keyword].to_s.strip if keyword.present? - like_sql = 'subjects.name LIKE :keyword OR CONCAT(users.lastname, users.firstname) LIKE :keyword' + like_sql = 'subjects.name LIKE :keyword OR CONCAT_WS(users.lastname, users.firstname, users.nickname) LIKE :keyword' subjects = subjects.joins(:user).where(like_sql, keyword: "%#{keyword}%") end diff --git a/app/controllers/members_controller.rb b/app/controllers/members_controller.rb index bea4a0d29..fea57fa72 100644 --- a/app/controllers/members_controller.rb +++ b/app/controllers/members_controller.rb @@ -18,7 +18,7 @@ class MembersController < ApplicationController scope = @project.members.includes(:roles, user: :user_extension) search = params[:search].to_s.downcase role = params[:role].to_s - scope = scope.joins(:user).where("LOWER(concat(users.lastname, users.firstname, users.login, users.mail)) LIKE ?", "%#{search.split(" ").join('|')}%") if search.present? + scope = scope.joins(:user).where("LOWER(CONCAT_WS(users.lastname, users.firstname, users.login, users.mail, users.nickname)) LIKE ?", "%#{search.split(" ").join('|')}%") if search.present? scope = scope.joins(:roles).where("roles.name LIKE ?", "%#{role}%") if role.present? @total_count = scope.size diff --git a/app/controllers/organizations/organization_users_controller.rb b/app/controllers/organizations/organization_users_controller.rb index 8a7755a1b..d2d6963a4 100644 --- a/app/controllers/organizations/organization_users_controller.rb +++ b/app/controllers/organizations/organization_users_controller.rb @@ -5,7 +5,7 @@ class Organizations::OrganizationUsersController < Organizations::BaseController def index @organization_users = @organization.organization_users.includes(:user) search = params[:search].to_s.downcase - @organization_users = @organization_users.joins(:user).where("LOWER(CONCAT_WS(users.lastname, users.firstname, users.login, users.mail)) LIKE ?", "%#{search.split(" ").join('|')}%") if search.present? + @organization_users = @organization_users.joins(:user).where("LOWER(CONCAT_WS(users.lastname, users.firstname, users.login, users.mail, users.nickname)) LIKE ?", "%#{search.split(" ").join('|')}%") if search.present? @organization_users = kaminari_paginate(@organization_users) end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 237ce9e6a..163b5849f 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -63,7 +63,7 @@ class UsersController < ApplicationController def fan_users watchers = @user.watchers.includes(:user).order("watchers.created_at desc") - watchers = watchers.joins(:user).where("LOWER(concat(users.lastname, users.firstname, users.login)) LIKE ?", "%#{params[:search].split(" ").join('|')}%") if params[:search].present? + watchers = watchers.joins(:user).where("LOWER(CONCAT_WS(users.lastname, users.firstname, users.login, users.nickname)) LIKE ?", "%#{params[:search].split(" ").join('|')}%") if params[:search].present? @watchers_count = watchers.size @watchers = paginate(watchers) diff --git a/app/controllers/users_for_private_messages_controller.rb b/app/controllers/users_for_private_messages_controller.rb index 610bf5d52..3a53a1af8 100644 --- a/app/controllers/users_for_private_messages_controller.rb +++ b/app/controllers/users_for_private_messages_controller.rb @@ -11,7 +11,7 @@ class UsersForPrivateMessagesController < ApplicationController return end - users = users.where('LOWER(concat(lastname, firstname, nickname)) LIKE ?', "%#{keyword}%") + users = users.where('LOWER(CONCAT_WS(lastname, firstname, nickname)) LIKE ?', "%#{keyword}%") @users = users.limit(10).includes(:user_extension) end diff --git a/app/controllers/weapps/courses_controller.rb b/app/controllers/weapps/courses_controller.rb index ccd5d1bcf..72782f5cc 100644 --- a/app/controllers/weapps/courses_controller.rb +++ b/app/controllers/weapps/courses_controller.rb @@ -86,7 +86,7 @@ class Weapps::CoursesController < Weapps::BaseController end if search.present? - @teacher_list = @teacher_list.joins(:user).where("LOWER(CONCAT(users.lastname, users.firstname)) like ?", "%#{search}%") + @teacher_list = @teacher_list.joins(:user).where("LOWER(CONCAT_WS(users.lastname, users.firstname, users.nickname)) like ?", "%#{search}%") end @teacher_list_size = @teacher_list.size @@ -127,7 +127,7 @@ class Weapps::CoursesController < Weapps::BaseController @students = CourseMember.students(@course) if search.present? - @students = @students.joins(user: :user_extension).where("LOWER(CONCAT(users.lastname, users.firstname)) like ? or + @students = @students.joins(user: :user_extension).where("LOWER(CONCAT_WS(users.lastname, users.firstname, users.nickname)) like ? or user_extensions.student_id like ?", "%#{search}%", "%#{search}%") end diff --git a/app/controllers/zips_controller.rb b/app/controllers/zips_controller.rb index 3ed1eb8b3..0c226211f 100644 --- a/app/controllers/zips_controller.rb +++ b/app/controllers/zips_controller.rb @@ -86,7 +86,7 @@ class ZipsController < ApplicationController #搜索 if params[:search].present? - @ex_users = @ex_users.joins(user: :user_extension).where("CONCAT(lastname, firstname) like ? OR student_id like ?", "%#{params[:search]}%", "%#{params[:search]}%") + @ex_users = @ex_users.joins(user: :user_extension).where("CONCAT_WS(lastname, firstname, nickname) like ? OR student_id like ?", "%#{params[:search]}%", "%#{params[:search]}%") end default_ex_users_size = @ex_users&.size @@ -130,7 +130,7 @@ class ZipsController < ApplicationController end unless params[:search].blank? - @all_student_works = @all_student_works.joins(user: :user_extension).where("concat(lastname, firstname) like ? + @all_student_works = @all_student_works.joins(user: :user_extension).where("CONCAT_WS(lastname, firstname, nickname) like ? or student_id like ?", "%#{params[:search]}%", "%#{params[:search]}%") end diff --git a/app/models/attachment.rb b/app/models/attachment.rb index 461c835fe..3bfc9a8ce 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -1,42 +1,42 @@ -# == Schema Information -# -# Table name: attachments -# -# id :integer not null, primary key -# container_id :integer -# container_type :string(30) -# filename :string(255) default(""), not null -# disk_filename :string(255) default(""), not null -# filesize :integer default("0"), not null -# content_type :string(255) default("") -# digest :string(60) default(""), not null -# downloads :integer default("0"), not null -# author_id :integer default("0"), not null -# created_on :datetime -# description :text(65535) -# disk_directory :string(255) -# attachtype :integer default("1") -# is_public :integer default("1") -# copy_from :integer -# quotes :integer default("0") -# is_publish :integer default("1") -# publish_time :datetime -# resource_bank_id :integer -# unified_setting :boolean default("1") -# cloud_url :string(255) default("") -# course_second_category_id :integer default("0") -# delay_publish :boolean default("0") -# -# Indexes -# -# index_attachments_on_author_id (author_id) -# index_attachments_on_container_id_and_container_type (container_id,container_type) -# index_attachments_on_course_second_category_id (course_second_category_id) -# index_attachments_on_created_on (created_on) -# index_attachments_on_is_public (is_public) -# index_attachments_on_quotes (quotes) -# - +# == Schema Information +# +# Table name: attachments +# +# id :integer not null, primary key +# container_id :integer +# container_type :string(30) +# filename :string(255) default(""), not null +# disk_filename :string(255) default(""), not null +# filesize :integer default("0"), not null +# content_type :string(255) default("") +# digest :string(60) default(""), not null +# downloads :integer default("0"), not null +# author_id :integer default("0"), not null +# created_on :datetime +# description :text(65535) +# disk_directory :string(255) +# attachtype :integer default("1") +# is_public :integer default("1") +# copy_from :integer +# quotes :integer default("0") +# is_publish :integer default("1") +# publish_time :datetime +# resource_bank_id :integer +# unified_setting :boolean default("1") +# cloud_url :string(255) default("") +# course_second_category_id :integer default("0") +# delay_publish :boolean default("0") +# +# Indexes +# +# index_attachments_on_author_id (author_id) +# index_attachments_on_container_id_and_container_type (container_id,container_type) +# index_attachments_on_course_second_category_id (course_second_category_id) +# index_attachments_on_created_on (created_on) +# index_attachments_on_is_public (is_public) +# index_attachments_on_quotes (quotes) +# + class Attachment < ApplicationRecord include BaseModel include Publicable @@ -51,7 +51,7 @@ class Attachment < ApplicationRecord # 二级目录 # belongs_to :course_second_category, optional: true - scope :by_filename_or_user_name, -> (keywords) { joins(:author).where("filename like :search or LOWER(concat(users.lastname, users.firstname)) LIKE :search", + scope :by_filename_or_user_name, -> (keywords) { joins(:author).where("filename like :search or LOWER(CONCAT_WS(users.lastname, users.firstname, users.nickname)) LIKE :search", :search => "%#{keywords.split(" ").join('|')}%") unless keywords.blank? } scope :by_keywords, -> (keywords) { where("filename LIKE ?", "%#{keywords.split(" ").join('|')}%") unless keywords.blank? } scope :ordered, -> (opts = {}) { order("#{opts[:sort_type]} #{opts[:sort] == 1 ? 'asc': 'desc'}") } diff --git a/app/models/user.rb b/app/models/user.rb index 99b1e7cd7..9d917f4c8 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -170,7 +170,7 @@ class User < Owner # Groups and active users scope :active, lambda { where(status: STATUS_ACTIVE) } scope :like, lambda { |keywords| - sql = "CONCAT(lastname, firstname) LIKE :search OR login LIKE :search OR mail LIKE :search OR nickname LIKE :search" + sql = "CONCAT_WS(lastname, firstname, nickname) LIKE :search OR login LIKE :search OR mail LIKE :search OR nickname LIKE :search" where(sql, :search => "%#{keywords.split(" ").join('|')}%") unless keywords.blank? } diff --git a/app/queries/admins/apply_item_bank_query.rb b/app/queries/admins/apply_item_bank_query.rb index 37b6d25a6..922d136ef 100644 --- a/app/queries/admins/apply_item_bank_query.rb +++ b/app/queries/admins/apply_item_bank_query.rb @@ -26,7 +26,7 @@ class Admins::ApplyItemBankQuery < ApplicationQuery keyword = params[:keyword].to_s.strip if keyword.present? applies = applies.joins(user: { user_extension: :school }) - .where('CONCAT(lastname,firstname) LIKE :keyword OR schools.name LIKE :keyword', keyword: "%#{keyword}%") + .where('CONCAT_WS(lastname,firstname, nickname) LIKE :keyword OR schools.name LIKE :keyword', keyword: "%#{keyword}%") end custom_sort(applies, params[:sort_by], params[:sort_direction]) diff --git a/app/queries/admins/apply_user_authentication_query.rb b/app/queries/admins/apply_user_authentication_query.rb index a4d1c2a4a..60b781d1c 100644 --- a/app/queries/admins/apply_user_authentication_query.rb +++ b/app/queries/admins/apply_user_authentication_query.rb @@ -26,7 +26,7 @@ class Admins::ApplyUserAuthenticationQuery < ApplicationQuery keyword = params[:keyword].to_s.strip if keyword.present? applies = applies.joins(user: { user_extension: :school }) - .where('CONCAT(lastname,firstname) LIKE :keyword OR schools.name LIKE :keyword', keyword: "%#{keyword}%") + .where('CONCAT_WS(lastname,firstname,nickname) LIKE :keyword OR schools.name LIKE :keyword', keyword: "%#{keyword}%") end custom_sort(applies, params[:sort_by], params[:sort_direction]) diff --git a/app/queries/admins/course_list_query.rb b/app/queries/admins/course_list_query.rb index 24eedaf1b..b97a9cebe 100644 --- a/app/queries/admins/course_list_query.rb +++ b/app/queries/admins/course_list_query.rb @@ -19,7 +19,7 @@ class Admins::CourseListQuery < ApplicationQuery case search_type when "0" course_lists = course_lists.joins(:user) - .where('CONCAT(lastname, firstname) like :keyword', keyword: "%#{keyword}%") + .where('CONCAT_WS(lastname, firstname, nickname) like :keyword', keyword: "%#{keyword}%") when "1" course_lists = course_lists.where('name like :keyword', keyword: "%#{keyword}%") end diff --git a/app/queries/admins/course_query.rb b/app/queries/admins/course_query.rb index e883650d0..b1466e22f 100644 --- a/app/queries/admins/course_query.rb +++ b/app/queries/admins/course_query.rb @@ -35,7 +35,7 @@ class Admins::CourseQuery < ApplicationQuery # 关键字 keyword = params[:keyword].to_s.strip if keyword - sql = 'CONCAT(lastname, firstname) LIKE :keyword OR courses.name LIKE :keyword OR course_lists.name LIKE :keyword' + sql = 'CONCAT_WS(lastname, firstname, nickname) LIKE :keyword OR courses.name LIKE :keyword OR course_lists.name LIKE :keyword' courses = courses.joins(:teacher, :course_list).where(sql, keyword: "%#{keyword}%") end diff --git a/app/queries/admins/laboratory_shixun_query.rb b/app/queries/admins/laboratory_shixun_query.rb index d489aed21..9b9bf6a21 100644 --- a/app/queries/admins/laboratory_shixun_query.rb +++ b/app/queries/admins/laboratory_shixun_query.rb @@ -11,7 +11,7 @@ class Admins::LaboratoryShixunQuery < ApplicationQuery keyword = params[:keyword].to_s.strip if keyword.present? - like_sql = 'shixuns.name LIKE :keyword OR CONCAT(users.lastname, users.firstname) LIKE :keyword' + like_sql = 'shixuns.name LIKE :keyword OR CONCAT_WS(users.lastname, users.firstname, users.nickname) LIKE :keyword' laboratory_shixuns = laboratory_shixuns.joins(shixun: :user).where(like_sql, keyword: "%#{keyword}%") end diff --git a/app/queries/admins/laboratory_subject_query.rb b/app/queries/admins/laboratory_subject_query.rb index 316ea9743..619aeb2c2 100644 --- a/app/queries/admins/laboratory_subject_query.rb +++ b/app/queries/admins/laboratory_subject_query.rb @@ -11,7 +11,7 @@ class Admins::LaboratorySubjectQuery < ApplicationQuery keyword = params[:keyword].to_s.strip if keyword.present? - like_sql = 'subjects.name LIKE :keyword OR CONCAT(users.lastname, users.firstname) LIKE :keyword' + like_sql = 'subjects.name LIKE :keyword OR CONCAT_WS(users.lastname, users.firstname, users.nickname) LIKE :keyword' laboratory_subjects = laboratory_subjects.joins(subject: :user).where(like_sql, keyword: "%#{keyword}%") end diff --git a/app/queries/admins/subject_query.rb b/app/queries/admins/subject_query.rb index 0415deb9f..df2ac40ef 100644 --- a/app/queries/admins/subject_query.rb +++ b/app/queries/admins/subject_query.rb @@ -40,7 +40,7 @@ class Admins::SubjectQuery < ApplicationQuery # 关键字 keyword = params[:keyword].to_s.strip if keyword - sql = 'CONCAT(lastname, firstname) LIKE :keyword OR subjects.name LIKE :keyword' + sql = 'CONCAT_WS(lastname, firstname, nickname) LIKE :keyword OR subjects.name LIKE :keyword' subjects = subjects.joins(:user).where(sql, keyword: "%#{keyword}%") end diff --git a/app/queries/admins/user_query.rb b/app/queries/admins/user_query.rb index cdf158c67..670eef58d 100644 --- a/app/queries/admins/user_query.rb +++ b/app/queries/admins/user_query.rb @@ -30,14 +30,14 @@ class Admins::UserQuery < ApplicationQuery # 关键字检索 keyword = params[:keyword].to_s.strip.presence if keyword - sql = 'CONCAT(lastname, firstname) LIKE :keyword OR login LIKE :keyword OR mail LIKE :keyword OR phone LIKE :keyword' + sql = 'CONCAT_WS(lastname, firstname, nickname) LIKE :keyword OR login LIKE :keyword OR mail LIKE :keyword OR phone LIKE :keyword' users = users.where(sql, keyword: "%#{keyword}%") end # 姓名 name = params[:name].to_s.strip.presence if name.present? - users = users.where('CONCAT(lastname, firstname) LIKE :name', name: "%#{name}%") + users = users.where('CONCAT_WS(lastname, firstname, nickname) LIKE :name', name: "%#{name}%") end # 单位ID diff --git a/app/queries/user_query.rb b/app/queries/user_query.rb index 326665fe9..f2964c7dc 100644 --- a/app/queries/user_query.rb +++ b/app/queries/user_query.rb @@ -10,7 +10,7 @@ class UserQuery < ApplicationQuery # 真实姓名 if name = strip_param(:name) - users = users.where('LOWER(CONCAT(users.lastname, users.firstname)) LIKE ?', "%#{name.downcase}%") + users = users.where('LOWER(CONCAT_WS(users.lastname, users.firstname, users.nickname)) LIKE ?', "%#{name.downcase}%") end # 单位名称 diff --git a/app/services/admins/import_user_service.rb b/app/services/admins/import_user_service.rb index f3408051b..298bf1e16 100644 --- a/app/services/admins/import_user_service.rb +++ b/app/services/admins/import_user_service.rb @@ -84,7 +84,7 @@ class Admins::ImportUserService < ApplicationService if data.identity.to_i == 1 users = users.where(user_extensions: { student_id: data.student_id }) else - users = users.where(user_extensions: { technical_title: data.technical_title }).where('CONCAT(users.lastname,users.firstname) = ?', data.name) + users = users.where(user_extensions: { technical_title: data.technical_title }).where('CONCAT_WS(users.lastname,users.firstname,users.nickname) = ?', data.name) end users.first From 02fe8a8966d8cdc895875bd5586fcd0c84c96f40 Mon Sep 17 00:00:00 2001 From: "vilet.yy" Date: Tue, 8 Jun 2021 11:51:46 +0800 Subject: [PATCH 49/51] add: user and platform cache --- .../users/statistics_controller.rb | 150 +++++------------- app/jobs/reset_platform_cache_job.rb | 14 ++ app/jobs/reset_user_cache_job.rb | 14 ++ app/models/application_record.rb | 8 + app/models/fork_user.rb | 8 + app/models/issue.rb | 7 +- app/models/praise_tread.rb | 43 +++-- app/models/project.rb | 11 +- app/models/pull_request.rb | 8 + app/models/watcher.rb | 28 +++- .../cache/platform_follow_count_service.rb | 41 +++++ .../cache/platform_issue_count_service.rb | 41 +++++ .../cache/platform_project_count_service.rb | 41 +++++ .../platform_project_fork_count_service.rb | 41 +++++ ...latform_project_languages_count_service.rb | 57 +++++++ .../platform_project_praises_count_service.rb | 41 +++++ ...platform_project_watchers_count_service.rb | 41 +++++ .../platform_pullrequest_count_service.rb | 41 +++++ .../cache/user_follow_count_service.rb | 43 +++++ .../cache/user_issue_count_service.rb | 43 +++++ .../cache/user_project_count_service.rb | 43 +++++ .../cache/user_project_fork_count_service.rb | 43 +++++ .../user_project_languages_count_service.rb | 60 +++++++ .../user_project_praises_count_service.rb | 43 +++++ .../user_project_watchers_count_service.rb | 43 +++++ .../cache/user_pullrequest_count_service.rb | 43 +++++ .../users/statistics/develop.json.jbuilder | 4 +- config/initializers/redis_cache.rb | 3 + config/sidekiq.yml | 1 + 29 files changed, 866 insertions(+), 138 deletions(-) create mode 100644 app/jobs/reset_platform_cache_job.rb create mode 100644 app/jobs/reset_user_cache_job.rb create mode 100644 app/services/cache/platform_follow_count_service.rb create mode 100644 app/services/cache/platform_issue_count_service.rb create mode 100644 app/services/cache/platform_project_count_service.rb create mode 100644 app/services/cache/platform_project_fork_count_service.rb create mode 100644 app/services/cache/platform_project_languages_count_service.rb create mode 100644 app/services/cache/platform_project_praises_count_service.rb create mode 100644 app/services/cache/platform_project_watchers_count_service.rb create mode 100644 app/services/cache/platform_pullrequest_count_service.rb create mode 100644 app/services/cache/user_follow_count_service.rb create mode 100644 app/services/cache/user_issue_count_service.rb create mode 100644 app/services/cache/user_project_count_service.rb create mode 100644 app/services/cache/user_project_fork_count_service.rb create mode 100644 app/services/cache/user_project_languages_count_service.rb create mode 100644 app/services/cache/user_project_praises_count_service.rb create mode 100644 app/services/cache/user_project_watchers_count_service.rb create mode 100644 app/services/cache/user_pullrequest_count_service.rb create mode 100644 config/initializers/redis_cache.rb diff --git a/app/controllers/users/statistics_controller.rb b/app/controllers/users/statistics_controller.rb index 255f0e948..c6cc0d889 100644 --- a/app/controllers/users/statistics_controller.rb +++ b/app/controllers/users/statistics_controller.rb @@ -85,19 +85,19 @@ class Users::StatisticsController < Users::BaseController for key in @project_languages_count.keys do @languages_percent[key] = (@project_languages_count[key].to_f / @project_languages_count.values.sum).round(2) end - @platform_languages_percent = Hash.new - for key in @platform_project_languages_count.keys do - @platform_languages_percent[key] = (@platform_project_languages_count[key].to_f / @platform_project_languages_count.values.sum).round(2) - end + # @platform_languages_percent = Hash.new + # for key in @platform_project_languages_count.keys do + # @platform_languages_percent[key] = (@platform_project_languages_count[key].to_f / @platform_project_languages_count.values.sum).round(2) + # end # 各门语言分数 @each_language_score = Hash.new for key in @project_languages_count.keys do @each_language_score[key] = (60.0 + @project_languages_count[key] / (@project_languages_count[key] + 5.0) * 40.0).to_i end - @platform_each_language_score = Hash.new - for key in @platform_project_languages_count.keys do - @platform_each_language_score[key] = (60.0 + @platform_project_languages_count[key] / (@platform_project_languages_count[key] + 5.0) * 40.0).to_i - end + # @platform_each_language_score = Hash.new + # for key in @platform_project_languages_count.keys do + # @platform_each_language_score[key] = (60.0 + @platform_project_languages_count[key] / (@platform_project_languages_count[key] + 5.0) * 40.0).to_i + # end end end @@ -164,124 +164,54 @@ class Users::StatisticsController < Users::BaseController def preload_develop_data if params[:start_time].present? && params[:end_time].present? # 用户被follow数量 - @follow_count = Rails.cache.fetch("user-follow-count-#{observed_user.id}-start:#{params[:start_time]}-end:#{params[:end_time]}-#{Watcher.where(watchable: observed_user).maximum('created_at').to_i}") do - time_filter(Watcher.where(watchable: observed_user), 'created_at').count - end - @platform_follow_count = Rails.cache.fetch("platform-follow-count-start:#{params[:start_time]}-end:#{params[:end_time]}-#{Watcher.where(watchable_type: 'User').maximum('created_at').to_i}") do - time_filter(Watcher.where(watchable_type: 'User'), 'created_at').count - end + @follow_count = time_filter(Watcher.where(watchable: observed_user), 'created_at').count + @platform_follow_count = time_filter(Watcher.where(watchable_type: 'User'), 'created_at').count # 用户pr数量 - @pullrequest_count = Rails.cache.fetch("user-pullrequest-count-#{observed_user.id}-start:#{params[:start_time]}-end:#{params[:end_time]}-#{PullRequest.where(user_id: observed_user.id).maximum('created_at').to_i}") do - time_filter(PullRequest.where(user_id: observed_user.id), 'created_at').count - end - @platform_pullrequest_count = Rails.cache.fetch("platform-pullrequest-count-start:#{params[:start_time]}-end:#{params[:end_time]}-#{PullRequest.maximum('created_at').to_i}") do - time_filter(PullRequest, 'created_at').count - end + @pullrequest_count = time_filter(PullRequest.where(user_id: observed_user.id), 'created_at').count + @platform_pullrequest_count = time_filter(PullRequest, 'created_at').count # 用户issue数量 - @issues_count = Rails.cache.fetch("user-issue-count-#{observed_user.id}-start:#{params[:start_time]}-end:#{params[:end_time]}-#{Issue.where(author_id: observed_user.id).maximum('created_on').to_i}") do - time_filter(Issue.where(author_id: observed_user.id), 'created_on').count - end - @platform_issues_count = Rails.cache.fetch("platform-issue-count-start:#{params[:start_time]}-end:#{params[:end_time]}-#{Issue.maximum('created_on').to_i}") do - time_filter(Issue, 'created_on').count - end + @issues_count = time_filter(Issue.where(author_id: observed_user.id), 'created_on').count + @platform_issues_count = time_filter(Issue, 'created_on').count # 用户总项目数 - @project_count = Rails.cache.fetch("user-project-count-#{observed_user.id}-start:#{params[:start_time]}-end:#{params[:end_time]}-#{Project.where(user_id:observed_user.id).maximum('created_on').to_i}") do - time_filter(Project.where(user_id:observed_user.id), 'created_on').count - end - @platform_project_count = Rails.cache.fetch("platform-project-count-start:#{params[:start_time]}-end:#{params[:end_time]}-#{Project.maximum('created_on').to_i}") do - time_filter(Project, 'created_on').count - end + @project_count = time_filter(Project.where(user_id:observed_user.id), 'created_on').count + @platform_project_count = time_filter(Project, 'created_on').count # 用户项目被fork数量 - @fork_count = Rails.cache.fetch("user-fork-count-#{observed_user.id}-start:#{params[:start_time]}-end:#{params[:end_time]}-#{ForkUser.joins(:project).where(projects: {user_id: observed_user.id}).maximum('created_at').to_i}") do - time_filter(Project.where(user_id:observed_user.id), 'created_on').sum("forked_count") - end - @platform_fork_count = Rails.cache.fetch("platform-fork-count-start:#{params[:start_time]}-end:#{params[:end_time]}-#{ForkUser.maximum('created_at').to_i}") do - time_filter(Project, 'created_on').sum("forked_count") - end - + @fork_count = time_filter(Project.where(user_id:observed_user.id), 'created_on').sum("forked_count") + @platform_fork_count = time_filter(Project, 'created_on').sum("forked_count") # 用户项目关注数 - @project_watchers_count = Rails.cache.fetch("user-watchers-count-start:#{params[:start_time]}-end:#{params[:end_time]}-#{observed_user.id}-#{Watcher.where(watchable_type: 'Project', watchable_id: observed_user.projects).maximum('created_at').to_i}") do - time_filter(Project.where(user_id: observed_user.id), 'created_on').sum("watchers_count") - end - @platform_project_watchers_count = Rails.cache.fetch("platform-watchers-count-start:#{params[:start_time]}-end:#{params[:end_time]}-#{Watcher.where(watchable_type: 'Project').maximum('created_at').to_i}") do - time_filter(Project, 'created_on').sum("watchers_count") - end - + @project_watchers_count = time_filter(Project.where(user_id: observed_user.id), 'created_on').sum("watchers_count") + @platform_project_watchers_count = time_filter(Project, 'created_on').sum("watchers_count") # 用户项目点赞数 - @project_praises_count = Rails.cache.fetch("user-praises-count-#{observed_user.id}-start:#{params[:start_time]}-end:#{params[:end_time]}-#{PraiseTread.where(praise_tread_object_type: 'Project', praise_tread_object_id: observed_user.projects).maximum('created_at').to_i}") do - time_filter(Project.where(user_id: observed_user.id), 'created_on').sum("praises_count") - end - @platform_project_praises_count = Rails.cache.fetch("user-praises-count-#{observed_user.id}-start:#{params[:start_time]}-end:#{params[:end_time]}-#{PraiseTread.where(praise_tread_object_type: 'Project', praise_tread_object_id: observed_user.projects).maximum('created_at').to_i}") do - time_filter(Project, 'created_on').sum("praises_count") - end - + @project_praises_count = time_filter(Project.where(user_id: observed_user.id), 'created_on').sum("praises_count") + @platform_project_praises_count = time_filter(Project, 'created_on').sum("praises_count") # 用户不同语言项目数量 - @project_languages_count = Rails.cache.fetch("user-languages-count-#{observed_user.id}-start:#{params[:start_time]}-end:#{params[:end_time]}-#{Project.where(user_id:observed_user.id).maximum('created_on').to_i}") do - time_filter(Project.where(user_id: observed_user.id), 'created_on').joins(:project_language).group("project_languages.name").count - end - @platform_project_languages_count = Rails.cache.fetch("platform-languages-count-start:#{params[:start_time]}-end:#{params[:end_time]}-#{Project.maximum('created_on').to_i}") do - time_filter(Project, 'created_on').joins(:project_language).group("project_languages.name").count - end + @project_languages_count = time_filter(Project.where(user_id: observed_user.id), 'created_on').joins(:project_language).group("project_languages.name").count + @platform_project_languages_count = time_filter(Project, 'created_on').joins(:project_language).group("project_languages.name").count else # 用户被follow数量 - @follow_count = Rails.cache.fetch("user-follow-count-#{observed_user.id}-#{Watcher.where(watchable: observed_user).maximum('created_at').to_i}") do - time_filter(Watcher.where(watchable: observed_user), 'created_at').count - end - @platform_follow_count = Rails.cache.fetch("platform-follow-count-#{Watcher.where(watchable_type: 'User').maximum('created_at').to_i}") do - time_filter(Watcher.where(watchable_type: 'User'), 'created_at').count - end + @follow_count = Cache::UserFollowCountService.call(observed_user) + @platform_follow_count = Cache::PlatformFollowCountService.call # 用户pr数量 - @pullrequest_count = Rails.cache.fetch("user-pullrequest-count-#{observed_user.id}-#{PullRequest.where(user_id: observed_user.id).maximum('created_at').to_i}") do - time_filter(PullRequest.where(user_id: observed_user.id), 'created_at').count - end - @platform_pullrequest_count = Rails.cache.fetch("platform-pullrequest-count-#{PullRequest.maximum('created_at').to_i}") do - time_filter(PullRequest, 'created_at').count - end + @pullrequest_count = Cache::UserPullrequestCountService.call(observed_user) + @platform_pullrequest_count = Cache::PlatformPullrequestCountService.call # 用户issue数量 - @issues_count = Rails.cache.fetch("user-issue-count-#{observed_user.id}-#{Issue.where(author_id: observed_user.id).maximum('created_on').to_i}") do - time_filter(Issue.where(author_id: observed_user.id), 'created_on').count - end - @platform_issues_count = Rails.cache.fetch("platform-issue-count-#{Issue.maximum('created_on').to_i}") do - time_filter(Issue, 'created_on').count - end + @issues_count = Cache::UserIssueCountService.call(observed_user) + @platform_issues_count = Cache::PlatformIssueCountService.call # 用户总项目数 - @project_count = Rails.cache.fetch("user-project-count-#{observed_user.id}-#{Project.where(user_id:observed_user.id).maximum('created_on').to_i}") do - time_filter(Project.where(user_id:observed_user.id), 'created_on').count - end - @platform_project_count = Rails.cache.fetch("platform-project-count-#{Project.maximum('created_on').to_i}") do - time_filter(Project, 'created_on').count - end + @project_count = Cache::UserProjectCountService.call(observed_user) + @platform_project_count = Cache::PlatformProjectCountService.call # 用户项目被fork数量 - @fork_count = Rails.cache.fetch("user-fork-count-#{observed_user.id}-#{ForkUser.joins(:project).where(projects: {user_id: observed_user.id}).maximum('created_at').to_i}") do - time_filter(Project.where(user_id:observed_user.id), 'created_on').sum("forked_count") - end - @platform_fork_count = Rails.cache.fetch("platform-fork-count-#{ForkUser.maximum('created_at').to_i}") do - time_filter(Project, 'created_on').sum("forked_count") - end - + @fork_count = Cache::UserProjectForkCountService.call(observed_user) + @platform_fork_count = Cache::PlatformProjectForkCountService.call # 用户项目关注数 - @project_watchers_count = Rails.cache.fetch("user-watchers-count-#{observed_user.id}-#{Watcher.where(watchable_type: 'Project', watchable_id: observed_user.projects).maximum('created_at').to_i}") do - time_filter(Project.where(user_id: observed_user.id), 'created_on').sum("watchers_count") - end - @platform_project_watchers_count = Rails.cache.fetch("platform-watchers-count-#{Watcher.where(watchable_type: 'Project').maximum('created_at').to_i}") do - time_filter(Project, 'created_on').sum("watchers_count") - end - + @project_watchers_count = Cache::UserProjectWatchersCountService.call(observed_user) + @platform_project_watchers_count = Cache::PlatformProjectWatchersCountService.call # 用户项目点赞数 - @project_praises_count = Rails.cache.fetch("user-praises-count-#{observed_user.id}-#{PraiseTread.where(praise_tread_object_type: 'Project', praise_tread_object_id: observed_user.projects).maximum('created_at').to_i}") do - time_filter(Project.where(user_id: observed_user.id), 'created_on').sum("praises_count") - end - @platform_project_praises_count = Rails.cache.fetch("user-praises-count-#{observed_user.id}-#{PraiseTread.where(praise_tread_object_type: 'Project', praise_tread_object_id: observed_user.projects).maximum('created_at').to_i}") do - time_filter(Project, 'created_on').sum("praises_count") - end - + @project_praises_count = Cache::UserProjectPraisesCountService.call(observed_user) + @platform_project_praises_count = Cache::PlatformProjectPraisesCountService.call # 用户不同语言项目数量 - @project_languages_count = Rails.cache.fetch("user-languages-count-#{observed_user.id}-#{Project.where(user_id:observed_user.id).maximum('created_on').to_i}") do - time_filter(Project.where(user_id: observed_user.id), 'created_on').joins(:project_language).group("project_languages.name").count - end - @platform_project_languages_count = Rails.cache.fetch("platform-languages-count-#{Project.maximum('created_on').to_i}") do - time_filter(Project, 'created_on').joins(:project_language).group("project_languages.name").count - end + @project_languages_count = Cache::UserProjectLanguagesCountService.call(observed_user) + @platform_project_languages_count = Cache::PlatformProjectLanguagesCountService.call end end end \ No newline at end of file diff --git a/app/jobs/reset_platform_cache_job.rb b/app/jobs/reset_platform_cache_job.rb new file mode 100644 index 000000000..bdc5b6aaa --- /dev/null +++ b/app/jobs/reset_platform_cache_job.rb @@ -0,0 +1,14 @@ +class ResetPlatformCacheJob < ApplicationJob + queue_as :cache + + def perform + Cache::PlatformFollowCountService.new.reset + Cache::PlatformIssueCountService.new.reset + Cache::PlatformProjectCountService.new.reset + Cache::PlatformProjectForkCountService.new.reset + Cache::PlatformProjectLanguagesCountService.new.reset + Cache::PlatformProjectPraisesCountService.new.reset + Cache::PlatformProjectWatchersCountService.new.reset + Cache::PlatformPullrequestCountService.new.reset + end +end \ No newline at end of file diff --git a/app/jobs/reset_user_cache_job.rb b/app/jobs/reset_user_cache_job.rb new file mode 100644 index 000000000..3562475ce --- /dev/null +++ b/app/jobs/reset_user_cache_job.rb @@ -0,0 +1,14 @@ +class ResetUserCacheJob < ApplicationJob + queue_as :cache + + def perform(user) + Cache::UserFollowCountService.new(user).reset + Cache::UserIssueCountService.new(user).reset + Cache::UserProjectCountService.new(user).reset + Cache::UserProjectForkCountService.new(user).reset + Cache::UserProjectLanguagesCountService.new(user).reset + Cache::UserProjectPraisesCountService.new(user).reset + Cache::UserProjectWatchersCountService.new(user).reset + Cache::UserPullrequestCountService.new(user).reset + end +end \ No newline at end of file diff --git a/app/models/application_record.rb b/app/models/application_record.rb index 888c65423..3ab2b11e8 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -16,4 +16,12 @@ class ApplicationRecord < ActiveRecord::Base def allow_sync_to_trustie? Rails.env.production? && EduSetting.get('host_name') == 'https://www.educoder.net' end + + def reset_user_cache_async_job(user) + ResetUserCacheJob.perform_later(user) + end + + def reset_platform_cache_async_job + ResetPlatformCacheJob.perform_later + end end diff --git a/app/models/fork_user.rb b/app/models/fork_user.rb index d0915f152..0936f6bfa 100644 --- a/app/models/fork_user.rb +++ b/app/models/fork_user.rb @@ -20,4 +20,12 @@ class ForkUser < ApplicationRecord belongs_to :user belongs_to :fork_project, class_name: 'Project', foreign_key: :fork_project_id + after_save :reset_cache_data + after_destroy :reset_cache_data + + def reset_cache_data + self.reset_platform_cache_async_job + self.reset_user_cache_async_job(self.project.owner) + end + end diff --git a/app/models/issue.rb b/app/models/issue.rb index 58607ebdd..b43f5a3d2 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -76,8 +76,13 @@ class Issue < ApplicationRecord scope :issue_index_includes, ->{includes(:tracker, :priority, :version, :issue_status, :journals,:issue_tags,user: :user_extension)} after_update :change_versions_count - after_destroy :update_closed_issues_count_in_project! + after_save :reset_cache_data + after_destroy :update_closed_issues_count_in_project!, :reset_cache_data + def reset_cache_data + self.reset_platform_cache_async_job + self.reset_user_cache_async_job(self.user) + end def get_assign_user User&.find_by_id(self.assigned_to_id) if self.assigned_to_id.present? diff --git a/app/models/praise_tread.rb b/app/models/praise_tread.rb index d13c17ddd..04008eaf6 100644 --- a/app/models/praise_tread.rb +++ b/app/models/praise_tread.rb @@ -1,26 +1,35 @@ -# == Schema Information -# -# Table name: praise_treads -# -# id :integer not null, primary key -# user_id :integer not null -# praise_tread_object_id :integer -# praise_tread_object_type :string(255) -# praise_or_tread :integer default("1") -# created_at :datetime not null -# updated_at :datetime not null -# -# Indexes -# -# praise_tread (praise_tread_object_id,praise_tread_object_type) -# - +# == Schema Information +# +# Table name: praise_treads +# +# id :integer not null, primary key +# user_id :integer not null +# praise_tread_object_id :integer +# praise_tread_object_type :string(255) +# praise_or_tread :integer default("1") +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# praise_tread (praise_tread_object_id,praise_tread_object_type) +# + class PraiseTread < ApplicationRecord belongs_to :user belongs_to :praise_tread_object, polymorphic: true, counter_cache: :praises_count has_many :tidings, :as => :container, :dependent => :destroy after_create :send_tiding + after_save :reset_cache_data + after_destroy :reset_cache_data + + def reset_cache_data + self.reset_platform_cache_async_job + if self.praise_tread_object.is_a?(Project) + self.reset_user_cache_async_job(self.praise_tread_object&.owner) + end + end def send_tiding case self.praise_tread_object_type diff --git a/app/models/project.rb b/app/models/project.rb index f41e980d7..b61f05689 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -105,7 +105,8 @@ class Project < ApplicationRecord has_many :pinned_projects, dependent: :destroy has_many :has_pinned_users, through: :pinned_projects, source: :user - after_save :check_project_members + after_save :check_project_members, :reset_cache_data + after_destroy :reset_cache_data scope :project_statics_select, -> {select(:id,:name, :is_public, :identifier, :status, :project_type, :user_id, :forked_count, :visits, :project_category_id, :project_language_id, :license_id, :ignore_id, :watchers_count, :created_on)} scope :no_anomory_projects, -> {where("projects.user_id is not null and projects.user_id != ?", 2)} scope :recommend, -> { visible.project_statics_select.where(recommend: true) } @@ -113,6 +114,14 @@ class Project < ApplicationRecord delegate :content, to: :project_detail, allow_nil: true delegate :name, to: :license, prefix: true, allow_nil: true + def reset_cache_data + if changes[:user_id].present? + first_owner = Owner.find_by_id(changes[:user_id].first) + self.reset_user_cache_async_job(first_owner) + end + self.reset_platform_cache_async_job + self.reset_user_cache_async_job(self.owner) + end def self.search_project(search) ransack(name_or_identifier_cont: search) diff --git a/app/models/pull_request.rb b/app/models/pull_request.rb index c3eefb0db..97f4a9164 100644 --- a/app/models/pull_request.rb +++ b/app/models/pull_request.rb @@ -33,6 +33,14 @@ class PullRequest < ApplicationRecord has_many :project_trends, as: :trend, dependent: :destroy has_many :attachments, as: :container, dependent: :destroy + after_save :reset_cache_data + after_destroy :reset_cache_data + + def reset_cache_data + self.reset_platform_cache_async_job + self.reset_user_cache_async_job(self.user) + end + def fork_project Project.find_by(id: self.fork_project_id) end diff --git a/app/models/watcher.rb b/app/models/watcher.rb index 76a82702b..ccc8eefaa 100644 --- a/app/models/watcher.rb +++ b/app/models/watcher.rb @@ -15,10 +15,24 @@ # watchers_user_id_type (user_id,watchable_type) # -class Watcher < ApplicationRecord - belongs_to :user - - belongs_to :watchable, polymorphic: true, counter_cache: :watchers_count - - scope :watching_users, ->(watchable_id){ where("watchable_type = ? and user_id = ?",'User',watchable_id)} -end +class Watcher < ApplicationRecord + belongs_to :user + + belongs_to :watchable, polymorphic: true, counter_cache: :watchers_count + + scope :watching_users, ->(watchable_id){ where("watchable_type = ? and user_id = ?",'User',watchable_id)} + + after_save :reset_cache_data + after_destroy :reset_cache_data + + def reset_cache_data + if self.watchable.is_a?(User) + self.reset_user_cache_async_job(self.watchable) + end + if self.watchable.is_a?(Project) + self.reset_user_cache_async_job(self.watchable&.owner) + end + self.reset_platform_cache_async_job + end + +end diff --git a/app/services/cache/platform_follow_count_service.rb b/app/services/cache/platform_follow_count_service.rb new file mode 100644 index 000000000..5398da5a8 --- /dev/null +++ b/app/services/cache/platform_follow_count_service.rb @@ -0,0 +1,41 @@ +class Cache::PlatformFollowCountService < ApplicationService + attr_reader :increment_count + + def initialize(increment_count=0) + @increment_count = increment_count + end + + def call + set_platform_follow_count + + platform_follow_count + end + + def reset + reset_platform_follow_count + + platform_follow_count + end + + private + + def platform_follow_count_key + "platform-follow-count" + end + + def platform_follow_count + $redis_cache.get(platform_follow_count_key).to_i + end + + def set_platform_follow_count + if $redis_cache.exists(platform_follow_count_key) + $redis_cache.incrby(platform_follow_count_key, increment_count) + else + reset_platform_follow_count + end + end + + def reset_platform_follow_count + $redis_cache.set(platform_follow_count_key, Watcher.where(watchable_type: 'User').count) + end +end \ No newline at end of file diff --git a/app/services/cache/platform_issue_count_service.rb b/app/services/cache/platform_issue_count_service.rb new file mode 100644 index 000000000..95511f480 --- /dev/null +++ b/app/services/cache/platform_issue_count_service.rb @@ -0,0 +1,41 @@ +class Cache::PlatformIssueCountService < ApplicationService + attr_reader :increment_count + + def initialize(increment_count=0) + @increment_count = increment_count + end + + def call + set_platform_issue_count + + platform_issue_count + end + + def reset + reset_platform_issue_count + + platform_issue_count + end + + private + + def platform_issue_count_key + "platform-issue-count" + end + + def platform_issue_count + $redis_cache.get(platform_issue_count_key).to_i + end + + def set_platform_issue_count + if $redis_cache.exists(platform_issue_count_key) + $redis_cache.incrby(platform_issue_count_key, increment_count) + else + reset_platform_issue_count + end + end + + def reset_platform_issue_count + $redis_cache.set(platform_issue_count_key, Issue.count) + end +end \ No newline at end of file diff --git a/app/services/cache/platform_project_count_service.rb b/app/services/cache/platform_project_count_service.rb new file mode 100644 index 000000000..d807682f1 --- /dev/null +++ b/app/services/cache/platform_project_count_service.rb @@ -0,0 +1,41 @@ +class Cache::PlatformProjectCountService < ApplicationService + attr_reader :increment_count + + def initialize(increment_count=0) + @increment_count = increment_count + end + + def call + set_platform_project_count + + platform_project_count + end + + def reset + reset_platform_project_count + + platform_project_count + end + + private + + def platform_project_count_key + "platform-project-count" + end + + def platform_project_count + $redis_cache.get(platform_project_count_key).to_i + end + + def set_platform_project_count + if $redis_cache.exists(platform_project_count_key) + $redis_cache.incrby(platform_project_count_key, increment_count) + else + reset_platform_project_count + end + end + + def reset_platform_project_count + $redis_cache.set(platform_project_count_key, Project.count) + end +end \ No newline at end of file diff --git a/app/services/cache/platform_project_fork_count_service.rb b/app/services/cache/platform_project_fork_count_service.rb new file mode 100644 index 000000000..21d6c0636 --- /dev/null +++ b/app/services/cache/platform_project_fork_count_service.rb @@ -0,0 +1,41 @@ +class Cache::PlatformProjectForkCountService < ApplicationService + attr_reader :increment_count + + def initialize(increment_count=0) + @increment_count = increment_count + end + + def call + set_platform_project_fork_count + + platform_project_fork_count + end + + def reset + reset_platform_project_fork_count + + platform_project_fork_count + end + + private + + def platform_project_fork_count_key + "platform-project-fork-count" + end + + def platform_project_fork_count + $redis_cache.get(platform_project_fork_count_key).to_i + end + + def set_platform_project_fork_count + if $redis_cache.exists(platform_project_fork_count_key) + $redis_cache.incrby(platform_project_fork_count_key, increment_count) + else + reset_platform_project_fork_count + end + end + + def reset_platform_project_fork_count + $redis_cache.set(platform_project_fork_count_key, ForkUser.count) + end +end \ No newline at end of file diff --git a/app/services/cache/platform_project_languages_count_service.rb b/app/services/cache/platform_project_languages_count_service.rb new file mode 100644 index 000000000..2b4f0fae4 --- /dev/null +++ b/app/services/cache/platform_project_languages_count_service.rb @@ -0,0 +1,57 @@ +class Cache::PlatformProjectLanguagesCountService < ApplicationService + attr_reader :key, :increment_count + + def initialize(key=nil, increment_count=0) + @key = key + @increment_count = increment_count + end + + def call + set_platform_project_language_count + + platform_project_language_count + end + + def reset_by_key + reset_platform_project_language_count_by_key + + platform_project_language_count + end + + def reset + reset_platform_project_language_count + + platform_project_language_count + end + + private + + def platform_project_language_count_key + "platform-project-language-count" + end + + def platform_project_language_count + $redis_cache.hgetall(platform_project_language_count_key).transform_values(&:to_i) + end + + def set_platform_project_language_count + if $redis_cache.hlen(platform_project_language_count_key) == 0 + reset_platform_project_language_count + elsif $redis_cache.hget(platform_project_language_count_key, key).nil? + reset_platform_project_language_count_by_key + else + $redis_cache.hincrby(platform_project_language_count_key, key, increment_count) + end + end + + def reset_platform_project_language_count_by_key + return if key.nil? + $redis_cache.hset(platform_project_language_count_key, key, Project.joins(:project_language).where(project_languages: {name: key}).count) + end + + def reset_platform_project_language_count + Project.joins(:project_language).group("project_languages.name").count.each do |k, v| + $redis_cache.hset(platform_project_language_count_key, k, v) + end + end +end \ No newline at end of file diff --git a/app/services/cache/platform_project_praises_count_service.rb b/app/services/cache/platform_project_praises_count_service.rb new file mode 100644 index 000000000..6c78b8022 --- /dev/null +++ b/app/services/cache/platform_project_praises_count_service.rb @@ -0,0 +1,41 @@ +class Cache::PlatformProjectPraisesCountService < ApplicationService + attr_reader :increment_count + + def initialize(increment_count=0) + @increment_count = increment_count + end + + def call + set_platform_project_praises_count + + platform_project_praises_count + end + + def reset + reset_platform_project_praises_count + + platform_project_praises_count + end + + private + + def platform_project_praises_count_key + "platform-project-praises-count" + end + + def platform_project_praises_count + $redis_cache.get(platform_project_praises_count_key).to_i + end + + def set_platform_project_praises_count + if $redis_cache.exists(platform_project_praises_count_key) + $redis_cache.incrby(platform_project_praises_count_key, increment_count) + else + reset_platform_project_praises_count + end + end + + def reset_platform_project_praises_count + $redis_cache.set(platform_project_praises_count_key, PraiseTread.where(praise_tread_object_type: "Project").count) + end +end \ No newline at end of file diff --git a/app/services/cache/platform_project_watchers_count_service.rb b/app/services/cache/platform_project_watchers_count_service.rb new file mode 100644 index 000000000..70c834d2e --- /dev/null +++ b/app/services/cache/platform_project_watchers_count_service.rb @@ -0,0 +1,41 @@ +class Cache::PlatformProjectWatchersCountService < ApplicationService + attr_reader :increment_count + + def initialize(increment_count=0) + @increment_count = increment_count + end + + def call + set_platform_project_watchers_count + + platform_project_watchers_count + end + + def reset + reset_platform_project_watchers_count + + platform_project_watchers_count + end + + private + + def platform_project_watchers_count_key + "platform-project-watchers-count" + end + + def platform_project_watchers_count + $redis_cache.get(platform_project_watchers_count_key).to_i + end + + def set_platform_project_watchers_count + if $redis_cache.exists(platform_project_watchers_count_key) + $redis_cache.incrby(platform_project_watchers_count_key, increment_count) + else + reset_platform_project_watchers_count + end + end + + def reset_platform_project_watchers_count + $redis_cache.set(platform_project_watchers_count_key, Watcher.where(watchable_type: 'Project').count) + end +end \ No newline at end of file diff --git a/app/services/cache/platform_pullrequest_count_service.rb b/app/services/cache/platform_pullrequest_count_service.rb new file mode 100644 index 000000000..c497c488a --- /dev/null +++ b/app/services/cache/platform_pullrequest_count_service.rb @@ -0,0 +1,41 @@ +class Cache::PlatformPullrequestCountService < ApplicationService + attr_reader :increment_count + + def initialize(increment_count=0) + @increment_count = increment_count + end + + def call + set_platform_pullrequest_count + + platform_pullrequest_count + end + + def reset + reset_platform_pullrequest_count + + platform_pullrequest_count + end + + private + + def platform_pullrequest_count_key + "platform-pullrequest-count" + end + + def platform_pullrequest_count + $redis_cache.get(platform_pullrequest_count_key).to_i + end + + def set_platform_pullrequest_count + if $redis_cache.exists(platform_pullrequest_count_key) + $redis_cache.incrby(platform_pullrequest_count_key, increment_count) + else + reset_platform_pullrequest_count + end + end + + def reset_platform_pullrequest_count + $redis_cache.set(platform_pullrequest_count_key, PullRequest.count) + end +end \ No newline at end of file diff --git a/app/services/cache/user_follow_count_service.rb b/app/services/cache/user_follow_count_service.rb new file mode 100644 index 000000000..c583c32b6 --- /dev/null +++ b/app/services/cache/user_follow_count_service.rb @@ -0,0 +1,43 @@ +class Cache::UserFollowCountService < ApplicationService + attr_reader :user, :increment_count + + def initialize(user, increment_count=0) + @user = user + @increment_count = increment_count + end + + def call + set_user_follow_count + + user_follow_count + end + + def reset + reset_user_follow_count + + user_follow_count + end + + private + + def user_follow_count_key + "user-follow-count-#{user.id}" + end + + def user_follow_count + $redis_cache.get(user_follow_count_key).to_i + end + + def set_user_follow_count + if $redis_cache.exists(user_follow_count_key) + $redis_cache.incrby(user_follow_count_key, increment_count) + else + reset_user_follow_count + end + end + + def reset_user_follow_count + return if user.nil? + $redis_cache.set(user_follow_count_key, Watcher.where(watchable: user).count) + end +end \ No newline at end of file diff --git a/app/services/cache/user_issue_count_service.rb b/app/services/cache/user_issue_count_service.rb new file mode 100644 index 000000000..9e5f2d491 --- /dev/null +++ b/app/services/cache/user_issue_count_service.rb @@ -0,0 +1,43 @@ +class Cache::UserIssueCountService < ApplicationService + attr_reader :user, :increment_count + + def initialize(user, increment_count=0) + @user = user + @increment_count = increment_count + end + + def call + set_user_issue_count + + user_issue_count + end + + def reset + reset_user_issue_count + + user_issue_count + end + + private + + def user_issue_count_key + "user-issue-count-#{user.id}" + end + + def user_issue_count + $redis_cache.get(user_issue_count_key).to_i + end + + def set_user_issue_count + if $redis_cache.exists(user_issue_count_key) + $redis_cache.incrby(user_issue_count_key, increment_count) + else + reset_user_issue_count + end + end + + def reset_user_issue_count + return if user.nil? + $redis_cache.set(user_issue_count_key, Issue.where(author_id: user.id).count) + end +end \ No newline at end of file diff --git a/app/services/cache/user_project_count_service.rb b/app/services/cache/user_project_count_service.rb new file mode 100644 index 000000000..677184161 --- /dev/null +++ b/app/services/cache/user_project_count_service.rb @@ -0,0 +1,43 @@ +class Cache::UserProjectCountService < ApplicationService + attr_reader :user, :increment_count + + def initialize(user, increment_count=0) + @user = user + @increment_count = increment_count + end + + def call + set_user_project_count + + user_project_count + end + + def reset + reset_user_project_count + + user_project_count + end + + private + + def user_project_count_key + "user-project-count-#{user.id}" + end + + def user_project_count + $redis_cache.get(user_project_count_key).to_i + end + + def set_user_project_count + if $redis_cache.exists(user_project_count_key) + $redis_cache.incrby(user_project_count_key, increment_count) + else + reset_user_project_count + end + end + + def reset_user_project_count + return if user.nil? + $redis_cache.set(user_project_count_key, user.projects.count) + end +end \ No newline at end of file diff --git a/app/services/cache/user_project_fork_count_service.rb b/app/services/cache/user_project_fork_count_service.rb new file mode 100644 index 000000000..134e4ed65 --- /dev/null +++ b/app/services/cache/user_project_fork_count_service.rb @@ -0,0 +1,43 @@ +class Cache::UserProjectForkCountService < ApplicationService + attr_reader :user, :increment_count + + def initialize(user, increment_count=0) + @user = user + @increment_count = increment_count + end + + def call + set_user_project_fork_count + + user_project_fork_count + end + + def reset + reset_user_project_fork_count + + user_project_fork_count + end + + private + + def user_project_fork_count_key + "user-project-fork-count-#{user.id}" + end + + def user_project_fork_count + $redis_cache.get(user_project_fork_count_key).to_i + end + + def set_user_project_fork_count + if $redis_cache.exists(user_project_fork_count_key) + $redis_cache.incrby(user_project_fork_count_key, increment_count) + else + reset_user_project_fork_count + end + end + + def reset_user_project_fork_count + return if user.nil? + $redis_cache.set(user_project_fork_count_key, ForkUser.joins(:project).where(projects: {user_id: user.id}).count) + end +end \ No newline at end of file diff --git a/app/services/cache/user_project_languages_count_service.rb b/app/services/cache/user_project_languages_count_service.rb new file mode 100644 index 000000000..35b8a418e --- /dev/null +++ b/app/services/cache/user_project_languages_count_service.rb @@ -0,0 +1,60 @@ +class Cache::UserProjectLanguagesCountService < ApplicationService + attr_reader :user, :key, :increment_count + + def initialize(user, key=nil, increment_count=0) + @user = user + @key = key + @increment_count = increment_count + end + + def call + set_user_project_language_count + + user_project_language_count + end + + def reset_by_key + reset_user_project_language_count_by_key + + user_project_language_count + end + + def reset + reset_user_project_language_count + + user_project_language_count + end + + private + + def user_project_language_count_key + "user-project-language-count-#{user.id}" + end + + def user_project_language_count + $redis_cache.hgetall(user_project_language_count_key).transform_values(&:to_i) + end + + def set_user_project_language_count + if $redis_cache.hlen(user_project_language_count_key) == 0 + reset_user_project_language_count + elsif $redis_cache.hget(user_project_language_count_key, key).nil? + reset_user_project_language_count_by_key + else + $redis_cache.hincrby(user_project_language_count_key, key, increment_count) + end + end + + def reset_user_project_language_count_by_key + return if user.nil? + return if key.nil? + $redis_cache.hset(user_project_language_count_key, key, user.projects.joins(:project_language).where(project_languages: {name: key}).count) + end + + def reset_user_project_language_count + return if user.nil? + user.projects.joins(:project_language).group("project_languages.name").count.each do |k, v| + $redis_cache.hset(user_project_language_count_key, k, v) + end + end +end \ No newline at end of file diff --git a/app/services/cache/user_project_praises_count_service.rb b/app/services/cache/user_project_praises_count_service.rb new file mode 100644 index 000000000..0c7d49e3c --- /dev/null +++ b/app/services/cache/user_project_praises_count_service.rb @@ -0,0 +1,43 @@ +class Cache::UserProjectPraisesCountService < ApplicationService + attr_reader :user, :increment_count + + def initialize(user, increment_count=0) + @user = user + @increment_count = increment_count + end + + def call + set_user_project_praises_count + + user_project_praises_count + end + + def reset + reset_user_project_praises_count + + user_project_praises_count + end + + private + + def user_project_praises_count_key + "user-project-praises-count-#{user.id}" + end + + def user_project_praises_count + $redis_cache.get(user_project_praises_count_key).to_i + end + + def set_user_project_praises_count + if $redis_cache.exists(user_project_praises_count_key) + $redis_cache.incrby(user_project_praises_count_key, increment_count) + else + reset_user_project_praises_count + end + end + + def reset_user_project_praises_count + return if user.nil? + $redis_cache.set(user_project_praises_count_key, PraiseTread.where(praise_tread_object_type: 'Project', praise_tread_object_id: user.projects).count) + end +end \ No newline at end of file diff --git a/app/services/cache/user_project_watchers_count_service.rb b/app/services/cache/user_project_watchers_count_service.rb new file mode 100644 index 000000000..50733cad7 --- /dev/null +++ b/app/services/cache/user_project_watchers_count_service.rb @@ -0,0 +1,43 @@ +class Cache::UserProjectWatchersCountService < ApplicationService + attr_reader :user, :increment_count + + def initialize(user, increment_count=0) + @user = user + @increment_count = increment_count + end + + def call + set_user_project_watchers_count + + user_project_watchers_count + end + + def reset + reset_user_project_watchers_count + + user_project_watchers_count + end + + private + + def user_project_watchers_count_key + "user-project-watchers-count-#{user.id}" + end + + def user_project_watchers_count + $redis_cache.get(user_project_watchers_count_key).to_i + end + + def set_user_project_watchers_count + if $redis_cache.exists(user_project_watchers_count_key) + $redis_cache.incrby(user_project_watchers_count_key, increment_count) + else + reset_user_project_watchers_count + end + end + + def reset_user_project_watchers_count + return if user.nil? + $redis_cache.set(user_project_watchers_count_key, Watcher.where(watchable_type: 'Project', watchable_id: user.projects).count) + end +end \ No newline at end of file diff --git a/app/services/cache/user_pullrequest_count_service.rb b/app/services/cache/user_pullrequest_count_service.rb new file mode 100644 index 000000000..da478b2af --- /dev/null +++ b/app/services/cache/user_pullrequest_count_service.rb @@ -0,0 +1,43 @@ +class Cache::UserPullrequestCountService < ApplicationService + attr_reader :user, :increment_count + + def initialize(user, increment_count=0) + @user = user + @increment_count = increment_count + end + + def call + set_user_pullrequest_count + + user_pullrequest_count + end + + def reset + reset_user_pullrequest_count + + user_pullrequest_count + end + + private + + def user_pullrequest_count_key + "user-pullrequest-count-#{user.id}" + end + + def user_pullrequest_count + $redis_cache.get(user_pullrequest_count_key).to_i + end + + def set_user_pullrequest_count + if $redis_cache.exists(user_pullrequest_count_key) + $redis_cache.incrby(user_pullrequest_count_key, increment_count) + else + reset_user_pullrequest_count + end + end + + def reset_user_pullrequest_count + return if user.nil? + $redis_cache.set(user_pullrequest_count_key, PullRequest.where(user_id: user.id).count) + end +end \ No newline at end of file diff --git a/app/views/users/statistics/develop.json.jbuilder b/app/views/users/statistics/develop.json.jbuilder index 9d530fbbe..85f66f5c9 100644 --- a/app/views/users/statistics/develop.json.jbuilder +++ b/app/views/users/statistics/develop.json.jbuilder @@ -4,8 +4,8 @@ json.platform do json.activity @platform_activity json.experience @platform_experience json.language @platform_language - json.languages_percent @platform_languages_percent - json.each_language_score @platform_each_language_score + # json.languages_percent @platform_languages_percent + # json.each_language_score @platform_each_language_score end json.user do diff --git a/config/initializers/redis_cache.rb b/config/initializers/redis_cache.rb new file mode 100644 index 000000000..67f52ec7b --- /dev/null +++ b/config/initializers/redis_cache.rb @@ -0,0 +1,3 @@ +redis_config = Rails.application.config_for(:redis) +cache_url = redis_config["url"] || 'redis://localhost:6379' +$redis_cache = Redis.new(url: cache_url, db: 2) \ No newline at end of file diff --git a/config/sidekiq.yml b/config/sidekiq.yml index dda6a32eb..a50c1c1aa 100644 --- a/config/sidekiq.yml +++ b/config/sidekiq.yml @@ -7,3 +7,4 @@ - [searchkick, 10] - [notify, 100] - [mailers, 101] + - [cache, 10] From 39acaa7f217079071c084f07d9d8da4e74ef3344 Mon Sep 17 00:00:00 2001 From: jasder Date: Tue, 8 Jun 2021 14:34:03 +0800 Subject: [PATCH 50/51] =?UTF-8?q?FIX=20=E8=A7=A3=E5=86=B3=E5=A4=B4?= =?UTF-8?q?=E6=AD=8C=E7=89=88=E6=9C=AC=E5=BA=93=E6=97=A0=E6=B3=95=E8=AE=BF?= =?UTF-8?q?=E9=97=AE=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/views/repositories/detail.json.jbuilder | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/repositories/detail.json.jbuilder b/app/views/repositories/detail.json.jbuilder index 39f2563a4..3cf3858d6 100644 --- a/app/views/repositories/detail.json.jbuilder +++ b/app/views/repositories/detail.json.jbuilder @@ -48,7 +48,7 @@ if @result[:repo] json.size replace_bytes_to_b(number_to_human_size(@result[:repo]['size'].to_i*1024)) json.ssh_url @result[:repo]['ssh_url'] json.clone_url @result[:repo]['clone_url'] - json.default_branch @result[:repo]['default_branch'] + json.default_branch @project.educoder? ? "master" : @result[:repo]['default_branch'] json.empty @result[:repo]['empty'] json.full_name @result[:repo]['full_name'] json.private @result[:repo]['private'] From 1fca089949062dcf274e44c616e1332481a07be1 Mon Sep 17 00:00:00 2001 From: jasder Date: Wed, 9 Jun 2021 09:43:34 +0800 Subject: [PATCH 51/51] FIX change license --- LICENSE | 137 +++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 120 insertions(+), 17 deletions(-) diff --git a/LICENSE b/LICENSE index 8aa26455d..2b9b385e6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,124 @@ -MIT License +木兰宽松许可证, 第2版 -Copyright (c) [year] [fullname] +2020年1月 http://license.coscl.org.cn/MulanPSL2 -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +0. 定义 -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +“软件” 是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。 + +“贡献” 是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。 + +“贡献者” 是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。 + +“法人实体” 是指提交贡献的机构及其“关联实体”。 + +“关联实体” 是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。 + +1. 授予版权许可 + +每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。 + +2. 授予专利许可 + +每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。 + +3. 无商标许可 + +“本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定的声明义务而必须使用除外。 + +4. 分发限制 + +您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。 + +5. 免责声明与责任限制 + +“软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。 + +6. 语言 + +“本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文版为准。 + +条款结束 + +如何将木兰宽松许可证,第2版,应用到您的软件 + +如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步: + +1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字; + +2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中; + +3, 请将如下声明文本放入每个源文件的头部注释中。 + +Copyright (c) [Year] [name of copyright holder] +[Software Name] is licensed under Mulan PSL v2. +You can use this software according to the terms and conditions of the Mulan PSL v2. +You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +See the Mulan PSL v2 for more details. +Mulan Permissive Software License,Version 2 +Mulan Permissive Software License,Version 2 (Mulan PSL v2) + +January 2020 http://license.coscl.org.cn/MulanPSL2 + +Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions: + +0. Definition + +Software means the program and related documents which are licensed under this License and comprise all Contribution(s). + +Contribution means the copyrightable work licensed by a particular Contributor under this License. + +Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License. + +Legal Entity means the entity making a Contribution and all its Affiliates. + +Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, ‘control’ means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity. + +1. Grant of Copyright License + +Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not. + +2. Grant of Patent License + +Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken. + +3. No Trademark License + +No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in section 4. + +4. Distribution Restriction + +You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software. + +5. Disclaimer of Warranty and Limitation of Liability + +THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +6. Language + +THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL. + +END OF THE TERMS AND CONDITIONS + +How to Apply the Mulan Permissive Software License,Version 2 (Mulan PSL v2) to Your Software + +To apply the Mulan PSL v2 to your work, for easy identification by recipients, you are suggested to complete following three steps: + +Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner; +Create a file named "LICENSE" which contains the whole context of this License in the first directory of your software package; +Attach the statement to the appropriate annotated syntax at the beginning of each source file. +Copyright (c) [Year] [name of copyright holder] +[Software Name] is licensed under Mulan PSL v2. +You can use this software according to the terms and conditions of the Mulan PSL v2. +You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +See the Mulan PSL v2 for more details. \ No newline at end of file