| @@ -329,7 +329,6 @@ class ApplicationController < ActionController::Base | |||
| User.current = user | |||
| end | |||
| end | |||
| # if !User.current.logged? && Rails.env.development? | |||
| # User.current = User.find 1 | |||
| # end | |||
| @@ -1,13 +1,17 @@ | |||
| module RegisterHelper | |||
| extend ActiveSupport::Concern | |||
| def autologin_register(username, email, password, platform= 'forge') | |||
| def autologin_register(username, email, password, platform= 'forge', need_edit_info = false) | |||
| result = {message: nil, user: nil} | |||
| user = User.new(admin: false, login: username, mail: email, type: "User") | |||
| user.password = password | |||
| user.platform = platform | |||
| user.activate | |||
| if need_edit_info | |||
| user.need_edit_info | |||
| else | |||
| user.activate | |||
| end | |||
| return unless user.valid? | |||
| @@ -27,4 +31,30 @@ module RegisterHelper | |||
| result | |||
| end | |||
| def autosync_register_trustie(username, password, email) | |||
| config = Rails.application.config_for(:configuration).symbolize_keys! | |||
| api_host = config[:sync_url] | |||
| return if api_host.blank? | |||
| url = "#{api_host}/api/v1/users/common" | |||
| sync_json = { | |||
| "mail": email, | |||
| "password": password, | |||
| "login": username | |||
| } | |||
| uri = URI.parse(url) | |||
| if api_host | |||
| http = Net::HTTP.new(uri.hostname, uri.port) | |||
| if api_host.include?("https://") | |||
| http.use_ssl = true | |||
| end | |||
| http.send_request('POST', uri.path, sync_json.to_json, {'Content-Type' => 'application/json'}) | |||
| end | |||
| end | |||
| end | |||
| @@ -2,6 +2,7 @@ class Oauth::BaseController < ActionController::Base | |||
| include RenderHelper | |||
| include LoginHelper | |||
| include ControllerRescueHandler | |||
| include LoggerHelper | |||
| # include LaboratoryHelper | |||
| skip_before_action :verify_authenticity_token | |||
| @@ -11,6 +12,18 @@ class Oauth::BaseController < ActionController::Base | |||
| end | |||
| private | |||
| def tip_exception(status = -1, message) | |||
| raise Educoder::TipException.new(status, message) | |||
| end | |||
| def tip_show_exception(status = -2, message) | |||
| raise Educoder::TipException.new(status, message) | |||
| end | |||
| def tip_show(exception) | |||
| uid_logger("Tip show status is #{exception.status}, message is #{exception.message}") | |||
| render json: exception.tip_json | |||
| end | |||
| def session_user_id | |||
| # session[:user_id] | |||
| @@ -48,4 +61,13 @@ class Oauth::BaseController < ActionController::Base | |||
| Rails.logger.info("[wechat] set session unionid: #{unionid}") | |||
| session[:unionid] = unionid | |||
| end | |||
| def session_edulogin | |||
| session[:edulogin] | |||
| end | |||
| def set_session_edulogin(login) | |||
| Rails.logger.info("[educoder] set sesstion edulogin: #{login}") | |||
| session[:edulogin] = login | |||
| end | |||
| end | |||
| @@ -1,4 +1,6 @@ | |||
| class Oauth::EducoderController < Oauth::BaseController | |||
| include RegisterHelper | |||
| def bind | |||
| begin | |||
| login = params[:login] | |||
| @@ -32,4 +34,41 @@ class Oauth::EducoderController < Oauth::BaseController | |||
| render_error(ex.message) | |||
| end | |||
| end | |||
| # 需要educoder那边设置回调地址 | |||
| def create | |||
| begin | |||
| code = params['code'].to_s.strip | |||
| tip_exception("code不能为空") if code.blank? | |||
| new_user = false | |||
| result = EducoderOauth::Service.access_token(code) | |||
| result = EducoderOauth::Service.user_info(result[:access_token]) | |||
| # 存在该用户 | |||
| open_user = OpenUsers::Educoder.find_by(uid: result['login']) | |||
| if open_user.present? && open_user.user.present? | |||
| successful_authentication(open_user.user) | |||
| else | |||
| if current_user.blank? || !current_user.logged? | |||
| new_user = true | |||
| login = User.generate_login('E') | |||
| reg_result = autologin_register(login,"#{login}@forge.com", "Ec#{login}2021#", 'educoder', true) | |||
| if reg_result[:message].blank? | |||
| open_user = OpenUsers::Educoder.create!(user_id: reg_result[:user][:id], uid: result['login'], extra: result) | |||
| autosync_register_trustie(login, "Ec#{login}2021#", "#{login}@forge.com") | |||
| successful_authentication(open_user.user) | |||
| else | |||
| render_error(reg_result[:message]) | |||
| end | |||
| else | |||
| OpenUsers::Educoder.create!(user: current_user, uid: result['login'], extra: result) | |||
| end | |||
| end | |||
| redirect_to root_path(new_user: new_user) | |||
| rescue Exception => ex | |||
| render_error(ex.message) | |||
| end | |||
| end | |||
| end | |||
| @@ -4,7 +4,7 @@ class SettingsController < ApplicationController | |||
| get_add_menu | |||
| get_common_menu | |||
| get_personal_menu | |||
| get_third_party | |||
| end | |||
| private | |||
| @@ -40,6 +40,14 @@ class SettingsController < ApplicationController | |||
| end | |||
| end | |||
| def get_third_party | |||
| @third_party = [] | |||
| @third_party << { | |||
| name: 'educoder', | |||
| url: EducoderOauth.oauth_url | |||
| } | |||
| end | |||
| def get_site_url(key, value) | |||
| key.to_s === "url" ? append_http(reset_site_url(value)) : reset_site_url(value) | |||
| end | |||
| @@ -4,7 +4,7 @@ class UsersController < ApplicationController | |||
| 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 :require_login, only: %i[me list] | |||
| before_action :require_login, only: %i[me list sync_user_info] | |||
| before_action :connect_to_ci_db, only: [:get_user_info] | |||
| skip_before_action :check_sign, only: [:attachment_show] | |||
| @@ -233,6 +233,26 @@ class UsersController < ApplicationController | |||
| render_ok | |||
| end | |||
| def sync_user_info | |||
| user = User.find_by_login params[:login] | |||
| return render_forbidden unless user === current_user | |||
| sync_params = { | |||
| email: params[:email], | |||
| password: params[:password] | |||
| } | |||
| Users::UpdateInfoForm.new(sync_params).validate! | |||
| interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params) | |||
| if interactor.success? | |||
| user.update!(password: params[:password], mail: params[:email], status: User::STATUS_ACTIVE) | |||
| render_ok | |||
| else | |||
| render_error(interactor.error) | |||
| end | |||
| end | |||
| private | |||
| def load_user | |||
| @user = User.find_by_login(params[:id]) || User.find_by(id: params[:id]) | |||
| @@ -0,0 +1,9 @@ | |||
| class Users::UpdateInfoForm | |||
| include ActiveModel::Model | |||
| attr_accessor :email, :password, :login | |||
| validates :email, presence: true, format: { with: CustomRegexp::EMAIL } | |||
| validates :password, presence: true | |||
| validates :login, presence: true | |||
| end | |||
| @@ -0,0 +1,18 @@ | |||
| module EducoderOauth | |||
| class << self | |||
| attr_accessor :client_id, :client_secret, :base_url, :redirect_uri | |||
| def logger | |||
| @_logger ||= STDOUT | |||
| end | |||
| def logger=(l) | |||
| @_logger = l | |||
| end | |||
| def oauth_url | |||
| "#{base_url}/oauth2?call_url=/oauth/authorize?client_id=#{client_id}&redirect_uri=#{URI.encode_www_form_component(redirect_uri)}&response_type=code" | |||
| end | |||
| end | |||
| end | |||
| @@ -0,0 +1,37 @@ | |||
| require 'oauth2' | |||
| module EducoderOauth::Service | |||
| module_function | |||
| def request(method, url, params) | |||
| begin | |||
| Rails.logger.info("[EducoderOauth] [#{method.to_s.upcase}] #{url} || #{params}") | |||
| client = Faraday.new(url: EducoderOauth.base_url) | |||
| response = client.public_send(method, url, params) | |||
| result = JSON.parse(response.body) | |||
| Rails.logger.info("[EducoderOauth] [#{response.status}] #{result}") | |||
| result | |||
| rescue Exception => e | |||
| raise Educoder::TipException.new(e.message) | |||
| end | |||
| end | |||
| def access_token(code) | |||
| begin | |||
| Rails.logger.info("[EducoderOauth] [code] #{code} ") | |||
| Rails.logger.info("[EducoderOauth] [redirect_uri] #{EducoderOauth.redirect_uri} ") | |||
| client = OAuth2::Client.new(EducoderOauth.client_id, EducoderOauth.client_secret, site: EducoderOauth.base_url) | |||
| result = client.auth_code.get_token(code, redirect_uri: EducoderOauth.redirect_uri).to_hash | |||
| return result | |||
| rescue Exception => e | |||
| raise Educoder::TipException.new(e.message) | |||
| end | |||
| end | |||
| def user_info(access_token) | |||
| request(:get, '/api/users/info.json', {access_token: access_token}) | |||
| end | |||
| end | |||
| @@ -1,19 +1,19 @@ | |||
| # == Schema Information | |||
| # | |||
| # Table name: tokens | |||
| # | |||
| # id :integer not null, primary key | |||
| # user_id :integer default("0"), not null | |||
| # action :string(30) default(""), not null | |||
| # value :string(40) default(""), not null | |||
| # created_on :datetime not null | |||
| # | |||
| # Indexes | |||
| # | |||
| # index_tokens_on_user_id (user_id) | |||
| # tokens_value (value) UNIQUE | |||
| # | |||
| # == Schema Information | |||
| # | |||
| # Table name: tokens | |||
| # | |||
| # id :integer not null, primary key | |||
| # user_id :integer default("0"), not null | |||
| # action :string(30) default(""), not null | |||
| # value :string(40) default(""), not null | |||
| # created_on :datetime not null | |||
| # | |||
| # Indexes | |||
| # | |||
| # index_tokens_on_user_id (user_id) | |||
| # tokens_value (value) UNIQUE | |||
| # | |||
| # | |||
| # This program is free software; you can redistribute it and/or | |||
| # modify it under the terms of the GNU General Public License | |||
| @@ -76,7 +76,7 @@ class Token < ActiveRecord::Base | |||
| # Returns the active user who owns the key for the given action | |||
| def self.find_active_user(action, key, validity_days=nil) | |||
| user = find_user(action, key, validity_days) | |||
| if user && user.active? | |||
| if user && (user.active? || user.need_edit_info?) | |||
| user | |||
| end | |||
| end | |||
| @@ -79,6 +79,7 @@ class User < Owner | |||
| STATUS_ACTIVE = 1 | |||
| STATUS_REGISTERED = 2 | |||
| STATUS_LOCKED = 3 | |||
| STATUS_EDIT_INFO = 4 | |||
| # tpi tpm权限控制 | |||
| EDU_ADMIN = 1 # 超级管理员 | |||
| @@ -161,7 +162,7 @@ class User < Owner | |||
| has_many :organizations, through: :organization_users | |||
| # Groups and active users | |||
| scope :active, lambda { where(status: STATUS_ACTIVE) } | |||
| scope :active, lambda { where(status: [STATUS_ACTIVE, STATUS_EDIT_INFO]) } | |||
| scope :like, lambda { |keywords| | |||
| where("LOWER(concat(lastname, firstname, login, mail)) LIKE ?", "%#{keywords.split(" ").join('|')}%") unless keywords.blank? | |||
| } | |||
| @@ -378,6 +379,10 @@ class User < Owner | |||
| status == STATUS_LOCKED | |||
| end | |||
| def need_edit_info? | |||
| status == STATUS_EDIT_INFO | |||
| end | |||
| def activate | |||
| self.status = STATUS_ACTIVE | |||
| end | |||
| @@ -390,6 +395,10 @@ class User < Owner | |||
| self.status = STATUS_LOCKED | |||
| end | |||
| def need_edit_info | |||
| self.status = STATUS_EDIT_INFO | |||
| end | |||
| def activate! | |||
| update_attribute(:status, STATUS_ACTIVE) | |||
| end | |||
| @@ -402,6 +411,10 @@ class User < Owner | |||
| update_attribute(:status, STATUS_LOCKED) | |||
| end | |||
| def need_edit_info! | |||
| update_attribute(:status, STATUS_EDIT_INFO) | |||
| end | |||
| # 课程用户身份 | |||
| def course_identity(course) | |||
| if !logged? | |||
| @@ -56,4 +56,5 @@ json.setting do | |||
| end | |||
| json.common @common | |||
| json.third_party @third_party | |||
| end | |||
| @@ -8,8 +8,9 @@ json.is_teacher @user.user_extension&.teacher? | |||
| json.user_identity @user.identity | |||
| json.tidding_count 0 | |||
| json.user_phone_binded @user.phone.present? | |||
| json.need_edit_info @user.need_edit_info? | |||
| # json.phone @user.phone | |||
| # json.email @user.mail | |||
| json.email @user.mail | |||
| json.profile_completed @user.profile_completed? | |||
| json.professional_certification @user.professional_certification | |||
| json.devops_step @user.devops_step | |||
| @@ -43,6 +43,11 @@ default: &default | |||
| cate_id: '-1' | |||
| callback_url: 'callback_url' | |||
| signature_key: 'test12345678' | |||
| educoder: | |||
| client_id: 'e9ce4d5ba1698d6f7d01d8ee2959776c7a6d743ebe94da2341e288fd2fbf60aa' | |||
| client_secret: '6ff84dd75eddd859c5bd0e7a791b58bc5ad1ba4fbb30bc9db37cb0baf9f33012' | |||
| base_url: 'https://test-data.educoder.net' | |||
| redirect_uri: 'https://testforgeplus.trustie.net/api/auth/educoder/callback' | |||
| gitea: | |||
| access_key_id: 'root' | |||
| @@ -0,0 +1,16 @@ | |||
| oauth_config = {} | |||
| begin | |||
| config = Rails.application.config_for(:configuration) | |||
| oauth_config = config.dig('oauth', 'educoder') | |||
| raise 'oauth educoder config missing' if oauth_config.blank? | |||
| rescue => ex | |||
| raise ex if Rails.env.production? | |||
| puts %Q{\033[33m [warning] wechat oauth config or configuration.yml missing, | |||
| please add it or execute 'cp config/configuration.yml.example config/configuration.yml' \033[0m} | |||
| end | |||
| EducoderOauth.client_id = oauth_config['client_id'] | |||
| EducoderOauth.client_secret = oauth_config['client_secret'] | |||
| EducoderOauth.base_url = oauth_config['base_url'] | |||
| EducoderOauth.redirect_uri = oauth_config['redirect_uri'] | |||
| @@ -72,12 +72,12 @@ Rails.application.routes.draw do | |||
| end | |||
| resources :statistic, only: [:index] do | |||
| collection do | |||
| collection do | |||
| get :platform_profile | |||
| get :platform_code | |||
| get :active_project_rank | |||
| get :active_developer_rank | |||
| end | |||
| end | |||
| end | |||
| resources :sync_forge, only: [:create] do | |||
| collection do | |||
| @@ -218,6 +218,7 @@ Rails.application.routes.draw do | |||
| post :sync_salt | |||
| get :trustie_projects | |||
| get :trustie_related_projects | |||
| post :sync_user_info | |||
| scope '/ci', module: :ci do | |||
| scope do | |||
| @@ -312,6 +313,7 @@ Rails.application.routes.draw do | |||
| get '/auth/qq/callback', to: 'oauth/qq#create' | |||
| get '/auth/wechat/callback', to: 'oauth/wechat#create' | |||
| get '/auth/educoder/callback', to: 'oauth/educoder#create' | |||
| resource :bind_user, only: [:create] | |||
| resources :hot_keywords, only: [:index] | |||