diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 3f0fbcc7d..8ff81a465 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -337,7 +337,6 @@ class ApplicationController < ActionController::Base User.current = user end end - # if !User.current.logged? && Rails.env.development? # User.current = User.find 1 # end diff --git a/app/controllers/concerns/register_helper.rb b/app/controllers/concerns/register_helper.rb index 3a23a2103..9d2f420a0 100644 --- a/app/controllers/concerns/register_helper.rb +++ b/app/controllers/concerns/register_helper.rb @@ -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,31 @@ module RegisterHelper result end + def autosync_register_trustie(username, password, email, lastname="") + 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, + "lastname": lastname + }.compact + 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 diff --git a/app/controllers/oauth/base_controller.rb b/app/controllers/oauth/base_controller.rb index 3fe349bb5..6956c9ce9 100644 --- a/app/controllers/oauth/base_controller.rb +++ b/app/controllers/oauth/base_controller.rb @@ -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 diff --git a/app/controllers/oauth/educoder_controller.rb b/app/controllers/oauth/educoder_controller.rb index 8ed537d6c..9ca4ae49b 100644 --- a/app/controllers/oauth/educoder_controller.rb +++ b/app/controllers/oauth/educoder_controller.rb @@ -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 diff --git a/app/controllers/oauth_controller.rb b/app/controllers/oauth_controller.rb index 5da9297a6..f2ca2cc21 100644 --- a/app/controllers/oauth_controller.rb +++ b/app/controllers/oauth_controller.rb @@ -61,6 +61,7 @@ class OauthController < ApplicationController login = params[:login] email = params[:mail] password = params[:password] + lastname = params[:lastname] callback_url = params[:callback_url] platform = params[:plathform] || 'educoder' @@ -72,8 +73,11 @@ class OauthController < ApplicationController if result[:message].blank? logger.info "[Oauth educoer] ====auto_register success" user = User.find result[:user][:id] - successful_authentication(user) + user.update_column(:lastname, params[:lastname]) + autosync_register_trustie(login, password, email, lastname) + OpenUsers::Educoder.create!(user: user, uid: user.login) + successful_authentication(user) render json: { callback_url: callback_url } # redirect_to callback_url diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb index 35f11f476..f9d949db5 100644 --- a/app/controllers/repositories_controller.rb +++ b/app/controllers/repositories_controller.rb @@ -347,7 +347,7 @@ class RepositoriesController < ApplicationController local_requests = PullRequest.new(local_params.merge(user_id: current_user.try(:id), project_id: @project.id, issue_id: @pull_issue.id)) if local_requests.save gitea_request = Gitea::PullRequest::CreateService.new(current_user.try(:gitea_token), @owner.login, @project.try(:identifier), requests_params).call - if gitea_request[:status] == :success && local_requests.update_attributes(gpid: gitea_request["body"]["number"]) + if gitea_request[:status] == :success && local_requests.update_attributes(gitea_number: gitea_request["body"]["number"]) local_requests.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create") end end diff --git a/app/controllers/settings_controller.rb b/app/controllers/settings_controller.rb index b2dc2e900..3a68ff7ba 100644 --- a/app/controllers/settings_controller.rb +++ b/app/controllers/settings_controller.rb @@ -4,6 +4,7 @@ class SettingsController < ApplicationController get_add_menu get_common_menu get_personal_menu + get_third_party get_top_system_notification end @@ -40,6 +41,14 @@ class SettingsController < ApplicationController end end + def get_third_party + @third_party = [] + @third_party << { + name: 'educoder', + url: EducoderOauth.oauth_url + } + end + def get_top_system_notification @top_system_notification = SystemNotification.is_top.first end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index b80827efa..7890ee864 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -273,7 +273,7 @@ class UsersController < ApplicationController interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params) if interactor.success? - user.update!(password: params[:password], mail: params[:email], status: User::STATUS_EDIT_INFO) + user.update!(password: params[:password], mail: params[:email], status: User::STATUS_ACTIVE) render_ok else render_error(interactor.error) diff --git a/app/libs/educoder_oauth.rb b/app/libs/educoder_oauth.rb new file mode 100644 index 000000000..0c3fb61bf --- /dev/null +++ b/app/libs/educoder_oauth.rb @@ -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 \ No newline at end of file diff --git a/app/libs/educoder_oauth/service.rb b/app/libs/educoder_oauth/service.rb new file mode 100644 index 000000000..9d93d314d --- /dev/null +++ b/app/libs/educoder_oauth/service.rb @@ -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 \ No newline at end of file diff --git a/app/models/gitea/pull.rb b/app/models/gitea/pull.rb index 591e36c42..7adb8c366 100644 --- a/app/models/gitea/pull.rb +++ b/app/models/gitea/pull.rb @@ -39,6 +39,6 @@ class Gitea::Pull < Gitea::Base serialize :conflicted_files, Array - belongs_to :pull_request, class_name: '::PullRequest', foreign_key: :id, primary_key: :gitea_number, optional: true + belongs_to :pull_request, class_name: '::PullRequest', foreign_key: :id, primary_key: :gitea_id, optional: true end diff --git a/app/models/project.rb b/app/models/project.rb index 293e6c478..d7b0519b7 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1,4 +1,3 @@ - # == Schema Information # # Table name: projects @@ -38,8 +37,6 @@ # 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") @@ -53,9 +50,10 @@ # 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) -# order_index :integer default("0") # lesson_url :string(255) # # Indexes @@ -78,7 +76,6 @@ # - class Project < ApplicationRecord include Matchable include Publicable diff --git a/app/models/pull_request.rb b/app/models/pull_request.rb index ce0cb04ad..aec320858 100644 --- a/app/models/pull_request.rb +++ b/app/models/pull_request.rb @@ -37,7 +37,7 @@ class PullRequest < ApplicationRecord has_many :pull_request_tags, foreign_key: :pull_request_id has_many :project_trends, as: :trend, dependent: :destroy has_many :attachments, as: :container, dependent: :destroy - has_one :gitea_pull, foreign_key: :id, primary_key: :gitea_number, class_name: 'Gitea::Pull' + has_one :gitea_pull, foreign_key: :id, primary_key: :gitea_id, class_name: 'Gitea::Pull' scope :merged_and_closed, ->{where.not(status: 0)} scope :opening, -> {where(status: 0)} diff --git a/app/models/token.rb b/app/models/token.rb index c71a860af..db778c6b8 100644 --- a/app/models/token.rb +++ b/app/models/token.rb @@ -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 diff --git a/app/models/user.rb b/app/models/user.rb index fc4c33618..15c760a3f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -83,6 +83,7 @@ class User < Owner STATUS_ACTIVE = 1 STATUS_REGISTERED = 2 STATUS_LOCKED = 3 + STATUS_EDIT_INFO = 4 # tpi tpm权限控制 EDU_ADMIN = 1 # 超级管理员 @@ -174,7 +175,7 @@ class User < Owner has_one :user_template_message_setting, dependent: :destroy # 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| sql = "CONCAT(lastname, firstname) LIKE :search OR nickname LIKE :search OR login LIKE :search OR mail LIKE :search OR nickname LIKE :search" where(sql, :search => "%#{keywords.split(" ").join('|')}%") unless keywords.blank? @@ -412,6 +413,10 @@ class User < Owner status == STATUS_LOCKED end + def need_edit_info? + status == STATUS_EDIT_INFO + end + def activate self.status = STATUS_ACTIVE end @@ -424,6 +429,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 @@ -436,6 +445,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? diff --git a/app/views/oauth/register.html.erb b/app/views/oauth/register.html.erb index 96778fa06..372b2b04e 100644 --- a/app/views/oauth/register.html.erb +++ b/app/views/oauth/register.html.erb @@ -1,14 +1,19 @@
-

完善信息,进入比赛

+

平台已检测到您的如下信息,完善即可进入比赛

<%= form_tag('', method: :post, id: 'oauth_form', class: 'form-inline search-form flex-1', remote: true) do %> <%= hidden_field_tag 'callback_url', params[:callback_url] %>
- 用户名: - <%= text_field_tag :login, params[:login], placeholder: '请输入用户名', readonly: true, id: 'login' %> + 登录名: + <%= text_field_tag :login, params[:login], placeholder: '请输入登录名', readonly: true, id: 'login' %>

+
+ 用户名称: + <%= text_field_tag :lastname, params[:lastname], placeholder: '登录平台后显示的用户名称', maxlength: 40, id: 'lastname' %> +

+
邮箱: <%= text_field_tag :mail, params[:mail], placeholder: '请输入绑定邮箱', maxlength: 40, id: 'email' %> @@ -16,7 +21,7 @@
密码: - <%= password_field_tag :password, '', placeholder: '请输入账号密码', id: 'password' %> + <%= password_field_tag :password, '', placeholder: '输入EduCoder账号密码或新的密码',maxlength: 15, id: 'password' %>

@@ -29,6 +34,7 @@ function submitdata(){ var login = $("#login").val(); var email = $("#email").val(); + var lastname = $("#lastname").val(); var password = $("#password").val(); if(!login){ @@ -37,6 +43,12 @@ }else{ $(".loginCheck span").html(""); } + if(!lastname){ + $(".lastnameCheck span").html("请输入用户名称"); + return; + }else{ + $(".lastnameCheck span").html(""); + } if(!email){ $(".emailCheck span").html("请输入绑定的邮箱"); return; diff --git a/app/views/settings/show.json.jbuilder b/app/views/settings/show.json.jbuilder index 1147ffde2..93347c1d6 100644 --- a/app/views/settings/show.json.jbuilder +++ b/app/views/settings/show.json.jbuilder @@ -56,6 +56,7 @@ json.setting do end json.common @common + json.third_party @third_party if @top_system_notification.present? json.system_notification do diff --git a/app/views/users/get_user_info.json.jbuilder b/app/views/users/get_user_info.json.jbuilder index 2f96c6969..c02a3160f 100644 --- a/app/views/users/get_user_info.json.jbuilder +++ b/app/views/users/get_user_info.json.jbuilder @@ -10,6 +10,7 @@ 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.profile_completed @user.profile_is_completed? @@ -22,4 +23,4 @@ json.city @user.city json.custom_department @user.custom_department json.description @user.description json.(@user, :show_email, :show_department, :show_location) -json.message_unread_total @message_unread_total +json.message_unread_total @message_unread_total diff --git a/config/configuration.yml.example b/config/configuration.yml.example index 4671e4166..4c9683e12 100644 --- a/config/configuration.yml.example +++ b/config/configuration.yml.example @@ -44,6 +44,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: '' diff --git a/config/initializers/educoder_oauth_init.rb b/config/initializers/educoder_oauth_init.rb new file mode 100644 index 000000000..0f47cc7ce --- /dev/null +++ b/config/initializers/educoder_oauth_init.rb @@ -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']