diff --git a/app/controllers/api/v1/users_controller.rb b/app/controllers/api/v1/users_controller.rb index 55f5cfb22..37a41ff75 100644 --- a/app/controllers/api/v1/users_controller.rb +++ b/app/controllers/api/v1/users_controller.rb @@ -1,6 +1,78 @@ class Api::V1::UsersController < Api::V1::BaseController - def index - render_ok + before_action :load_observe_user + before_action :check_auth_for_observe_user + + def send_email_vefify_code + code = %W(0 1 2 3 4 5 6 7 8 9) + verification_code = code.sample(6).join + mail = params[:email] + code_type = params[:code_type] + + sign = Digest::MD5.hexdigest("#{OPENKEY}#{mail}") + Rails.logger.info sign + + tip_exception(501, "请求不合理") if sign != params[:smscode] + + # 60s内不能重复发送 + send_email_limit_cache_key = "send_email_60_second_limit:#{mail}" + tip_exception(-1, '请勿频繁操作') if Rails.cache.exist?(send_email_limit_cache_key) + send_email_control = LimitForbidControl::SendEmailCode.new(mail) + tip_exception(-1, '邮件发送太频繁,请稍后再试') if send_email_control.forbid? + begin + UserMailer.update_email(mail, verification_code).deliver_now + + Rails.cache.write(send_email_limit_cache_key, 1, expires_in: 1.minute) + send_email_control.increment! + rescue Exception => e + logger_error(e) + tip_exception(-2,"邮件发送失败,请稍后重试") + end + ver_params = {code_type: code_type, code: verification_code, email: mail} + data = VerificationCode.new(ver_params) + if data.save! + render_ok + else + tip_exception(-1, "创建数据失败") + end + end + + def check_password + password = params[:password] + return render_error("8~16位密码,支持字母数字和符号") unless password =~ CustomRegexp::PASSWORD + return render_error("密码错误") unless @observe_user.check_password?(password) + render_ok + end + + def check_email + mail = strip(params[:email]) + return render_error("邮件格式有误") unless mail =~ CustomRegexp::EMAIL + + exist_owner = Owner.find_by(mail: mail) + return render_error('邮箱已被使用') if exist_owner + render_ok + end + + def check_email_verify_code + code = strip(params[:code]) + mail = strip(params[:email]) + code_type = params[:code_type] + + return render_error("邮件格式有误") unless mail =~ CustomRegexp::EMAIL + + verifi_code = VerificationCode.where(email: mail, code: code, code_type: code_type).last + + return render_error("验证码不正确") if verifi_code&.code != code + return render_error("验证码已失效") if !verifi_code&.effective? + render_ok + end + + def update_email + @result_object = Api::V1::Users::UpdateEmailService.call(@observe_user, params, current_user.gitea_token) + if @result_object + return render_ok + else + return render_error('更改邮箱失败!') + end end end \ No newline at end of file diff --git a/app/controllers/attachments_controller.rb b/app/controllers/attachments_controller.rb index 79047b516..e9b767def 100644 --- a/app/controllers/attachments_controller.rb +++ b/app/controllers/attachments_controller.rb @@ -31,11 +31,11 @@ class AttachmentsController < ApplicationController def get_file normal_status(-1, "参数缺失") if params[:download_url].blank? - url = URI.encode(params[:download_url].to_s.gsub("http:", "https:")) + url = base_url.starts_with?("https:") ? URI.encode(params[:download_url].to_s.gsub("http:", "https:")) : URI.encode(params[:download_url].to_s) if url.starts_with?(base_url) domain = GiteaService.gitea_config[:domain] api_url = GiteaService.gitea_config[:base_url] - url = url.split(base_url)[1].gsub("api", "repos").gsub('?filepath=', '/').gsub('&', '?') + url = ("/repos"+url.split(base_url + "/api")[1]).gsub('?filepath=', '/').gsub('&', '?') request_url = [domain, api_url, url, "?ref=#{params[:ref]}&access_token=#{current_user&.gitea_token}"].join response = Faraday.get(request_url) filename = url.to_s.split("/").pop() diff --git a/app/controllers/concerns/api/user_helper.rb b/app/controllers/concerns/api/user_helper.rb index e6156ea56..4c7b713fc 100644 --- a/app/controllers/concerns/api/user_helper.rb +++ b/app/controllers/concerns/api/user_helper.rb @@ -16,4 +16,13 @@ module Api::UserHelper end @observe_user end + + # 是否具有查看用户或编辑用户的权限 + def check_auth_for_observe_user + return render_forbidden unless current_user.admin? || @observe_user.id == current_user.id + end + + def strip(str) + str.to_s.strip.presence + end end \ No newline at end of file diff --git a/app/controllers/concerns/register_helper.rb b/app/controllers/concerns/register_helper.rb index 2e910d8c4..e1b7dee24 100644 --- a/app/controllers/concerns/register_helper.rb +++ b/app/controllers/concerns/register_helper.rb @@ -16,6 +16,7 @@ module RegisterHelper return unless user.valid? interactor = Gitea::RegisterInteractor.call({username: username, email: email, password: password}) + result ={} if interactor.success? gitea_user = interactor.result result = Gitea::User::GenerateTokenService.call(username, password) @@ -26,7 +27,7 @@ module RegisterHelper result[:user] = {id: user.id, token: user.gitea_token} end else - result[:message] = interactor.error + result[:message] = interactor.result[:message] end result end diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb index 10af36f2b..5ee1fdde3 100644 --- a/app/controllers/repositories_controller.rb +++ b/app/controllers/repositories_controller.rb @@ -1,392 +1,397 @@ -class RepositoriesController < ApplicationController - include RepositoriesHelper - include ApplicationHelper - include OperateProjectAbilityAble - include Repository::LanguagesPercentagable - - before_action :require_login, only: %i[edit update create_file update_file delete_file sync_mirror] - before_action :require_profile_completed, only: [:create_file] - before_action :load_repository - before_action :authorizate!, except: [:sync_mirror, :tags, :commit, :archive] - before_action :authorizate_user_can_edit_repo!, only: %i[sync_mirror] - before_action :get_ref, only: %i[entries sub_entries top_counts files archive] - before_action :get_latest_commit, only: %i[entries sub_entries top_counts] - before_action :get_statistics, only: %i[top_counts] - - def files - result = @project.educoder? ? nil : Gitea::Repository::Files::GetService.call(@owner, @project.identifier, @ref, params[:search], @owner.gitea_token) - render json: result - end - - # 新版项目详情 - def detail - @user = current_user - @result = Repositories::DetailService.call(@owner, @repository, @user) - @project_fork_id = @project.try(:forked_from_project_id) - if @project_fork_id.present? - @fork_project = Project.find_by(id: @project_fork_id) - @fork_project_user = @fork_project.owner - end - rescue Exception => e - uid_logger_error(e.message) - tip_exception(e.message) - end - - def show - @user = current_user - @repo = @project.repository - @result = @project.forge? ? Gitea::Repository::GetService.new(@owner, @project.identifier).call : nil - @project_fork_id = @project.try(:forked_from_project_id) - if @project_fork_id.present? - @fork_project = Project.find_by(id: @project_fork_id) - @fork_project_user = @fork_project.owner - end - rescue Exception => e - uid_logger_error(e.message) - tip_exception(e.message) - end - - def entries - @project.increment!(:visits) - CacheAsyncSetJob.perform_later("project_common_service", {visits: 1}, @project.id) - if @project.educoder? - @entries = Educoder::Repository::Entries::ListService.call(@project&.project_educoder.repo_name) - else - @entries = Gitea::Repository::Entries::ListService.new(@owner, @project.identifier, ref: @ref).call - @entries = @entries.present? ? @entries.sort_by{ |hash| hash['type'] } : [] - @path = GiteaService.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/" - end - end - - def top_counts - @result = @project.educoder? ? nil : Gitea::Repository::GetService.new(@project.owner, @project.identifier).call - end - - def sub_entries - file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip)) - - if @project.educoder? - if params[:type] === 'file' - @sub_entries = Educoder::Repository::Entries::GetService.call(@project&.project_educoder&.repo_name, file_path_uri) - logger.info "######### sub_entries: #{@sub_entries}" - return render_error('该文件暂未开放,敬请期待.') if @sub_entries['status'].to_i === -1 - - tmp_entries = { - "content" => @sub_entries['data']['content'], - "type" => "blob" - } - @sub_entries = { - "trees"=>tmp_entries, - "commits" => [{}] - } - else - begin - @sub_entries = Educoder::Repository::Entries::ListService.call(@project&.project_educoder&.repo_name, {path: file_path_uri}) - if @sub_entries.blank? || @sub_entries['status'].to_i === -1 - @sub_entries = Educoder::Repository::Entries::GetService.call(@project&.project_educoder&.repo_name, file_path_uri) - return render_error('该文件暂未开放,敬请期待.') if @sub_entries['status'].to_i === -1 - tmp_entries = { - "content" => @sub_entries['data']['content'], - "type" => "blob" - } - @sub_entries = { - "trees"=>tmp_entries, - "commits" => [{}] - } - end - rescue - return render_error('该文件暂未开放,敬请期待.') - end - end - else - @path = GiteaService.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/" - interactor = Repositories::EntriesInteractor.call(@owner, @project.identifier, file_path_uri, ref: @ref) - if interactor.success? - result = interactor.result - @sub_entries = result.is_a?(Array) ? result.sort_by{ |hash| hash['type'] } : result - else - render_error(interactor.error) - end - end - end - - def commits - if @project.educoder? - @commits = Educoder::Repository::Commits::ListService.call(@project&.project_educoder&.repo_name) - else - if params[:filepath].present? - file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip)) - @hash_commit = Gitea::Repository::Commits::FileListService.new(@owner.login, @project.identifier, file_path_uri, - sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token).call - else - @hash_commit = Gitea::Repository::Commits::ListService.new(@owner.login, @project.identifier, - sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token).call - end - end - end - - def commits_slice - @hash_commit = Gitea::Repository::Commits::ListSliceService.call(@owner.login, @project.identifier, - sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token) - end - - def commit - @sha = params[:sha] - if @project.educoder? - return render_error('暂未开放,敬请期待.') - else - @commit = Gitea::Repository::Commits::GetService.call(@owner.login, @repository.identifier, @sha, current_user&.gitea_token) - @commit_diff = Gitea::Repository::Commits::GetService.call(@owner.login, @repository.identifier, @sha, current_user&.gitea_token, {diff: true}) - render_error(@commit[:message], @commit[:status]) if @commit.has_key?(:status) || @commit_diff.has_key?(:status) - end - end - - def tags - result = Gitea::Repository::Tags::ListService.call(current_user&.gitea_token, @owner.login, @project.identifier, {page: params[:page], limit: params[:limit]}) - - @tags = result.is_a?(Hash) && result.key?(:status) ? [] : result - end - - def contributors - if params[:filepath].present? || @project.educoder? - @contributors = [] - else - result = Gitea::Repository::Contributors::GetService.call(@owner, @repository.identifier) - @contributors = result.is_a?(Hash) && result.key?(:status) ? [] : result - end - rescue - @contributors = [] - end - - def edit - return render_forbidden if !@project.manager?(current_user) && !current_user.admin? - end - - def create_file - interactor = Gitea::CreateFileInteractor.call(current_user.gitea_token, @owner.login, content_params) - if interactor.success? - @file = interactor.result - # create_new_pr(params) - #如果是更新流水线文件 - if params[:pipeline_id] - update_pipeline(params[:pipeline_id]) - end - else - render_error(interactor.error) - end - end - - def update_pipeline(pipeline_id) - pipeline = Ci::Pipeline.find(pipeline_id) - if pipeline - pipeline.update!(sync: 1) - end - end - - def update_file - interactor = Gitea::UpdateFileInteractor.call(current_user.gitea_token, @owner.login, params.merge(identifier: @project.identifier)) - if interactor.success? - @file = interactor.result - # TODO: 是否创建pr - # create_new_pr(params) - render_result(1, "更新成功") - else - render_error(interactor.error) - end - end - - def delete_file - interactor = Gitea::DeleteFileInteractor.call(current_user.gitea_token, @owner.login, params.merge(identifier: @project.identifier)) - if interactor.success? - @file = interactor.result - render_result(1, "文件删除成功") - else - render_error(interactor.error) - end - end - - def repo_hook - - end - - def sync_mirror - return render_error("正在镜像中..") if @repository.mirror.waiting? - - @repository.sync_mirror! - SyncMirroredRepositoryJob.perform_later(@repository.id, current_user.id) - render_ok - end - - def readme - if params[:filepath].present? - result = Gitea::Repository::Readme::DirService.call(@owner.login, @repository.identifier, params[:filepath], params[:ref], current_user&.gitea_token) - else - result = Gitea::Repository::Readme::GetService.call(@owner.login, @repository.identifier, params[:ref], current_user&.gitea_token) - end - @path = GiteaService.gitea_config[:domain]+"/#{@owner.login}/#{@repository.identifier}/raw/branch/#{params[:ref]}/" - @readme = result[:status] === :success ? result[:body] : nil - @readme['content'] = decode64_content(@readme, @owner, @repository, params[:ref], @path) - @readme['replace_content'] = readme_decode64_content(@readme, @owner, @repository, params[:ref], @path) - render json: @readme.slice("type", "encoding", "size", "name", "path", "content", "sha", "replace_content") - rescue - render json: nil - end - - def languages - if @project.educoder? - render json: {} - else - render json: languages_precentagable - end - end - - def archive - domain = GiteaService.gitea_config[:domain] - api_url = GiteaService.gitea_config[:base_url] - archive_url = "/repos/#{@owner.login}/#{@repository.identifier}/archive/#{Addressable::URI.escape(params[:archive])}" - - file_path = [domain, api_url, archive_url].join - file_path = [file_path, "access_token=#{current_user&.gitea_token}"].join("?") if @repository.hidden? - - return render_not_found if !request.format.zip? && !request.format.gzip? - - redirect_to file_path - end - - def raw - domain = GiteaService.gitea_config[:domain] - api_url = GiteaService.gitea_config[:base_url] - - url = "/repos/#{@owner.login}/#{@repository.identifier}/raw/#{Addressable::URI.escape(params[:filepath])}?ref=#{Addressable::URI.escape(params[:ref])}" - file_path = [domain, api_url, url].join - file_path = [file_path, "access_token=#{current_user&.gitea_token}"].join("&") - - redirect_to file_path - end - - private - - def find_project - @project = Project.find params[:id] - render_not_found("未找到相关的仓库") unless @project - end - - def find_project_with_includes - @project = Project.includes(:repository, :owner, :watchers, :praise_treads).find params[:id] - end - - def authorizate! - return if current_user && current_user.admin? - if @project.repository.hidden? && !@project.member?(current_user) - render_forbidden - end - end - - # TODO 获取最新commit信息 - def project_commits - if params[:filepath].present? - file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip)) - Gitea::Repository::Commits::FileListService.new(@project.owner.login, @project.identifier, file_path_uri, - sha: get_ref, page: 1, limit: 1, token: current_user&.gitea_token).call - else - Gitea::Repository::Commits::ListService.new(@project.owner.login, @project.identifier, - sha: get_ref, page: 1, limit: 1, token: current_user&.gitea_token).call - end - end - - def get_statistics - @branches_count = @project.educoder? ? 0 : Gitea::Repository::Branches::ListService.new(@project.owner, @project.identifier).call&.size - @tags_count = @project.educoder? ? 0 : Gitea::Repository::Tags::ListService.new(current_user&.gitea_token, @project.owner.login, @project.identifier).call&.size - end - - def get_ref - @ref = params[:ref] || @project&.default_branch - end - - def get_latest_commit - latest_commit = @project.educoder? ? nil : project_commits - @latest_commit = latest_commit.present? ? latest_commit[:body][0] : nil - @commits_count = latest_commit.present? ? latest_commit[:total_count] : 0 - end - - def content_params - { - filepath: params[:filepath], - branch: params[:branch], - new_branch: params[:new_branch], - content: params[:content], - message: params[:message], - committer: { - email: current_user.mail, - name: current_user.login - }, - identifier: @project.identifier - } - end - - def hook_params(hook_type, params) - # if hook_type == "push" - # # TODO hook返回的记录中,暂时没有文件代码数量的增减,暂时根据 commits数量来计算 - # uploadPushInfo = { - # "sha": params["commits"].present? ? params["commits"].last : "", - # "branch": params["ref"].to_s.split("/").last, - # "modification_lines": params["commits"].length - # } - # elsif hook_type == "pull_request" && params["action"].to_s == "closed" #合并请求合并后才会有上链操作 - # uploadPushInfo = { - # "branch": params["base"]["ref"].to_s.split("/").last, - # "sha": params["pull_request"]["merge_base"], - # "modification_lines": 1 #pull_request中没有commits数量 - # } - # else - # uploadPushInfo = {} - # end - - # uploadPushInfo - end - - def create_new_pr(params) - if params[:new_branch].present? && params[:new_branch] != params[:branch] - local_params = { - title: params[:message], #标题 - body: params[:content], #内容 - head: params[:new_branch], #源分支 - base: params[:branch], #目标分支 - milestone: 0 #里程碑,未与本地的里程碑关联 - - } - requests_params = local_params.merge({ - assignee: current_user.try(:login), - assignees: [], - labels: [], - due_date: Time.now - }) - - issue_params = { - author_id: current_user.id, - project_id: @project.id, - subject: params[:message], - description: params[:content], - assigned_to_id: nil, - fixed_version_id: nil, - issue_tags_value: nil, - issue_classify: "pull_request", - issue_type: "1", - tracker_id: 2, - status_id: 1, - priority_id: params[:priority_id] || "2" - } - @pull_issue = Issue.new(issue_params) - if @pull_issue.save! - 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"]) - local_requests.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create") - end - end - end - end - end - -end +class RepositoriesController < ApplicationController + include RepositoriesHelper + include ApplicationHelper + include OperateProjectAbilityAble + include Repository::LanguagesPercentagable + + before_action :require_login, only: %i[edit update create_file update_file delete_file sync_mirror] + before_action :require_profile_completed, only: [:create_file] + before_action :load_repository + before_action :authorizate!, except: [:sync_mirror, :tags, :commit, :archive] + before_action :authorizate_user_can_edit_repo!, only: %i[sync_mirror] + before_action :get_ref, only: %i[entries sub_entries top_counts files archive] + before_action :get_latest_commit, only: %i[entries sub_entries top_counts] + before_action :get_statistics, only: %i[top_counts] + + def files + result = @project.educoder? ? nil : Gitea::Repository::Files::GetService.call(@owner, @project.identifier, @ref, params[:search], @owner.gitea_token) + render json: result + end + + # 新版项目详情 + def detail + @user = current_user + @result = Repositories::DetailService.call(@owner, @repository, @user) + @project_fork_id = @project.try(:forked_from_project_id) + if @project_fork_id.present? + @fork_project = Project.find_by(id: @project_fork_id) + @fork_project_user = @fork_project.owner + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + + def show + @user = current_user + @repo = @project.repository + @result = @project.forge? ? Gitea::Repository::GetService.new(@owner, @project.identifier).call : nil + @project_fork_id = @project.try(:forked_from_project_id) + if @project_fork_id.present? + @fork_project = Project.find_by(id: @project_fork_id) + @fork_project_user = @fork_project.owner + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + + def entries + @week_project_visit_record, @month_project_visit_record = TimeableVisitRecord.build(@project.id) + if @week_project_visit_record.visits < 300 && @month_project_visit_record.visits < 1000 + @week_project_visit_record.increment!(:visits) + @month_project_visit_record.increment!(:visits) + @project.increment!(:visits) + CacheAsyncSetJob.perform_later("project_common_service", {visits: 1}, @project.id) + end + if @project.educoder? + @entries = Educoder::Repository::Entries::ListService.call(@project&.project_educoder.repo_name) + else + @entries = Gitea::Repository::Entries::ListService.new(@owner, @project.identifier, ref: @ref).call + @entries = @entries.present? ? @entries.sort_by{ |hash| hash['type'] } : [] + @path = GiteaService.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/" + end + end + + def top_counts + @result = @project.educoder? ? nil : Gitea::Repository::GetService.new(@project.owner, @project.identifier).call + end + + def sub_entries + file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip)) + + if @project.educoder? + if params[:type] === 'file' + @sub_entries = Educoder::Repository::Entries::GetService.call(@project&.project_educoder&.repo_name, file_path_uri) + logger.info "######### sub_entries: #{@sub_entries}" + return render_error('该文件暂未开放,敬请期待.') if @sub_entries['status'].to_i === -1 + + tmp_entries = { + "content" => @sub_entries['data']['content'], + "type" => "blob" + } + @sub_entries = { + "trees"=>tmp_entries, + "commits" => [{}] + } + else + begin + @sub_entries = Educoder::Repository::Entries::ListService.call(@project&.project_educoder&.repo_name, {path: file_path_uri}) + if @sub_entries.blank? || @sub_entries['status'].to_i === -1 + @sub_entries = Educoder::Repository::Entries::GetService.call(@project&.project_educoder&.repo_name, file_path_uri) + return render_error('该文件暂未开放,敬请期待.') if @sub_entries['status'].to_i === -1 + tmp_entries = { + "content" => @sub_entries['data']['content'], + "type" => "blob" + } + @sub_entries = { + "trees"=>tmp_entries, + "commits" => [{}] + } + end + rescue + return render_error('该文件暂未开放,敬请期待.') + end + end + else + @path = GiteaService.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/" + interactor = Repositories::EntriesInteractor.call(@owner, @project.identifier, file_path_uri, ref: @ref) + if interactor.success? + result = interactor.result + @sub_entries = result.is_a?(Array) ? result.sort_by{ |hash| hash['type'] } : result + else + render_error(interactor.error) + end + end + end + + def commits + if @project.educoder? + @commits = Educoder::Repository::Commits::ListService.call(@project&.project_educoder&.repo_name) + else + if params[:filepath].present? + file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip)) + @hash_commit = Gitea::Repository::Commits::FileListService.new(@owner.login, @project.identifier, file_path_uri, + sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token).call + else + @hash_commit = Gitea::Repository::Commits::ListService.new(@owner.login, @project.identifier, + sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token).call + end + end + end + + def commits_slice + @hash_commit = Gitea::Repository::Commits::ListSliceService.call(@owner.login, @project.identifier, + sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token) + end + + def commit + @sha = params[:sha] + if @project.educoder? + return render_error('暂未开放,敬请期待.') + else + @commit = Gitea::Repository::Commits::GetService.call(@owner.login, @repository.identifier, @sha, current_user&.gitea_token) + @commit_diff = Gitea::Repository::Commits::GetService.call(@owner.login, @repository.identifier, @sha, current_user&.gitea_token, {diff: true}) + render_error(@commit[:message], @commit[:status]) if @commit.has_key?(:status) || @commit_diff.has_key?(:status) + end + end + + def tags + result = Gitea::Repository::Tags::ListService.call(current_user&.gitea_token, @owner.login, @project.identifier, {page: params[:page], limit: params[:limit]}) + + @tags = result.is_a?(Hash) && result.key?(:status) ? [] : result + end + + def contributors + if params[:filepath].present? || @project.educoder? + @contributors = [] + else + result = Gitea::Repository::Contributors::GetService.call(@owner, @repository.identifier) + @contributors = result.is_a?(Hash) && result.key?(:status) ? [] : result + end + rescue + @contributors = [] + end + + def edit + return render_forbidden if !@project.manager?(current_user) && !current_user.admin? + end + + def create_file + interactor = Gitea::CreateFileInteractor.call(current_user.gitea_token, @owner.login, content_params) + if interactor.success? + @file = interactor.result + # create_new_pr(params) + #如果是更新流水线文件 + if params[:pipeline_id] + update_pipeline(params[:pipeline_id]) + end + else + render_error(interactor.error) + end + end + + def update_pipeline(pipeline_id) + pipeline = Ci::Pipeline.find(pipeline_id) + if pipeline + pipeline.update!(sync: 1) + end + end + + def update_file + interactor = Gitea::UpdateFileInteractor.call(current_user.gitea_token, @owner.login, params.merge(identifier: @project.identifier)) + if interactor.success? + @file = interactor.result + # TODO: 是否创建pr + # create_new_pr(params) + render_result(1, "更新成功") + else + render_error(interactor.error) + end + end + + def delete_file + interactor = Gitea::DeleteFileInteractor.call(current_user.gitea_token, @owner.login, params.merge(identifier: @project.identifier)) + if interactor.success? + @file = interactor.result + render_result(1, "文件删除成功") + else + render_error(interactor.error) + end + end + + def repo_hook + + end + + def sync_mirror + return render_error("正在镜像中..") if @repository.mirror.waiting? + + @repository.sync_mirror! + SyncMirroredRepositoryJob.perform_later(@repository.id, current_user.id) + render_ok + end + + def readme + if params[:filepath].present? + result = Gitea::Repository::Readme::DirService.call(@owner.login, @repository.identifier, params[:filepath], params[:ref], current_user&.gitea_token) + else + result = Gitea::Repository::Readme::GetService.call(@owner.login, @repository.identifier, params[:ref], current_user&.gitea_token) + end + @path = GiteaService.gitea_config[:domain]+"/#{@owner.login}/#{@repository.identifier}/raw/branch/#{params[:ref]}/" + @readme = result[:status] === :success ? result[:body] : nil + @readme['content'] = decode64_content(@readme, @owner, @repository, params[:ref], @path) + @readme['replace_content'] = readme_decode64_content(@readme, @owner, @repository, params[:ref], @path) + render json: @readme.slice("type", "encoding", "size", "name", "path", "content", "sha", "replace_content") + rescue + render json: nil + end + + def languages + if @project.educoder? + render json: {} + else + render json: languages_precentagable + end + end + + def archive + domain = GiteaService.gitea_config[:domain] + api_url = GiteaService.gitea_config[:base_url] + archive_url = "/repos/#{@owner.login}/#{@repository.identifier}/archive/#{Addressable::URI.escape(params[:archive])}" + + file_path = [domain, api_url, archive_url].join + file_path = [file_path, "access_token=#{current_user&.gitea_token}"].join("?") if @repository.hidden? + + return render_not_found if !request.format.zip? && !request.format.gzip? + + redirect_to file_path + end + + def raw + domain = GiteaService.gitea_config[:domain] + api_url = GiteaService.gitea_config[:base_url] + + url = "/repos/#{@owner.login}/#{@repository.identifier}/raw/#{Addressable::URI.escape(params[:filepath])}?ref=#{Addressable::URI.escape(params[:ref])}" + file_path = [domain, api_url, url].join + file_path = [file_path, "access_token=#{current_user&.gitea_token}"].join("&") + + redirect_to file_path + end + + private + + def find_project + @project = Project.find params[:id] + render_not_found("未找到相关的仓库") unless @project + end + + def find_project_with_includes + @project = Project.includes(:repository, :owner, :watchers, :praise_treads).find params[:id] + end + + def authorizate! + return if current_user && current_user.admin? + if @project.repository.hidden? && !@project.member?(current_user) + render_forbidden + end + end + + # TODO 获取最新commit信息 + def project_commits + if params[:filepath].present? + file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip)) + Gitea::Repository::Commits::FileListService.new(@project.owner.login, @project.identifier, file_path_uri, + sha: get_ref, page: 1, limit: 1, token: current_user&.gitea_token).call + else + Gitea::Repository::Commits::ListService.new(@project.owner.login, @project.identifier, + sha: get_ref, page: 1, limit: 1, token: current_user&.gitea_token).call + end + end + + def get_statistics + @branches_count = @project.educoder? ? 0 : Gitea::Repository::Branches::ListService.new(@project.owner, @project.identifier).call&.size + @tags_count = @project.educoder? ? 0 : Gitea::Repository::Tags::ListService.new(current_user&.gitea_token, @project.owner.login, @project.identifier).call&.size + end + + def get_ref + @ref = params[:ref] || @project&.default_branch + end + + def get_latest_commit + latest_commit = @project.educoder? ? nil : project_commits + @latest_commit = latest_commit.present? ? latest_commit[:body][0] : nil + @commits_count = latest_commit.present? ? latest_commit[:total_count] : 0 + end + + def content_params + { + filepath: params[:filepath], + branch: params[:branch], + new_branch: params[:new_branch], + content: params[:content], + message: params[:message], + committer: { + email: current_user.mail, + name: current_user.login + }, + identifier: @project.identifier + } + end + + def hook_params(hook_type, params) + # if hook_type == "push" + # # TODO hook返回的记录中,暂时没有文件代码数量的增减,暂时根据 commits数量来计算 + # uploadPushInfo = { + # "sha": params["commits"].present? ? params["commits"].last : "", + # "branch": params["ref"].to_s.split("/").last, + # "modification_lines": params["commits"].length + # } + # elsif hook_type == "pull_request" && params["action"].to_s == "closed" #合并请求合并后才会有上链操作 + # uploadPushInfo = { + # "branch": params["base"]["ref"].to_s.split("/").last, + # "sha": params["pull_request"]["merge_base"], + # "modification_lines": 1 #pull_request中没有commits数量 + # } + # else + # uploadPushInfo = {} + # end + + # uploadPushInfo + end + + def create_new_pr(params) + if params[:new_branch].present? && params[:new_branch] != params[:branch] + local_params = { + title: params[:message], #标题 + body: params[:content], #内容 + head: params[:new_branch], #源分支 + base: params[:branch], #目标分支 + milestone: 0 #里程碑,未与本地的里程碑关联 + + } + requests_params = local_params.merge({ + assignee: current_user.try(:login), + assignees: [], + labels: [], + due_date: Time.now + }) + + issue_params = { + author_id: current_user.id, + project_id: @project.id, + subject: params[:message], + description: params[:content], + assigned_to_id: nil, + fixed_version_id: nil, + issue_tags_value: nil, + issue_classify: "pull_request", + issue_type: "1", + tracker_id: 2, + status_id: 1, + priority_id: params[:priority_id] || "2" + } + @pull_issue = Issue.new(issue_params) + if @pull_issue.save! + 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"]) + local_requests.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create") + end + end + end + end + end + +end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index ff1d4b887..c70f053f6 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -109,6 +109,19 @@ class UsersController < ApplicationController @user = current_user end + # cloudIDE saas定制 + def info + @code = 1001 + @message = "用户不存在" + if params[:token].present? + @user = User.try_to_autologin(params[:token]) + if @user.present? + @code = 1000 + @message = "success" + end + end + end + # 贴吧获取用户信接口 def get_user_info begin diff --git a/app/docs/slate/source/includes/_users.md b/app/docs/slate/source/includes/_users.md index 318c7930a..e16a52033 100644 --- a/app/docs/slate/source/includes/_users.md +++ b/app/docs/slate/source/includes/_users.md @@ -2304,4 +2304,189 @@ await octokit.request('GET /api/users/:login/applied_projects/:id/refuse.json') "created_at": "2021-06-09 16:41", "time_ago": "7分钟前" } +``` + + +## 用户发送邮件验证码 +用户发送邮件验证码 + +> 示例: + +```shell +curl -X GET http://localhost:3000/api/v1/yystopf/send_email_vefify_code.json +``` + +```javascript +await octokit.request('GET /api/v1/:login/send_email_vefify_code.json') +``` + +### HTTP 请求 +`GET /api/v1/:login/send_email_vefify_code.json` + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|login |string |用户标识 | +|code_type |int |10: 更新邮箱| +|email |string |邮箱| +|smscode |string |邮箱md5加密值| + +### 返回字段说明: + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} +``` + + +## 用户验证邮件验证码 +用户验证邮件验证码 + +> 示例: + +```shell +curl -X POST http://localhost:3000/api/v1/yystopf/check_email_verify_code.json +``` + +```javascript +await octokit.request('POST /api/v1/:login/check_email_verify_code.json') +``` + +### HTTP 请求 +`POST /api/v1/:login/check_email_verify_code.json` + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|login |string |用户标识 | +|code_type |int |10: 更新邮箱| +|email |string |邮箱| +|code |string |邮箱验证码| + +### 返回字段说明: + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} +``` + + +## 用户验证密码 +用户验证密码,检查是否和用户密码一致 + +> 示例: + +```shell +curl -X POST http://localhost:3000/api/v1/yystopf/check_password.json +``` + +```javascript +await octokit.request('POST /api/v1/:login/check_password.json') +``` + +### HTTP 请求 +`POST /api/v1/:login/check_password.json` + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|login |string |用户标识 | +|password |string |用户密码| + +### 返回字段说明: + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} +``` + + +## 用户验证邮箱 +用户验证邮箱是否符合规范以及是否已被使用 + +> 示例: + +```shell +curl -X POST http://localhost:3000/api/v1/yystopf/check_email.json +``` + +```javascript +await octokit.request('POST /api/v1/:login/check_email.json') +``` + +### HTTP 请求 +`POST /api/v1/:login/check_email.json` + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|login |string |用户标识 | +|email |string |邮箱地址| + +### 返回字段说明: + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} +``` + + +## 用户更改邮箱 +用户更改一个新的邮箱 + +> 示例: + +```shell +curl -X PATCH http://localhost:3000/api/v1/yystopf/update_email.json +``` + +```javascript +await octokit.request('PATCH /api/v1/:login/update_email.json') +``` + +### HTTP 请求 +`PATCH /api/v1/:login/update_email.json` + +### 请求字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|login |string |用户标识 | +|password |string |用户密码| +|email |string |邮箱地址| +|code |string |邮箱验证码| + + +> 请求的JSON示例: + +```json +{ + "password": "Aa19960425.", + "code": "657134", + "email": "yystopf@163.com" +} +``` + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} ``` \ No newline at end of file diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index c9ea87f9a..b4c21e044 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -65,6 +65,7 @@ module ProjectsHelper license_id: project.license_id, jianmu_devops: jianmu_devops_code(project, user), jianmu_devops_url: jianmu_devops_url, + cloud_ide_saas_url: cloud_ide_saas_url(user), ignore_id: project.ignore_id }).compact @@ -128,6 +129,15 @@ module ProjectsHelper EduSetting.get("jianmu_devops_url") || "https://ci-v3.test.jianmuhub.com" end + + def cloud_ide_saas_url(user) + "" unless user.logged? + token = Token.get_token_from_user(user, "autologin") + oauth_url = "#{Rails.application.config_for(:configuration)['platform_url']}/api/users/info.json" + saas_url = EduSetting.get("cloud_ide_saas_url") || "https://saasfactory.test.opentrs.com" + "#{saas_url}/oauth/login?product_account_id=PA1001218&tenant_code=TI1001383&oauth_url=#{oauth_url}&token=#{token.value}" + end + def aes_encrypt(key, des_text) # des_text='{"access_key_id":"STS.NTuC9RVmWfJqj3JkcMzPnDf7X","access_key_secret":"E8NxRZWGNxxMfwgt5nFLnBFgg6AzgXCZkSNCyqygLuHM","end_point":"oss-accelerate.aliyuncs.com","security_token":"CAIS8gF1q6Ft5B2yfSjIr5fACIPmu7J20YiaaBX7j2MYdt9Cq6Ocujz2IHhMenVhA+8Wv/02n2hR7PcYlq9IS55VWEqc/VXLaywQo22beIPkl5Gfz95t0e+IewW6Dxr8w7WhAYHQR8/cffGAck3NkjQJr5LxaTSlWS7OU/TL8+kFCO4aRQ6ldzFLKc5LLw950q8gOGDWKOymP2yB4AOSLjIx6lAt2T8vs/7hmZPFukSFtjCglL9J/baWC4O/csxhMK14V9qIx+FsfsLDqnUIs0YWpf0p3P0doGyf54vMWUM05A6dduPS7txkLAJwerjVl1/ADxc0/hqAASXhPeiktbmDjwvnSn4iKcSGQ+xoQB468eHXNdvf13dUlbbE1+JhRi0pZIB2UCtN9oTsLHcwIHt+EJaoMd3+hGwPVmvHSXzECDFHylZ8l/pzTwlE/aCtZyVmI5cZEvmWu2xBa3GRbULo7lLvyeX1cHTVmVWf4Nk6D09PzTU8qlAj","bucket":"edu-bigfiles1","region":"oss-cn-hangzhou","callback_url":"https://data.educoder.net/api/buckets/callback.json","bucket_host":"data.educoder.net"}' # des = OpenSSL::Cipher::Cipher.new('aes-256-ctr') diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index acd34fbbd..19f565183 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -1,11 +1,16 @@ -class UserMailer < ApplicationMailer - # 注意:这个地方一定要和你的邮箱服务域名一致 - default from: 'notification@trustie.org' - - # 用户注册验证码 - def register_email(mail, code) - @code = code - mail(to: mail, subject: 'Gitink | 注册验证码') - end - -end +class UserMailer < ApplicationMailer + # 注意:这个地方一定要和你的邮箱服务域名一致 + # default from: 'notification@trustie.org' + default from: 'noreply@gitlink.org.cn' + + # 用户注册验证码 + def register_email(mail, code) + @code = code + mail(to: mail, subject: 'Gitink | 注册验证码') + end + + def update_email(mail, code) + @code = code + mail(to: mail, subject: 'Gitink | 更改邮箱验证码') + end +end diff --git a/app/models/timeable_visit_record.rb b/app/models/timeable_visit_record.rb new file mode 100644 index 000000000..8411ddf66 --- /dev/null +++ b/app/models/timeable_visit_record.rb @@ -0,0 +1,28 @@ +# == Schema Information +# +# Table name: timeable_visit_records +# +# id :integer not null, primary key +# time :string(255) +# project_id :integer +# visits :integer +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_timeable_visit_records_on_project_id (project_id) +# index_timeable_visit_records_on_time (time) +# + +class TimeableVisitRecord < ApplicationRecord + + belongs_to :project + + def self.build(project_id) + week = TimeableVisitRecord.find_or_create_by!(time: Date.today.strftime("%Y-%W"), project_id: project_id) + month = TimeableVisitRecord.find_or_create_by!(time: Date.today.strftime("%Y%m"), project_id: project_id) + + return week, month + end +end diff --git a/app/services/api/v1/users/update_email_service.rb b/app/services/api/v1/users/update_email_service.rb new file mode 100644 index 000000000..e11dd2f61 --- /dev/null +++ b/app/services/api/v1/users/update_email_service.rb @@ -0,0 +1,68 @@ +class Api::V1::Users::UpdateEmailService < ApplicationService + include ActiveModel::Model + + attr_reader :user, :token, :password, :mail, :old_mail, :code, :verify_code + attr_accessor :gitea_data + + validates :password, :code, presence: true + validates :mail, presence: true, format: { with: CustomRegexp::EMAIL } + + def initialize(user, params, token =nil) + @user = user + @token = token + @password = params[:password] + @mail = params[:email] + @old_mail = user.mail + @code = params[:code] + @verify_code = VerificationCode.where(email: @mail, code: @code, code_type: 10).last + end + + def call + raise Error, errors.full_messages.join(",") unless valid? + raise Error, "密码不正确." unless @user.check_password?(@password) + raise Error, "验证码不正确." if @verify_code&.code != @code + raise Error, "验证码已失效." if !@verify_code&.effective? + + # begin + ActiveRecord::Base.transaction do + change_user_email + excute_data_to_gitea + excute_change_email_from_gitea + end + + return gitea_data + + # rescue + # raise Error, "服务器错误,请联系系统管理员!" + # end + end + + private + def request_params + { + access_token: token + } + end + + def request_body + { + email: @mail, + login_name: @user.login, + source_id: 0 + } + end + + def change_user_email + @user.update_attributes!({mail: @mail}) + end + + def excute_data_to_gitea + Rails.logger.info request_body + @gitea_data = $gitea_client.patch_admin_users_by_username(@user.login, {body: request_body.to_json}) + end + + def excute_change_email_from_gitea + $gitea_client.delete_user_emails({body: {emails: [@old_mail]}.to_json, query: request_params}) + $gitea_client.post_user_emails({body: {emails: [@mail]}.to_json, query: request_params}) + end +end \ No newline at end of file diff --git a/app/services/cache/v2/project_common_service.rb b/app/services/cache/v2/project_common_service.rb index 97023ae29..0d167c2a7 100644 --- a/app/services/cache/v2/project_common_service.rb +++ b/app/services/cache/v2/project_common_service.rb @@ -133,6 +133,8 @@ class Cache::V2::ProjectCommonService < ApplicationService end if @watchers.present? $redis_cache.hincrby(project_common_key, watchers_key, @watchers) + Cache::V2::ProjectRankService.call(@project_id, {watchers: @watchers}) + Cache::V2::ProjectDateRankService.call(@project_id, Date.today, {watchers: @watchers}) end if @praises.present? $redis_cache.hincrby(project_common_key, praises_key, @praises) diff --git a/app/services/cache/v2/project_date_rank_service.rb b/app/services/cache/v2/project_date_rank_service.rb index 08aae6f77..9d8ffca90 100644 --- a/app/services/cache/v2/project_date_rank_service.rb +++ b/app/services/cache/v2/project_date_rank_service.rb @@ -7,6 +7,7 @@ class Cache::V2::ProjectDateRankService < ApplicationService @project_id = project_id @rank_date = rank_date @visits = params[:visits] + @watchers = params[:watchers] @praises = params[:praises] @forks = params[:forks] @issues = params[:issues] @@ -35,6 +36,9 @@ class Cache::V2::ProjectDateRankService < ApplicationService if @visits.present? $redis_cache.zincrby(project_rank_key, @visits.to_i * 1, @project_id) end + if @watchers.present? + $redis_cache.zincrby(project_rank_key, @watchers.to_i * 5, @project_id) + end if @praises.present? $redis_cache.zincrby(project_rank_key, @praises.to_i * 5, @project_id) end @@ -42,13 +46,13 @@ class Cache::V2::ProjectDateRankService < ApplicationService $redis_cache.zincrby(project_rank_key, @forks.to_i * 10, @project_id) end if @issues.present? - $redis_cache.zincrby(project_rank_key, @issues.to_i * 10, @project_id) + $redis_cache.zincrby(project_rank_key, @issues.to_i * 5, @project_id) end if @pullrequests.present? $redis_cache.zincrby(project_rank_key, @pullrequests.to_i * 10, @project_id) end if @commits.present? - $redis_cache.zincrby(project_rank_key, @commits.to_i * 1, @project_id) + $redis_cache.zincrby(project_rank_key, @commits.to_i * 5, @project_id) end $redis_cache.zscore(project_rank_key, @project_id) diff --git a/app/services/cache/v2/project_rank_service.rb b/app/services/cache/v2/project_rank_service.rb index 3265c0a6c..b88c416c4 100644 --- a/app/services/cache/v2/project_rank_service.rb +++ b/app/services/cache/v2/project_rank_service.rb @@ -5,6 +5,7 @@ class Cache::V2::ProjectRankService < ApplicationService def initialize(project_id, params={}) @project_id = project_id @visits = params[:visits] + @watchers = params[:watchers] @praises = params[:praises] @forks = params[:forks] @issues = params[:issues] @@ -51,6 +52,9 @@ class Cache::V2::ProjectRankService < ApplicationService if @visits.present? $redis_cache.zincrby(project_rank_key, @visits.to_i * 1, @project_id) end + if @watchers.present? + $redis_cache.zincrby(project_rank_key, @watchers.to_i * 5, @project_id) + end if @praises.present? $redis_cache.zincrby(project_rank_key, @praises.to_i * 5, @project_id) end @@ -58,13 +62,13 @@ class Cache::V2::ProjectRankService < ApplicationService $redis_cache.zincrby(project_rank_key, @forks.to_i * 10, @project_id) end if @issues.present? - $redis_cache.zincrby(project_rank_key, @issues.to_i * 10, @project_id) + $redis_cache.zincrby(project_rank_key, @issues.to_i * 5, @project_id) end if @pullrequests.present? $redis_cache.zincrby(project_rank_key, @pullrequests.to_i * 10, @project_id) end if @commits.present? - $redis_cache.zincrby(project_rank_key, @commits.to_i * 1, @project_id) + $redis_cache.zincrby(project_rank_key, @commits.to_i * 5, @project_id) end reset_user_project_rank end @@ -74,7 +78,7 @@ class Cache::V2::ProjectRankService < ApplicationService def reset_project_rank load_project_common - score = @project_common["visits"].to_i * 1 + @project_common["praises"].to_i * 5 + @project_common["forks"].to_i * 10 + @project_common["issues"].to_i * 10 + @project_common["pullrequests"].to_i * 10 + @project_common["commits"].to_i * 1 + score = @project_common["visits"].to_i * 1 + @project_common["watchers"].to_i * 5 + @project_common["praises"].to_i * 5 + @project_common["forks"].to_i * 10 + @project_common["issues"].to_i * 5 + @project_common["pullrequests"].to_i * 10 + @project_common["commits"].to_i * 5 $redis_cache.zadd(project_rank_key, score, @project_id) reset_user_project_rank diff --git a/app/views/admins/nps/index.html.erb b/app/views/admins/nps/index.html.erb index c7c208378..81e11dd2f 100644 --- a/app/views/admins/nps/index.html.erb +++ b/app/views/admins/nps/index.html.erb @@ -35,7 +35,7 @@ 期待更加丰富的功能:<%= UserNp.where("memo like '%期待更加丰富的功能%'").count %>, 希望有新手引导:<%= UserNp.where("memo like '%希望有新手引导%'").count %>, 提升用户体验:<%= UserNp.where("memo like '%用户体验需进一步提升%'").count %>, - 其他:<%= UserNp.where("action_type !='close'").where("memo is not null").where.not(id: UserNp.where("memo like '%期待更加丰富的功能%' or memo like '%希望有新手引导%' or memo like '%用户体验需进一步提升%' ").ids).count %> + 其他:<%= UserNp.where("action_type !='close'").where("LENGTH(memo) >0").where.not(id: UserNp.where("memo like '%期待更加丰富的功能%' or memo like '%希望有新手引导%' or memo like '%用户体验需进一步提升%' ").ids).count %>
+ 您好! +
++ 你正在进行GitLink邮箱更改操作,如非本人操作,请忽略。 +
+<%= @code %>
++ 如果您并未发过此请求,则可能是因为其他用户在注册时误输了您的邮件地址,而使您收到了这封邮件,那么您可以放心的忽略此邮件,无需进一步采取任何操作。 +
+用户发送邮件验证码
+ +++示例:
+
curl -X GET http://localhost:3000/api/v1/yystopf/send_email_vefify_code.json
+
await octokit.request('GET /api/v1/:login/send_email_vefify_code.json')
+
GET /api/v1/:login/send_email_vefify_code.json
参数 | +类型 | +字段说明 | +
---|---|---|
login | +string | +用户标识 | +
code_type | +int | +10: 更新邮箱 | +
string | +邮箱 | +|
smscode | +string | +邮箱md5加密值 | +
++返回的JSON示例:
+
{
+ "status": 0,
+ "message": "success"
+}
+
用户验证邮件验证码
+ +++示例:
+
curl -X POST http://localhost:3000/api/v1/yystopf/check_email_verify_code.json
+
await octokit.request('POST /api/v1/:login/check_email_verify_code.json')
+
POST /api/v1/:login/check_email_verify_code.json
参数 | +类型 | +字段说明 | +
---|---|---|
login | +string | +用户标识 | +
code_type | +int | +10: 更新邮箱 | +
string | +邮箱 | +|
code | +string | +邮箱验证码 | +
++返回的JSON示例:
+
{
+ "status": 0,
+ "message": "success"
+}
+
用户验证密码,检查是否和用户密码一致
+ +++示例:
+
curl -X POST http://localhost:3000/api/v1/yystopf/check_password.json
+
await octokit.request('POST /api/v1/:login/check_password.json')
+
POST /api/v1/:login/check_password.json
参数 | +类型 | +字段说明 | +
---|---|---|
login | +string | +用户标识 | +
password | +string | +用户密码 | +
++返回的JSON示例:
+
{
+ "status": 0,
+ "message": "success"
+}
+
用户验证邮箱是否符合规范以及是否已被使用
+ +++示例:
+
curl -X POST http://localhost:3000/api/v1/yystopf/check_email.json
+
await octokit.request('POST /api/v1/:login/check_email.json')
+
POST /api/v1/:login/check_email.json
参数 | +类型 | +字段说明 | +
---|---|---|
login | +string | +用户标识 | +
string | +邮箱地址 | +
++返回的JSON示例:
+
{
+ "status": 0,
+ "message": "success"
+}
+
用户更改一个新的邮箱
+ +++示例:
+
curl -X PATCH http://localhost:3000/api/v1/yystopf/update_email.json
+
await octokit.request('PATCH /api/v1/:login/update_email.json')
+
PATCH /api/v1/:login/update_email.json
参数 | +类型 | +字段说明 | +
---|---|---|
login | +string | +用户标识 | +
password | +string | +用户密码 | +
string | +邮箱地址 | +|
code | +string | +邮箱验证码 | +
++请求的JSON示例:
+
{
+ "password": "Aa19960425.",
+ "code": "657134",
+ "email": "yystopf@163.com"
+}
+
++返回的JSON示例:
+
{
+ "status": 0,
+ "message": "success"
+}
当前登录(管理员)用户获取项目邀请链接的接口(第一次请求会默认生成role类型为developer和is_apply为true的链接)