| @@ -2357,6 +2357,51 @@ http://localhost:3000/api//api/repositories/3868/delete_file | jq | |||||
| ### DevOps相关api | ### DevOps相关api | ||||
| --- | --- | ||||
| #### 获取devops流程步骤(判断devops是否初始化) | |||||
| ``` | |||||
| GET /api/users/devops | |||||
| ``` | |||||
| *示例* | |||||
| ``` | |||||
| curl -X GET \ | |||||
| -d "project_id=5988" \ | |||||
| https://localhost:3000/api/users/devops.json | jq | |||||
| ``` | |||||
| *请求参数说明:* | |||||
| |参数名|必选|类型|说明| | |||||
| |-|-|-|-| | |||||
| |project_id |是|string |项目id或者项目的标识identifier| | |||||
| *返回参数说明:* | |||||
| |参数名|类型|说明| | |||||
| |-|-|-| | |||||
| |step |int|初始化devops流程步骤; 0: 标识未开启devops,1: 标识用户已填写了云服务器相关信息,但并未开启认证, 2: 标识用户已开启了CI服务端的认证, 3: 标识用户已经授权并获取了CI服务的token| | |||||
| |account |string|你的云服务器帐号| | |||||
| |ip |string|你的云服务器帐号ip| | |||||
| |secret |string|你的云服务器登录密码| | |||||
| |authenticate_url |string|devops授权认证地址, 只有填写了服务器相关信息后才会有该地址| | |||||
| |get_drone_token_url |string|获取CI服务端token地址, 只有认证成功后才会有该地址| | |||||
| 返回值 | |||||
| ```json | |||||
| { | |||||
| "step": 0, | |||||
| "cloud_account": { | |||||
| "id": 1, | |||||
| "account": "xxx", | |||||
| "ip": "xxx.xxx.xxx.x", | |||||
| "secret": "11111", | |||||
| "authenticate_url": "http://localhost:3000/login", | |||||
| "get_drone_token_url": "http://localhost:3000/account" | |||||
| } | |||||
| } | |||||
| ``` | |||||
| --- | |||||
| #### 初始化DevOps流程 | #### 初始化DevOps流程 | ||||
| ``` | ``` | ||||
| POST /api/dev_ops/cloud_accounts | POST /api/dev_ops/cloud_accounts | ||||
| @@ -2399,6 +2444,72 @@ https://localhost:3000/api/dev_ops/cloud_accounts.json | jq | |||||
| ``` | ``` | ||||
| --- | --- | ||||
| #### 用户认证CI服务端后,需要调用该接口进行更新devlops流程状态 | |||||
| ``` | |||||
| PUT /api/users/devops_authenticate | |||||
| ``` | |||||
| *示例* | |||||
| ``` | |||||
| curl -X PUT \ | |||||
| -d "project_id=5988" \ | |||||
| http://localhost:3000/api/users/devops_authenticate.json | jq | |||||
| ``` | |||||
| *请求参数说明:* | |||||
| |参数名|必选|类型|说明| | |||||
| |-|-|-|-| | |||||
| |project_id |是|string |项目id或者项目的标识identifier| | |||||
| *返回参数说明:* | |||||
| |参数名|类型|说明| | |||||
| |-|-|-| | |||||
| |status |int|0:成功, -1: 失败| | |||||
| ``` | |||||
| { | |||||
| "status": 0, | |||||
| "message": "success" | |||||
| } | |||||
| ``` | |||||
| --- | |||||
| #### 激活项目 | |||||
| ``` | |||||
| POST /api/dev_ops/cloud_accounts/:id/activate | |||||
| ``` | |||||
| *示例* | |||||
| ``` | |||||
| curl -X POST \ | |||||
| -d "id=1" \ | |||||
| -d "project_id=4844" \ | |||||
| -d "drone_token=xxxxxxxxxx" \ | |||||
| http://localhost:3000/api/dev_ops/cloud_accounts/1/activate.json | jq | |||||
| ``` | |||||
| *请求参数说明:* | |||||
| |参数名|必选|类型|说明| | |||||
| |-|-|-|-| | |||||
| |project_id |是|int |project's id or identifier | | |||||
| |id |是|int |cloud_account's id | | |||||
| |drone_token |否|string |CI端用户的token值,只有当用户第一次激活时,才需要填写该值 | | |||||
| *返回参数说明:* | |||||
| |参数名|类型|说明| | |||||
| |-|-|-| | |||||
| |status |int|0:成功, -1: 失败| | |||||
| ``` | |||||
| { | |||||
| "status": 0, | |||||
| "message": "success" | |||||
| } | |||||
| ``` | |||||
| --- | |||||
| #### 获取仓库的.trustie-pipeline.yml | #### 获取仓库的.trustie-pipeline.yml | ||||
| ``` | ``` | ||||
| GET /api/dev_ops/builds/get_trustie_pipeline | GET /api/dev_ops/builds/get_trustie_pipeline | ||||
| @@ -2433,6 +2544,7 @@ http://localhost:3000/api/dev_ops/builds/get_trustie_pipeline.json | jq | |||||
| "content": "..jsaf" | "content": "..jsaf" | ||||
| } | } | ||||
| ``` | ``` | ||||
| --- | |||||
| #### 获取语言列表 | #### 获取语言列表 | ||||
| ``` | ``` | ||||
| @@ -744,11 +744,6 @@ class ApplicationController < ActionController::Base | |||||
| interactor.success? ? render_ok : render_error(interactor.error) | interactor.success? ? render_ok : render_error(interactor.error) | ||||
| end | end | ||||
| # devops 权限验证 | |||||
| def devops_authorize! | |||||
| render_forbidden unless @project.owner?(current_user) | |||||
| end | |||||
| private | private | ||||
| def object_not_found | def object_not_found | ||||
| uid_logger("Missing template or cant't find record, responding with 404") | uid_logger("Missing template or cant't find record, responding with 404") | ||||
| @@ -0,0 +1,32 @@ | |||||
| module Devopsable | |||||
| extend ActiveSupport::Concern | |||||
| included do | |||||
| end | |||||
| # devops 权限验证 | |||||
| def devops_authorize! | |||||
| render_forbidden unless @project.owner?(current_user) | |||||
| end | |||||
| def auto_load_project | |||||
| @project = Project.find_by(id: params[:project_id]) || Project.find_by(identifier: params[:project_id]) | |||||
| render_not_found('未找到相关的项目') if @project.blank? | |||||
| end | |||||
| # TODO 暂时限制项目拥有者才有权限操作 | |||||
| def limit_owner_can_devops!(user) | |||||
| return if @project.owner? user | |||||
| render_forbidden | |||||
| end | |||||
| def find_cloud_account | |||||
| @cloud_account = DevOps::CloudAccount.find params[:id] | |||||
| end | |||||
| def set_drone_token!(user, cloud_account, drone_token) | |||||
| return if user.devops_has_token? | |||||
| cloud_account.update_column(:drone_token, drone_token) | |||||
| user.set_drone_step!(User::DEVOPS_HAS_TOKEN) | |||||
| end | |||||
| end | |||||
| @@ -1,7 +1,10 @@ | |||||
| class DevOps::CloudAccountsController < ApplicationController | class DevOps::CloudAccountsController < ApplicationController | ||||
| include Devopsable | |||||
| before_action :require_login | before_action :require_login | ||||
| before_action :find_project | |||||
| before_action :auto_load_project | |||||
| before_action :devops_authorize! | before_action :devops_authorize! | ||||
| before_action :find_cloud_account, only: %i[activate] | |||||
| def create | def create | ||||
| ActiveRecord::Base.transaction do | ActiveRecord::Base.transaction do | ||||
| @@ -14,8 +17,6 @@ class DevOps::CloudAccountsController < ApplicationController | |||||
| else | else | ||||
| cloud_account = DevOps::CloudAccount.new(create_params) | cloud_account = DevOps::CloudAccount.new(create_params) | ||||
| cloud_account.user = current_user | cloud_account.user = current_user | ||||
| cloud_account.repo_id = @project.repository.id | |||||
| cloud_account.project_id = @project.id | |||||
| cloud_account.save! | cloud_account.save! | ||||
| end | end | ||||
| @@ -50,6 +51,7 @@ class DevOps::CloudAccountsController < ApplicationController | |||||
| logger.info "######### redirect_url: #{redirect_url}" | logger.info "######### redirect_url: #{redirect_url}" | ||||
| if result && !result.blank? | if result && !result.blank? | ||||
| current_user.set_drone_step!(User::DEVOPS_UNVERIFIED) | |||||
| render_ok(redirect_url: redirect_url) | render_ok(redirect_url: redirect_url) | ||||
| else | else | ||||
| render_error('激活失败, 请检查你的云服务器信息是否正确.') | render_error('激活失败, 请检查你的云服务器信息是否正确.') | ||||
| @@ -60,12 +62,28 @@ class DevOps::CloudAccountsController < ApplicationController | |||||
| render_error(ex.message) | render_error(ex.message) | ||||
| end | end | ||||
| def activate | |||||
| result = | |||||
| if current_user.devops_has_token? | |||||
| # 已有drone_token的,直接激活项目 | |||||
| DevOps::Drone::API.new(@cloud_account.drone_token, @cloud_account.drone_url, @project.owner.login, @project.identifier).activate | |||||
| else | |||||
| # 没有token,说明是第一次激活devops, 需要用户填写token值 | |||||
| return render_error('请先在CI服务端做用户认证.') if !current_user.devops_verified? | |||||
| DevOps::Drone::API.new(params[:drone_token], @cloud_account.drone_url, @project.owner.login, @project.identifier).activate | |||||
| end | |||||
| if result | |||||
| set_drone_token!(current_user, @cloud_account, params[:drone_token]) | |||||
| @project.update_column(:open_devops, true) | |||||
| render_ok | |||||
| else | |||||
| render_error("激活失败,请检查你的token值是否正确.") | |||||
| end | |||||
| end | |||||
| private | private | ||||
| def devops_params | def devops_params | ||||
| params.permit(:account, :secret, :ip_num, :project_id) | params.permit(:account, :secret, :ip_num, :project_id) | ||||
| end | end | ||||
| def find_project | |||||
| @project = Project.find params[:project_id] | |||||
| end | |||||
| end | end | ||||
| @@ -1,4 +1,5 @@ | |||||
| class DevOps::LanguagesController < ApplicationController | class DevOps::LanguagesController < ApplicationController | ||||
| # TODO 需要开启权限认证,只有该项目devops初始化成功后才能获取语言列表 | |||||
| before_action :require_login | before_action :require_login | ||||
| before_action :find_langugae, only: :show | before_action :find_langugae, only: :show | ||||
| @@ -1,8 +1,10 @@ | |||||
| class UsersController < ApplicationController | class UsersController < ApplicationController | ||||
| include Devopsable | |||||
| before_action :load_user, only: [:show, :homepage_info, :sync_token, :sync_gitea_pwd, :projects, :watch_users, :fan_users] | before_action :load_user, only: [:show, :homepage_info, :sync_token, :sync_gitea_pwd, :projects, :watch_users, :fan_users] | ||||
| before_action :check_user_exist, only: [:show, :homepage_info,:projects, :watch_users, :fan_users] | before_action :check_user_exist, only: [:show, :homepage_info,:projects, :watch_users, :fan_users] | ||||
| before_action :require_login, only: %i[me list] | |||||
| before_action :require_login, only: %i[me list devops_authenticate devops] | |||||
| before_action :auto_load_project, only: %i[devops devops_authenticate] | |||||
| skip_before_action :check_sign, only: [:attachment_show] | skip_before_action :check_sign, only: [:attachment_show] | ||||
| def list | def list | ||||
| @@ -177,7 +179,7 @@ class UsersController < ApplicationController | |||||
| def trustie_projects | def trustie_projects | ||||
| user_id = User.select(:id, :login).where(login: params[:login])&.first&.id | user_id = User.select(:id, :login).where(login: params[:login])&.first&.id | ||||
| projects = Project.visible | projects = Project.visible | ||||
| projects = projects.joins(:members).where(members: { user_id: user_id }) | projects = projects.joins(:members).where(members: { user_id: user_id }) | ||||
| search = params[:search].to_s.strip | search = params[:search].to_s.strip | ||||
| @@ -212,6 +214,19 @@ class UsersController < ApplicationController | |||||
| render_ok | render_ok | ||||
| end | end | ||||
| def devops | |||||
| @user = current_user | |||||
| limit_owner_can_devops!(user) | |||||
| @cloud_account = @user.dev_ops_cloud_account | |||||
| end | |||||
| # devops 认证 | |||||
| def devops_authenticate | |||||
| limit_owner_can_devops!(current_user) | |||||
| current_user.set_drone_step!(User::DEVOPS_VERIFIED) | |||||
| render_ok | |||||
| end | |||||
| private | private | ||||
| def load_user | def load_user | ||||
| @user = User.find_by_login(params[:id]) || User.find_by(id: params[:id]) | @user = User.find_by_login(params[:id]) || User.find_by(id: params[:id]) | ||||
| @@ -20,6 +20,6 @@ class DevOps::Drone::Ci | |||||
| private | private | ||||
| def cmd | def cmd | ||||
| "cd ..; cd var/lib/drone/; sqlite3 database.sqlite; .dump; select user_hash from users where user_login=#{gitea_username} " | |||||
| "cd ..; cd var/lib/drone/; sqlite3 database.sqlite; .dump; select user_hash from users where user_login=#{gitea_username};" | |||||
| end | end | ||||
| end | end | ||||
| @@ -18,7 +18,8 @@ class DevOps::Drone::Server | |||||
| def generate_cmd | def generate_cmd | ||||
| "service docker start; docker rm -f `docker ps -qa`; docker run \ | "service docker start; docker rm -f `docker ps -qa`; docker run \ | ||||
| -v /var/run/docker.sock:/var/run/docker.sock \ | -v /var/run/docker.sock:/var/run/docker.sock \ | ||||
| -v /var/lib/drone:/data \ | |||||
| -e DRONE_DATABASE_DRIVER=mysql \ | |||||
| -e DRONE_DATABASE_DATASOURCE=#{database_username}:#{database_password}@#{database_host}:3306/drone?parseTime=true \ | |||||
| -e DRONE_GITEA_SERVER=#{gitea_url} \ | -e DRONE_GITEA_SERVER=#{gitea_url} \ | ||||
| -e DRONE_GITEA_CLIENT_ID=#{client_id} \ | -e DRONE_GITEA_CLIENT_ID=#{client_id} \ | ||||
| -e DRONE_GITEA_CLIENT_SECRET=#{client_secret} \ | -e DRONE_GITEA_CLIENT_SECRET=#{client_secret} \ | ||||
| @@ -37,4 +38,24 @@ class DevOps::Drone::Server | |||||
| def gitea_url | def gitea_url | ||||
| Gitea.gitea_config[:domain] | Gitea.gitea_config[:domain] | ||||
| end | end | ||||
| def database_username | |||||
| database_config[Rails.env]["username"] | |||||
| end | |||||
| def database_password | |||||
| database_config[Rails.env]["password"] | |||||
| end | |||||
| def database_host | |||||
| database_config[Rails.env]["host"] | |||||
| end | |||||
| def database | |||||
| database_config[Rails.env]["database"] | |||||
| end | |||||
| def database_config | |||||
| Rails.configuration.database_configuration | |||||
| end | |||||
| end | end | ||||
| @@ -0,0 +1,29 @@ | |||||
| module Droneable | |||||
| extend ActiveSupport::Concern | |||||
| included do | |||||
| end | |||||
| def devops_uninit? | |||||
| self.devops_step === User::DEVOPS_UNINIT | |||||
| end | |||||
| def devops_unverified? | |||||
| self.devops_step === User::DEVOPS_UNVERIFIED | |||||
| end | |||||
| def devops_verified? | |||||
| self.devops_step === User::DEVOPS_VERIFIED | |||||
| end | |||||
| def devops_has_token? | |||||
| self.devops_step === User::DEVOPS_HAS_TOKEN | |||||
| end | |||||
| def set_drone_step!(step) | |||||
| self.update_column(:devops_step, step) | |||||
| end | |||||
| module ClassMethods | |||||
| end | |||||
| end | |||||
| @@ -5,8 +5,16 @@ class User < ApplicationRecord | |||||
| include Likeable | include Likeable | ||||
| include BaseModel | include BaseModel | ||||
| include ProjectOperable | include ProjectOperable | ||||
| include Droneable | |||||
| # include Searchable::Dependents::User | # include Searchable::Dependents::User | ||||
| # devops step | |||||
| # devops_step column: 0: 未填写服务器信息;1: 已填写服务器信息(未认证); 2: 已认证, 3: 已填写token值 | |||||
| DEVOPS_UNINIT = 0 | |||||
| DEVOPS_UNVERIFIED = 1 | |||||
| DEVOPS_VERIFIED = 2 | |||||
| DEVOPS_HAS_TOKEN = 3 | |||||
| # Account statuses | # Account statuses | ||||
| STATUS_ANONYMOUS = 0 | STATUS_ANONYMOUS = 0 | ||||
| STATUS_ACTIVE = 1 | STATUS_ACTIVE = 1 | ||||
| @@ -70,8 +78,9 @@ class User < ApplicationRecord | |||||
| # 关注 | # 关注 | ||||
| has_many :be_watchers, foreign_key: :user_id, dependent: :destroy # 我的关注 | has_many :be_watchers, foreign_key: :user_id, dependent: :destroy # 我的关注 | ||||
| has_many :be_watcher_users, through: :be_watchers, dependent: :destroy # 我关注的用户 | has_many :be_watcher_users, through: :be_watchers, dependent: :destroy # 我关注的用户 | ||||
| has_many :watchers, as: :watchable, dependent: :destroy | |||||
| has_many :watchers, as: :watchable, dependent: :destroy | |||||
| has_one :dev_ops_cloud_account, class_name: 'DevOps::CloudAccount', dependent: :destroy | |||||
| # 认证 | # 认证 | ||||
| has_many :apply_user_authentication | has_many :apply_user_authentication | ||||
| @@ -0,0 +1,12 @@ | |||||
| json.step @user.devops_step | |||||
| json.cloud_account do | |||||
| if @cloud_account && !@user.devops_uninit? | |||||
| json.account @cloud_account.account | |||||
| json.ip @cloud_account.drone_ip | |||||
| json.secret @cloud_account.visible_secret | |||||
| json.authenticate_url "#{@cloud_account.drone_url}/login" if @user.devops_unverified? | |||||
| json.get_drone_token_url "#{@cloud_account.drone_url}/account" if @user.devops_verified? | |||||
| else | |||||
| json.nil! | |||||
| end | |||||
| end | |||||
| @@ -12,5 +12,4 @@ json.user_phone_binded @user.phone.present? | |||||
| # json.email @user.mail | # json.email @user.mail | ||||
| json.profile_completed @user.profile_completed? | json.profile_completed @user.profile_completed? | ||||
| json.professional_certification @user.professional_certification | json.professional_certification @user.professional_certification | ||||
| json.devops_step @user.devops_step | |||||
| @@ -16,7 +16,11 @@ Rails.application.routes.draw do | |||||
| resources :edu_settings | resources :edu_settings | ||||
| scope '/api' do | scope '/api' do | ||||
| namespace :dev_ops do | namespace :dev_ops do | ||||
| resources :cloud_accounts, only: [:create] | |||||
| resources :cloud_accounts, only: [:create] do | |||||
| member do | |||||
| post :activate | |||||
| end | |||||
| end | |||||
| resources :languages, only: [:index, :show] do | resources :languages, only: [:index, :show] do | ||||
| collection do | collection do | ||||
| get :common | get :common | ||||
| @@ -189,11 +193,12 @@ Rails.application.routes.draw do | |||||
| post :sync_salt | post :sync_salt | ||||
| get :trustie_projects | get :trustie_projects | ||||
| get :trustie_related_projects | get :trustie_related_projects | ||||
| get :devops | |||||
| put :devops_authenticate | |||||
| end | end | ||||
| scope module: :users do | scope module: :users do | ||||
| # resources :courses, only: [:index] | |||||
| resources :projects, only: [:index] | |||||
| # resources :projects, only: [:index] | |||||
| # resources :subjects, only: [:index] | # resources :subjects, only: [:index] | ||||
| resources :project_packages, only: [:index] | resources :project_packages, only: [:index] | ||||
| # 私信 | # 私信 | ||||
| @@ -0,0 +1,5 @@ | |||||
| class AddDevopsStepToUsers < ActiveRecord::Migration[5.2] | |||||
| def change | |||||
| add_column :users, :devops_step, :integer, default: 0, comment: '0: uninit devops; 1: unverified; 2: verified' | |||||
| end | |||||
| end | |||||