| @@ -204,4 +204,14 @@ input.form-control { | |||
| color: #23272B; | |||
| font-size: 1rem; | |||
| } | |||
| } | |||
| .table th, .table td { | |||
| padding: 0.75rem 0.1rem; | |||
| vertical-align: top; | |||
| border-top: 1px solid #dee2e6; | |||
| } | |||
| .table .thead-light th{ | |||
| white-space: nowrap; | |||
| } | |||
| @@ -1,6 +1,6 @@ | |||
| class Admins::ProjectIgnoresController < Admins::BaseController | |||
| before_action :set_ignore, only: [:edit,:update, :destroy,:show] | |||
| before_action :validate_params, only: [:create, :update] | |||
| # before_action :validate_params, only: [:create, :update] | |||
| def index | |||
| sort_by = Ignore.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at' | |||
| @@ -31,12 +31,12 @@ class Admins::ProjectIgnoresController < Admins::BaseController | |||
| # } | |||
| @project_ignore = Ignore.new(ignore_params) | |||
| if @project_ignore.save! | |||
| if @project_ignore.save | |||
| redirect_to admins_project_ignores_path | |||
| flash[:success] = "创建成功" | |||
| else | |||
| render :new | |||
| flash[:danger] = "创建失败" | |||
| redirect_to admins_project_ignores_path | |||
| flash[:danger] = @project_ignore.errors.full_messages.join(",") | |||
| end | |||
| end | |||
| @@ -58,8 +58,8 @@ class Admins::ProjectIgnoresController < Admins::BaseController | |||
| redirect_to admins_project_ignores_path | |||
| flash[:success] = "更新成功" | |||
| else | |||
| render :edit | |||
| flash[:danger] = "更新失败" | |||
| redirect_to admins_project_ignores_path | |||
| flash[:danger] = @project_ignore.errors.full_messages.join(",") | |||
| end | |||
| end | |||
| @@ -98,23 +98,23 @@ class Admins::ProjectIgnoresController < Admins::BaseController | |||
| params.require(:ignore).permit(:name,:content) | |||
| end | |||
| def validate_params | |||
| name = params[:ignore][:name] | |||
| if name.blank? | |||
| flash[:danger] = "名称不允许为空" | |||
| redirect_to admins_project_ignores_path | |||
| elsif check_ignore_present?(name) && @project_ignore.blank? | |||
| flash[:danger] = "创建失败:名称已存在" | |||
| redirect_to admins_project_ignores_path | |||
| end | |||
| end | |||
| # def validate_params | |||
| # name = params[:ignore][:name] | |||
| # if name.blank? | |||
| # flash[:danger] = "名称不允许为空" | |||
| # redirect_to admins_project_ignores_path | |||
| # elsif check_ignore_present?(name) && @project_ignore.blank? | |||
| # flash[:danger] = "创建失败:名称已存在" | |||
| # redirect_to admins_project_ignores_path | |||
| # end | |||
| # end | |||
| def check_ignore_present?(name) | |||
| return true if name.blank? | |||
| name_downcase = name.downcase | |||
| name_upcase = name.upcase | |||
| name_first_big = name.capitalize | |||
| Ignore.exists?(name: name_downcase) || Ignore.exists?(name: name_upcase) || Ignore.exists?(name: name_first_big) | |||
| end | |||
| # def check_ignore_present?(name) | |||
| # return true if name.blank? | |||
| # name_downcase = name.downcase | |||
| # name_upcase = name.upcase | |||
| # name_first_big = name.capitalize | |||
| # Ignore.exists?(name: name_downcase) || Ignore.exists?(name: name_upcase) || Ignore.exists?(name: name_first_big) | |||
| # end | |||
| end | |||
| @@ -27,17 +27,18 @@ class Admins::ProjectLanguagesController < Admins::BaseController | |||
| flash[:success] = '创建成功' | |||
| else | |||
| redirect_to admins_project_languages_path | |||
| flash[:danger] = '创建失败' | |||
| flash[:danger] = @project_language.errors.full_messages.join(",") | |||
| end | |||
| end | |||
| def update | |||
| if @project_language.update_attribute(:name, @name) | |||
| @project_language.attributes = {name: @name} | |||
| if @project_language.save | |||
| redirect_to admins_project_languages_path | |||
| flash[:success] = '更新成功' | |||
| else | |||
| redirect_to admins_project_languages_path | |||
| flash[:success] = '更新失败' | |||
| flash[:danger] = @project_language.errors.full_messages.join(",") | |||
| end | |||
| end | |||
| @@ -1,6 +1,6 @@ | |||
| class Admins::ProjectLicensesController < Admins::BaseController | |||
| before_action :set_license, only: [:edit,:update, :destroy,:show] | |||
| before_action :validate_params, only: [:create, :update] | |||
| # before_action :validate_params, only: [:create, :update] | |||
| def index | |||
| sort_by = License.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at' | |||
| @@ -30,13 +30,12 @@ class Admins::ProjectLicensesController < Admins::BaseController | |||
| # position: max_position | |||
| # } | |||
| @project_license = License.new(license_params) | |||
| if @project_license.save! | |||
| if @project_license.save | |||
| redirect_to admins_project_licenses_path | |||
| flash[:success] = "创建成功" | |||
| else | |||
| render :new | |||
| flash[:danger] = "创建失败" | |||
| redirect_to admins_project_licenses_path | |||
| flash[:danger] = @project_license.errors.full_messages.join(",") | |||
| end | |||
| end | |||
| @@ -54,12 +53,13 @@ class Admins::ProjectLicensesController < Admins::BaseController | |||
| # permissions: permissions.to_s, | |||
| # limitations: limitations.to_s | |||
| # } | |||
| if @project_license.update_attributes(license_params) | |||
| @project_license.attributes = license_params | |||
| if @project_license.save | |||
| redirect_to admins_project_licenses_path | |||
| flash[:success] = "更新成功" | |||
| else | |||
| render :edit | |||
| flash[:danger] = "更新失败" | |||
| render admins_project_licenses_path | |||
| flash[:danger] = @project_license.errors.full_messages.join(",") | |||
| end | |||
| end | |||
| @@ -98,23 +98,23 @@ class Admins::ProjectLicensesController < Admins::BaseController | |||
| params.require(:license).permit(:name,:content) | |||
| end | |||
| def validate_params | |||
| name = params[:license][:name] | |||
| if name.blank? | |||
| flash[:danger] = "名称不允许为空" | |||
| redirect_to admins_project_licenses_path | |||
| elsif check_license_present?(name) && @project_license.blank? | |||
| flash[:danger] = "创建失败:名称已存在" | |||
| redirect_to admins_project_licenses_path | |||
| end | |||
| end | |||
| # def validate_params | |||
| # name = params[:license][:name] | |||
| # if name.blank? | |||
| # flash[:danger] = "名称不允许为空" | |||
| # redirect_to admins_project_licenses_path | |||
| # elsif check_license_present?(name) && @project_license.blank? | |||
| # flash[:danger] = "创建失败:名称已存在" | |||
| # redirect_to admins_project_licenses_path | |||
| # end | |||
| # end | |||
| def check_license_present?(name) | |||
| return true if name.blank? | |||
| name_downcase = name.downcase | |||
| name_upcase = name.upcase | |||
| name_first_big = name.capitalize | |||
| License.exists?(name: name_downcase) || License.exists?(name: name_upcase) || License.exists?(name: name_first_big) | |||
| end | |||
| # def check_license_present?(name) | |||
| # return true if name.blank? | |||
| # name_downcase = name.downcase | |||
| # name_upcase = name.upcase | |||
| # name_first_big = name.capitalize | |||
| # License.exists?(name: name_downcase) || License.exists?(name: name_upcase) || License.exists?(name: name_first_big) | |||
| # end | |||
| end | |||
| @@ -15,6 +15,5 @@ class Api::V1::ProjectsController < Api::V1::BaseController | |||
| def blame | |||
| @result_object = Api::V1::Projects::BlameService.call(@project, params[:sha], params[:filepath], current_user&.gitea_token) | |||
| puts @result_object | |||
| end | |||
| end | |||
| @@ -16,9 +16,9 @@ class Api::V1::UsersController < Api::V1::BaseController | |||
| # 60s内不能重复发送 | |||
| send_email_limit_cache_key = "send_email_60_second_limit:#{mail}" | |||
| tip_exception(-1, '请勿频繁操作') if Rails.cache.exist?(send_email_limit_cache_key) | |||
| tip_exception(-2, '请勿频繁操作') if Rails.cache.exist?(send_email_limit_cache_key) | |||
| send_email_control = LimitForbidControl::SendEmailCode.new(mail) | |||
| tip_exception(-1, '邮件发送太频繁,请稍后再试') if send_email_control.forbid? | |||
| tip_exception(-2, '邮件发送太频繁,请稍后再试') if send_email_control.forbid? | |||
| begin | |||
| UserMailer.update_email(mail, verification_code).deliver_now | |||
| @@ -39,17 +39,17 @@ class Api::V1::UsersController < Api::V1::BaseController | |||
| def check_password | |||
| password = params[:password] | |||
| return render_error("8~16位密码,支持字母数字和符号") unless password =~ CustomRegexp::PASSWORD | |||
| return render_error("密码错误") unless @observe_user.check_password?(password) | |||
| return tip_exception(-5, "8~16位密码,支持字母数字和符号") unless password =~ CustomRegexp::PASSWORD | |||
| return tip_exception(-5, "密码错误") unless @observe_user.check_password?(password) | |||
| render_ok | |||
| end | |||
| def check_email | |||
| mail = strip(params[:email]) | |||
| return render_error("邮件格式有误") unless mail =~ CustomRegexp::EMAIL | |||
| return tip_exception(-2, "邮件格式有误") unless mail =~ CustomRegexp::EMAIL | |||
| exist_owner = Owner.find_by(mail: mail) | |||
| return render_error('邮箱已被使用') if exist_owner | |||
| return tip_exception(-2, '邮箱已被使用') if exist_owner | |||
| render_ok | |||
| end | |||
| @@ -58,12 +58,13 @@ class Api::V1::UsersController < Api::V1::BaseController | |||
| mail = strip(params[:email]) | |||
| code_type = params[:code_type] | |||
| return render_error("邮件格式有误") unless mail =~ CustomRegexp::EMAIL | |||
| return tip_exception(-2, "邮件格式有误") unless mail =~ CustomRegexp::EMAIL | |||
| verifi_code = VerificationCode.where(email: mail, code: code, code_type: code_type).last | |||
| return render_ok if code == "123123" && EduSetting.get("code_debug") # 万能验证码,用于测试 # TODO 万能验证码,用于测试 | |||
| return render_error("验证码不正确") if verifi_code&.code != code | |||
| return render_error("验证码已失效") if !verifi_code&.effective? | |||
| return tip_exception(-6, "验证码不正确") if verifi_code&.code != code | |||
| return tip_exception(-6, "验证码已失效") if !verifi_code&.effective? | |||
| render_ok | |||
| end | |||
| @@ -173,6 +173,25 @@ class ApplicationController < ActionController::Base | |||
| tip_exception(401, "请登录后再操作") unless User.current.logged? | |||
| end | |||
| def require_login_or_token | |||
| if params[:token].present? | |||
| user = User.try_to_autologin(params[:token]) | |||
| User.current = user | |||
| end | |||
| tip_exception(401, "请登录后再操作") unless User.current.logged? | |||
| end | |||
| def require_login_cloud_ide_saas | |||
| if params[:sign].present? && params[:email].present? | |||
| sign = Digest::MD5.hexdigest("#{OPENKEY}#{params[:email]}") | |||
| if params[:sign].to_s == sign | |||
| user = User.find_by(mail: params[:email]) | |||
| User.current = user | |||
| end | |||
| end | |||
| tip_exception(401, "请登录后再操作") unless User.current.logged? | |||
| end | |||
| def require_profile_completed | |||
| tip_exception(411, "请完善资料后再操作") unless User.current.profile_is_completed? | |||
| end | |||
| @@ -704,9 +723,15 @@ class ApplicationController < ActionController::Base | |||
| # @project = nil if !@project.is_public? | |||
| # render_forbidden and return | |||
| else | |||
| logger.info "###########:project not found" | |||
| @project = nil | |||
| render_not_found and return | |||
| if @project.present? | |||
| logger.info "###########: has project and but can't read project" | |||
| @project = nil | |||
| render_forbidden and return | |||
| else | |||
| logger.info "###########:project not found" | |||
| @project = nil | |||
| render_not_found and return | |||
| end | |||
| end | |||
| @project | |||
| end | |||
| @@ -1,261 +1,261 @@ | |||
| #coding=utf-8 | |||
| # | |||
| # 文件上传 | |||
| class AttachmentsController < ApplicationController | |||
| before_action :require_login, :check_auth, except: [:show, :preview_attachment, :get_file] | |||
| before_action :find_file, only: %i[show destroy] | |||
| before_action :attachment_candown, only: [:show] | |||
| skip_before_action :check_sign, only: [:show, :create] | |||
| include ApplicationHelper | |||
| def show | |||
| # 1. 优先跳到cdn | |||
| # 2. 如果没有cdn,send_file | |||
| if @file.cloud_url.present? | |||
| update_downloads(@file) | |||
| redirect_to @file.cloud_url and return | |||
| end | |||
| type_attachment = params[:disposition] || "attachment" | |||
| if type_attachment == "inline" | |||
| send_file absolute_path(local_path(@file)),filename: @file.title, disposition: 'inline',type: 'application/pdf' | |||
| elsif type_attachment == "MP4" | |||
| send_file_with_range absolute_path(local_path(@file)), disposition: 'inline', type: "video/mp4", range: true | |||
| else | |||
| send_file(absolute_path(local_path(@file)), filename: @file.title,stream:false, type: @file.content_type.presence || 'application/octet-stream') | |||
| end | |||
| update_downloads(@file) | |||
| end | |||
| def get_file | |||
| normal_status(-1, "参数缺失") if params[:download_url].blank? | |||
| 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 = ("/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() | |||
| else | |||
| response = Faraday.get(url) | |||
| filename = params[:download_url].to_s.split("/").pop() | |||
| end | |||
| send_data(response.body.force_encoding("UTF-8"), filename: filename, type: "application/octet-stream", disposition: 'attachment') | |||
| end | |||
| def create | |||
| # 1. 本地存储 | |||
| # 2. 上传到云 | |||
| begin | |||
| upload_file = params["file"] || params["#{params[:file_param_name]}"]# 这里的file_param_name是为了方便其他插件名称 | |||
| uid_logger("#########################file_params####{params["#{params[:file_param_name]}"]}") | |||
| raise "未上传文件" unless upload_file | |||
| folder = file_storage_directory | |||
| raise "存储目录未定义" unless folder.present? | |||
| month_folder = current_month_folder | |||
| save_path = File.join(folder, month_folder) | |||
| ext = file_ext(upload_file.original_filename) | |||
| local_path, digest = file_save_to_local(save_path, upload_file.tempfile, ext) | |||
| content_type = upload_file.content_type.presence || 'application/octet-stream' | |||
| # remote_path = file_save_to_ucloud(local_path[folder.size, local_path.size], local_path, content_type) | |||
| remote_path = nil # TODO 暂时本地上传,待域名配置后方可上传至云端 | |||
| logger.info "local_path: #{local_path}" | |||
| logger.info "remote_path: #{remote_path}" | |||
| disk_filename = local_path[save_path.size + 1, local_path.size] | |||
| #存数据库 | |||
| # | |||
| @attachment = Attachment.where(disk_filename: disk_filename, | |||
| author_id: current_user.id, | |||
| cloud_url: remote_path).first | |||
| if @attachment.blank? | |||
| @attachment = Attachment.new | |||
| @attachment.filename = upload_file.original_filename | |||
| @attachment.disk_filename = local_path[save_path.size + 1, local_path.size] | |||
| @attachment.filesize = upload_file.tempfile.size | |||
| @attachment.content_type = content_type | |||
| @attachment.digest = digest | |||
| @attachment.author_id = current_user.id | |||
| @attachment.disk_directory = month_folder | |||
| @attachment.cloud_url = remote_path | |||
| @attachment.save! | |||
| else | |||
| logger.info "文件已存在,id = #{@attachment.id}, filename = #{@attachment.filename}" | |||
| end | |||
| render_json | |||
| rescue => e | |||
| uid_logger_error(e.message) | |||
| tip_exception(e.message) | |||
| end | |||
| end | |||
| def destroy | |||
| begin | |||
| @file_path = absolute_path(local_path(@file)) | |||
| #return normal_status(403, "") unless @file.author == current_user | |||
| @file.destroy! | |||
| delete_file(@file_path) | |||
| normal_status("删除成功") | |||
| rescue Exception => e | |||
| uid_logger_error(e.message) | |||
| tip_exception(e.message) | |||
| raise ActiveRecord::Rollback | |||
| end | |||
| end | |||
| # 附件为视频时,点击播放 | |||
| def preview_attachment | |||
| attachment = Attachment.find_by(id: params[:id]) | |||
| dir_path = "#{Rails.root}/public/preview" | |||
| Dir.mkdir(dir_path) unless Dir.exist?(dir_path) | |||
| if params[:status] == "preview" | |||
| if system("cp -r #{absolute_path(local_path(attachment))} #{dir_path}/") | |||
| render json: {status: 1, url: "/preview/#{attachment.disk_filename}"} | |||
| else | |||
| normal_status(-1, "出现错误,请稍后重试") | |||
| end | |||
| else | |||
| if system("rm -rf #{dir_path}/#{attachment.disk_filename}") | |||
| normal_status(1, "操作成功") | |||
| else | |||
| normal_status(-1, "出现错误,请稍后重试") | |||
| end | |||
| end | |||
| end | |||
| private | |||
| def find_file | |||
| @file = | |||
| if params[:type] == 'history' | |||
| AttachmentHistory.find params[:id] | |||
| else | |||
| Attachment.find params[:id] | |||
| end | |||
| end | |||
| def delete_file(file_path) | |||
| File.delete(file_path) if File.exist?(file_path) | |||
| end | |||
| def current_month_folder | |||
| date = Time.now | |||
| "#{date.year}/#{date.month.to_s.rjust(2, '0')}" | |||
| end | |||
| def file_ext(file_name) | |||
| ext = '' | |||
| exts = file_name.split(".") | |||
| if exts.size > 1 | |||
| ext = ".#{exts.last}" | |||
| end | |||
| ext | |||
| end | |||
| def file_save_to_local(save_path, temp_file, ext) | |||
| unless Dir.exists?(save_path) | |||
| FileUtils.mkdir_p(save_path) ##不成功这里会抛异常 | |||
| end | |||
| digest = md5_file(temp_file) | |||
| digest = "#{digest}_#{(Time.now.to_f * 1000).to_i}" | |||
| local_file_path = File.join(save_path, digest) + ext | |||
| save_temp_file(temp_file, local_file_path) | |||
| [local_file_path, digest] | |||
| end | |||
| def save_temp_file(temp_file, save_file_path) | |||
| File.open(save_file_path, 'wb') do |f| | |||
| temp_file.rewind | |||
| while (buffer = temp_file.read(8192)) | |||
| f.write(buffer) | |||
| end | |||
| end | |||
| end | |||
| def md5_file(temp_file) | |||
| md5 = Digest::MD5.new | |||
| temp_file.rewind | |||
| while (buffer = temp_file.read(8192)) | |||
| md5.update(buffer) | |||
| end | |||
| md5.hexdigest | |||
| end | |||
| def file_save_to_ucloud(path, file, content_type) | |||
| ufile = Gitlink::Ufile.new( | |||
| ucloud_public_key: edu_setting('public_key'), | |||
| ucloud_private_key: edu_setting('private_key'), | |||
| ucloud_public_read: true, | |||
| ucloud_public_bucket: edu_setting('public_bucket'), | |||
| ucloud_public_bucket_host: edu_setting('public_bucket_host'), | |||
| ucloud_public_cdn_host: edu_setting('public_cdn_host'), | |||
| ) | |||
| File.open(file) do |f| | |||
| ufile.put(path, f, 'Content-Type' => content_type) | |||
| end | |||
| edu_setting('public_cdn_host') + "/" + path | |||
| end | |||
| def attachment_candown | |||
| unless current_user.admin? || current_user.business? | |||
| candown = true | |||
| unless params[:type] == 'history' | |||
| if @file.container && current_user.logged? | |||
| if @file.container.is_a?(Issue) | |||
| course = @file.container.project | |||
| candown = course.member?(current_user) || course.is_public | |||
| elsif @file.container.is_a?(Journal) | |||
| course = @file.container.issue.project | |||
| candown = course.member?(current_user) | |||
| else | |||
| course = nil | |||
| end | |||
| tip_exception(403, "您没有权限进入") if course.present? && !candown | |||
| tip_exception(403, "您没有权限进入") if @file.container.is_a?(ApplyUserAuthentication) | |||
| end | |||
| end | |||
| end | |||
| end | |||
| def send_file_with_range(path, options = {}) | |||
| logger.info("########request.headers: #{request.headers}") | |||
| logger.info("########request.headers: #{File.exist?(path)}") | |||
| if File.exist?(path) | |||
| size = File.size(path) | |||
| logger.info("########request.headers: #{request.headers}") | |||
| if !request.headers["Range"] | |||
| status_code = 200 # 200 OK | |||
| offset = 0 | |||
| length = File.size(path) | |||
| else | |||
| status_code = 206 # 206 Partial Content | |||
| bytes = Rack::Utils.byte_ranges(request.headers, size)[0] | |||
| offset = bytes.begin | |||
| length = bytes.end - bytes.begin | |||
| end | |||
| response.header["Accept-Ranges"] = "bytes" | |||
| response.header["Content-Range"] = "bytes #{bytes.begin}-#{bytes.end}/#{size}" if bytes | |||
| response.header["status"] = status_code | |||
| send_data IO.binread(path, length, offset), options | |||
| else | |||
| raise ActionController::MissingFile, "Cannot read file #{path}." | |||
| end | |||
| end | |||
| end | |||
| #coding=utf-8 | |||
| # | |||
| # 文件上传 | |||
| class AttachmentsController < ApplicationController | |||
| before_action :require_login, :check_auth, except: [:show, :preview_attachment, :get_file] | |||
| before_action :find_file, only: %i[show destroy] | |||
| before_action :attachment_candown, only: [:show] | |||
| skip_before_action :check_sign, only: [:show, :create] | |||
| include ApplicationHelper | |||
| def show | |||
| # 1. 优先跳到cdn | |||
| # 2. 如果没有cdn,send_file | |||
| if @file.cloud_url.present? | |||
| update_downloads(@file) | |||
| redirect_to @file.cloud_url and return | |||
| end | |||
| type_attachment = params[:disposition] || "attachment" | |||
| if type_attachment == "inline" | |||
| send_file absolute_path(local_path(@file)),filename: @file.title, disposition: 'inline',type: 'application/pdf' | |||
| elsif type_attachment == "MP4" | |||
| send_file_with_range absolute_path(local_path(@file)), disposition: 'inline', type: "video/mp4", range: true | |||
| else | |||
| send_file(absolute_path(local_path(@file)), filename: @file.title,stream:false, type: @file.content_type.presence || 'application/octet-stream') | |||
| end | |||
| update_downloads(@file) | |||
| end | |||
| def get_file | |||
| normal_status(-1, "参数缺失") if params[:download_url].blank? | |||
| 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 = ("/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() | |||
| else | |||
| response = Faraday.get(url) | |||
| filename = params[:download_url].to_s.split("/").pop() | |||
| end | |||
| send_data(response.body.force_encoding("UTF-8"), filename: filename, type: "application/octet-stream", disposition: 'attachment') | |||
| end | |||
| def create | |||
| # 1. 本地存储 | |||
| # 2. 上传到云 | |||
| begin | |||
| upload_file = params["file"] || params["#{params[:file_param_name]}"]# 这里的file_param_name是为了方便其他插件名称 | |||
| uid_logger("#########################file_params####{params["#{params[:file_param_name]}"]}") | |||
| raise "未上传文件" unless upload_file | |||
| folder = file_storage_directory | |||
| raise "存储目录未定义" unless folder.present? | |||
| month_folder = current_month_folder | |||
| save_path = File.join(folder, month_folder) | |||
| ext = file_ext(upload_file.original_filename) | |||
| local_path, digest = file_save_to_local(save_path, upload_file.tempfile, ext) | |||
| content_type = upload_file.content_type.presence || 'application/octet-stream' | |||
| # remote_path = file_save_to_ucloud(local_path[folder.size, local_path.size], local_path, content_type) | |||
| remote_path = nil # TODO 暂时本地上传,待域名配置后方可上传至云端 | |||
| logger.info "local_path: #{local_path}" | |||
| logger.info "remote_path: #{remote_path}" | |||
| disk_filename = local_path[save_path.size + 1, local_path.size] | |||
| #存数据库 | |||
| # | |||
| @attachment = Attachment.where(disk_filename: disk_filename, | |||
| author_id: current_user.id, | |||
| cloud_url: remote_path).first | |||
| if @attachment.blank? | |||
| @attachment = Attachment.new | |||
| @attachment.filename = upload_file.original_filename | |||
| @attachment.disk_filename = local_path[save_path.size + 1, local_path.size] | |||
| @attachment.filesize = upload_file.tempfile.size | |||
| @attachment.content_type = content_type | |||
| @attachment.digest = digest | |||
| @attachment.author_id = current_user.id | |||
| @attachment.disk_directory = month_folder | |||
| @attachment.cloud_url = remote_path | |||
| @attachment.save! | |||
| else | |||
| logger.info "文件已存在,id = #{@attachment.id}, filename = #{@attachment.filename}" | |||
| end | |||
| render_json | |||
| rescue => e | |||
| uid_logger_error(e.message) | |||
| tip_exception(e.message) | |||
| end | |||
| end | |||
| def destroy | |||
| begin | |||
| @file_path = absolute_path(local_path(@file)) | |||
| #return normal_status(403, "") unless @file.author == current_user | |||
| @file.destroy! | |||
| delete_file(@file_path) | |||
| normal_status("删除成功") | |||
| rescue Exception => e | |||
| uid_logger_error(e.message) | |||
| tip_exception(e.message) | |||
| raise ActiveRecord::Rollback | |||
| end | |||
| end | |||
| # 附件为视频时,点击播放 | |||
| def preview_attachment | |||
| attachment = Attachment.find_by(id: params[:id]) | |||
| dir_path = "#{Rails.root}/public/preview" | |||
| Dir.mkdir(dir_path) unless Dir.exist?(dir_path) | |||
| if params[:status] == "preview" | |||
| if system("cp -r #{absolute_path(local_path(attachment))} #{dir_path}/") | |||
| render json: {status: 1, url: "/preview/#{attachment.disk_filename}"} | |||
| else | |||
| normal_status(-1, "出现错误,请稍后重试") | |||
| end | |||
| else | |||
| if system("rm -rf #{dir_path}/#{attachment.disk_filename}") | |||
| normal_status(1, "操作成功") | |||
| else | |||
| normal_status(-1, "出现错误,请稍后重试") | |||
| end | |||
| end | |||
| end | |||
| private | |||
| def find_file | |||
| @file = | |||
| if params[:type] == 'history' | |||
| AttachmentHistory.find params[:id] | |||
| else | |||
| Attachment.find params[:id] | |||
| end | |||
| end | |||
| def delete_file(file_path) | |||
| File.delete(file_path) if File.exist?(file_path) | |||
| end | |||
| def current_month_folder | |||
| date = Time.now | |||
| "#{date.year}/#{date.month.to_s.rjust(2, '0')}" | |||
| end | |||
| def file_ext(file_name) | |||
| ext = '' | |||
| exts = file_name.split(".") | |||
| if exts.size > 1 | |||
| ext = ".#{exts.last}" | |||
| end | |||
| ext | |||
| end | |||
| def file_save_to_local(save_path, temp_file, ext) | |||
| unless Dir.exists?(save_path) | |||
| FileUtils.mkdir_p(save_path) ##不成功这里会抛异常 | |||
| end | |||
| digest = md5_file(temp_file) | |||
| digest = "#{digest}_#{(Time.now.to_f * 1000).to_i}" | |||
| local_file_path = File.join(save_path, digest) + ext | |||
| save_temp_file(temp_file, local_file_path) | |||
| [local_file_path, digest] | |||
| end | |||
| def save_temp_file(temp_file, save_file_path) | |||
| File.open(save_file_path, 'wb') do |f| | |||
| temp_file.rewind | |||
| while (buffer = temp_file.read(8192)) | |||
| f.write(buffer) | |||
| end | |||
| end | |||
| end | |||
| def md5_file(temp_file) | |||
| md5 = Digest::MD5.new | |||
| temp_file.rewind | |||
| while (buffer = temp_file.read(8192)) | |||
| md5.update(buffer) | |||
| end | |||
| md5.hexdigest | |||
| end | |||
| def file_save_to_ucloud(path, file, content_type) | |||
| ufile = Gitlink::Ufile.new( | |||
| ucloud_public_key: edu_setting('public_key'), | |||
| ucloud_private_key: edu_setting('private_key'), | |||
| ucloud_public_read: true, | |||
| ucloud_public_bucket: edu_setting('public_bucket'), | |||
| ucloud_public_bucket_host: edu_setting('public_bucket_host'), | |||
| ucloud_public_cdn_host: edu_setting('public_cdn_host'), | |||
| ) | |||
| File.open(file) do |f| | |||
| ufile.put(path, f, 'Content-Type' => content_type) | |||
| end | |||
| edu_setting('public_cdn_host') + "/" + path | |||
| end | |||
| def attachment_candown | |||
| unless current_user.admin? || current_user.business? | |||
| candown = true | |||
| unless params[:type] == 'history' | |||
| if @file.container && current_user.logged? | |||
| if @file.container.is_a?(Issue) | |||
| course = @file.container.project | |||
| candown = course.member?(current_user) || course.is_public | |||
| elsif @file.container.is_a?(Journal) | |||
| course = @file.container.issue.project | |||
| candown = course.member?(current_user) || course.is_public | |||
| else | |||
| course = nil | |||
| end | |||
| tip_exception(403, "您没有权限进入") if course.present? && !candown | |||
| tip_exception(403, "您没有权限进入") if @file.container.is_a?(ApplyUserAuthentication) | |||
| end | |||
| end | |||
| end | |||
| end | |||
| def send_file_with_range(path, options = {}) | |||
| logger.info("########request.headers: #{request.headers}") | |||
| logger.info("########request.headers: #{File.exist?(path)}") | |||
| if File.exist?(path) | |||
| size = File.size(path) | |||
| logger.info("########request.headers: #{request.headers}") | |||
| if !request.headers["Range"] | |||
| status_code = 200 # 200 OK | |||
| offset = 0 | |||
| length = File.size(path) | |||
| else | |||
| status_code = 206 # 206 Partial Content | |||
| bytes = Rack::Utils.byte_ranges(request.headers, size)[0] | |||
| offset = bytes.begin | |||
| length = bytes.end - bytes.begin | |||
| end | |||
| response.header["Accept-Ranges"] = "bytes" | |||
| response.header["Content-Range"] = "bytes #{bytes.begin}-#{bytes.end}/#{size}" if bytes | |||
| response.header["status"] = status_code | |||
| send_data IO.binread(path, length, offset), options | |||
| else | |||
| raise ActionController::MissingFile, "Cannot read file #{path}." | |||
| end | |||
| end | |||
| end | |||
| @@ -65,13 +65,13 @@ class MembersController < ApplicationController | |||
| def check_member_exists! | |||
| @current_user_header_team = Team.joins(:team_users, :team_projects).where(team_projects: {project_id: @project.id}, team_users: {user_id: current_user.id}).order(authorize: :desc).take | |||
| return render_error("user_id为#{params[:user_id]}的用户已经是项目成员") if member_exists? || (params[:user_id].to_i == current_user.id && @current_user_header_team.present?) | |||
| return render_error("#{@user&.nickname}已经是项目成员") if member_exists? || (params[:user_id].to_i == current_user.id && @current_user_header_team.present?) | |||
| end | |||
| def check_member_not_exists! | |||
| @current_user_header_team = Team.joins(:team_users, :team_projects).where(team_projects: {project_id: @project.id}, team_users: {user_id: current_user.id}).order(authorize: :desc).take | |||
| return render_error("用户为组织成员,请到组织下操作!") if (params[:user_id].to_i == current_user.id && @current_user_header_team.present?) && !member_exists? | |||
| return render_error("user_id为#{params[:user_id]}的用户还不是项目成员") unless member_exists? | |||
| return render_error("#{@user&.nickname}还不是项目成员") unless member_exists? | |||
| end | |||
| def check_user_profile_completed | |||
| @@ -1,5 +1,5 @@ | |||
| class PublicKeysController < ApplicationController | |||
| before_action :require_login | |||
| before_action :require_login_cloud_ide_saas | |||
| before_action :find_public_key, only: [:destroy] | |||
| def index | |||
| @@ -61,4 +61,6 @@ class PublicKeysController < ApplicationController | |||
| def find_public_key | |||
| @public_key = current_user.public_keys.find_by_id(params[:id]) | |||
| end | |||
| end | |||
| @@ -273,7 +273,7 @@ class PullRequestsController < ApplicationController | |||
| def get_relatived | |||
| @project_tags = @project.issue_tags&.select(:id,:name, :color).as_json | |||
| @project_versions = @project.versions&.select(:id,:name, :status).as_json | |||
| @project_versions = @project.versions.opening&.select(:id,:name, :status).as_json | |||
| @project_members = @project.all_developers | |||
| @project_priories = IssuePriority&.select(:id,:name, :position).as_json | |||
| end | |||
| @@ -147,9 +147,19 @@ class RepositoriesController < ApplicationController | |||
| end | |||
| def tags | |||
| result = Gitea::Repository::Tags::ListService.call(current_user&.gitea_token, @owner.login, @project.identifier, {page: params[:page], limit: params[:limit]}) | |||
| if params[:only_name].present? | |||
| result = Gitea::Repository::Tags::ListNameService.call(@owner, @project.identifier, params[:name]) | |||
| @tags = result.is_a?(Hash) && result.key?(:status) ? [] : result | |||
| @tags = result.is_a?(Hash) && result.key?(:status) ? [] : result | |||
| else | |||
| name_result = Gitea::Repository::Tags::ListNameService.call(@owner, @project.identifier, params[:name]) | |||
| @tag_names = result.is_a?(Hash) && result.key?(:status) ? [] : name_result | |||
| 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 | |||
| end | |||
| def contributors | |||
| @@ -123,7 +123,7 @@ module TagChosenHelper | |||
| cache_key = "project-#{project.id}/all_milestones/size-#{project.versions.size}/#{project.versions.maximum('updated_on')}" | |||
| Rails.cache.fetch(cache_key) do | |||
| project.versions.select(:id, :name, :status).collect do |event| | |||
| project.versions.opening.select(:id, :name, :status).collect do |event| | |||
| { | |||
| id: event.id, | |||
| name: event.name, | |||
| @@ -17,30 +17,69 @@ module ProjectOperable | |||
| owner.build_permit_team_projects!(id) | |||
| # 避免自己创建的项目,却无法拥有访问权,因为该用户所在团队暂未获得项目访问权 | |||
| return if creator.nil? || owner.is_owner?(creator.id) | |||
| add_member!(creator.id, "Manager") | |||
| add_member!(creator.id, "Manager") if creator.is_a?(User) | |||
| end | |||
| def add_member!(user_id, role_name='Developer') | |||
| if self.owner.is_a?(Organization) | |||
| case role_name | |||
| when 'Manager' | |||
| # 构建相应的团队 | |||
| team = self.owner.teams.admin.take | |||
| team = team.nil? ? Team.build(self.user_id, 'admin', '管理员', '', 'admin', false, false) : team | |||
| TeamProject.build(self.user_id, team.id, self.id) | |||
| OrganizationUser.build(self.user_id, user_id) | |||
| if team.nil? | |||
| team = Team.build(self.user_id, 'admin', '管理员', '', 'admin', false, false) | |||
| gteam = $gitea_client.post_orgs_teams_by_org(self.owner.login, {body: team.to_gitea_hash.to_json}) rescue nil | |||
| team.update_attributes!({gtid: gteam["id"]}) unless gteam.nil? | |||
| end | |||
| # 设置项目在团队中的访问权限 | |||
| team_project = TeamProject.build(self.user_id, team.id, self.id) | |||
| tp_result = $gitea_client.put_teams_repos_by_id_org_repo(team.gtid, self.owner.login, self.identifier) rescue nil | |||
| # 新增对应的团队成员 | |||
| team_user = TeamUser.build(self.user_id, user_id, team.id) | |||
| $gitea_client.put_teams_members_by_id_username(team&.gtid, team_user.user&.login) rescue nil # 新增新的 | |||
| # 确保组织成员中有该用户 | |||
| OrganizationUser.build(self.user_id, user_id) | |||
| when 'Developer' | |||
| # 构建相应的团队 | |||
| team = self.owner.teams.write.take | |||
| team = team.nil? ? Team.build(self.user_id, 'developer', '开发者', '', 'write', false, false) : team | |||
| TeamProject.build(self.user_id, team.id, self.id) | |||
| OrganizationUser.build(self.user_id, user_id) | |||
| if team.nil? | |||
| team = Team.build(self.user_id, 'developer', '开发者', '', 'write', false, false) | |||
| gteam = $gitea_client.post_orgs_teams_by_org(self.owner.login, {body: team.to_gitea_hash.to_json}) rescue nil | |||
| team.update_attributes!({gtid: gteam["id"]}) unless gteam.nil? | |||
| end | |||
| # 设置项目在团队中的访问权限 | |||
| team_project = TeamProject.build(self.user_id, team.id, self.id) | |||
| tp_result = $gitea_client.put_teams_repos_by_id_org_repo(team.gtid, self.owner.login, self.identifier) rescue nil | |||
| # 新增对应的团队成员 | |||
| team_user = TeamUser.build(self.user_id, user_id, team.id) | |||
| $gitea_client.put_teams_members_by_id_username(team&.gtid, team_user.user&.login) rescue nil # 新增新的 | |||
| # 确保组织成员中有该用户 | |||
| OrganizationUser.build(self.user_id, user_id) | |||
| when 'Reporter' | |||
| # 构建相应的团队 | |||
| team = self.owner.teams.read.take | |||
| team = team.nil? ? Team.build(self.user_id, 'reporter', '报告者', '', 'read', false, false) : team | |||
| TeamProject.build(self.user_id, team.id, self.id) | |||
| OrganizationUser.build(self.user_id, user_id) | |||
| if team.nil? | |||
| team = Team.build(self.user_id, 'reporter', '报告者', '', 'read', false, false) | |||
| gteam = $gitea_client.post_orgs_teams_by_org(self.owner.login, {body: team.to_gitea_hash.to_json}) rescue nil | |||
| team.update_attributes!({gtid: gteam["id"]}) unless gteam.nil? | |||
| end | |||
| # 设置项目在团队中的访问权限 | |||
| team_project = TeamProject.build(self.user_id, team.id, self.id) | |||
| tp_result = $gitea_client.put_teams_repos_by_id_org_repo(team.gtid, self.owner.login, self.identifier) rescue nil | |||
| # 新增对应的团队成员 | |||
| team_user = TeamUser.build(self.user_id, user_id, team.id) | |||
| $gitea_client.put_teams_members_by_id_username(team&.gtid, team_user.user&.login) rescue nil # 新增新的 | |||
| # 确保组织成员中有该用户 | |||
| OrganizationUser.build(self.user_id, user_id) | |||
| end | |||
| end | |||
| member = members.create!(user_id: user_id, team_user_id: team_user&.id) | |||
| @@ -71,26 +110,70 @@ module ProjectOperable | |||
| def change_member_role!(user_id, role) | |||
| member = self.member(user_id) | |||
| # 所有者为组织,并且该用户属于组织成员 | |||
| if self.owner.is_a?(Organization) && member.team_user.present? | |||
| case role&.name | |||
| when 'Manager' | |||
| # 构建相应的团队 | |||
| team = self.owner.teams.admin.take | |||
| team = team.nil? ? Team.build(self.user_id, 'admin', '管理员', '', 'admin', false, false) : team | |||
| TeamProject.build(self.user_id, team.id, self.id) | |||
| if team.nil? | |||
| team = Team.build(self.user_id, 'admin', '管理员', '', 'admin', false, false) | |||
| gteam = $gitea_client.post_orgs_teams_by_org(self.owner.login, {body: team.to_gitea_hash.to_json}) rescue nil | |||
| team.update_attributes!({gtid: gteam["id"]}) unless gteam.nil? | |||
| end | |||
| # 设置项目在团队中的访问权限 | |||
| team_project = TeamProject.build(self.user_id, team.id, self.id) | |||
| tp_result = $gitea_client.put_teams_repos_by_id_org_repo(team.gtid, self.owner.login, self.identifier) rescue nil | |||
| # 更改对应的团队成员 | |||
| team_user = member.team_user | |||
| $gitea_client.delete_teams_members_by_id_username(team_user.team.gtid, team_user.user&.login) rescue nil # 移除旧的 | |||
| $gitea_client.put_teams_members_by_id_username(team&.gtid, team_user.user&.login) rescue nil # 新增新的 | |||
| team_user.update_attributes!({team_id: team.id}) | |||
| # 确保组织成员中有该用户 | |||
| OrganizationUser.build(self.user_id, user_id) | |||
| team_user = member.team_user.update(team_id: team&.id) | |||
| when 'Developer' | |||
| # 构建相应的团队 | |||
| team = self.owner.teams.write.take | |||
| team = team.nil? ? Team.build(self.user_id, 'developer', '开发者', '', 'write', false, false) : team | |||
| TeamProject.build(self.user_id, team.id, self.id) | |||
| if team.nil? | |||
| team = Team.build(self.user_id, 'developer', '开发者', '', 'write', false, false) | |||
| gteam = $gitea_client.post_orgs_teams_by_org(self.owner.login, {body: team.to_gitea_hash.to_json}) rescue nil | |||
| team.update_attributes!({gtid: gteam["id"]}) unless gteam.nil? | |||
| end | |||
| # 设置项目在团队中的访问权限 | |||
| team_project = TeamProject.build(self.user_id, team.id, self.id) | |||
| $gitea_client.put_teams_repos_by_id_org_repo(team.gtid, self.owner.login, self.identifier) rescue nil | |||
| # 更改对应的团队成员 | |||
| team_user = member.team_user | |||
| $gitea_client.delete_teams_members_by_id_username(team_user.team.gtid, team_user.user&.login) rescue nil # 移除旧的 | |||
| $gitea_client.put_teams_members_by_id_username(team&.gtid, team_user.user&.login) rescue nil # 新增新的 | |||
| team_user.update_attributes!({team_id: team.id}) | |||
| OrganizationUser.build(self.user_id, user_id) | |||
| team_user = member.team_user.update(team_id: team&.id) | |||
| when 'Reporter' | |||
| # 构建相应的团队 | |||
| team = self.owner.teams.read.take | |||
| team = team.nil? ? Team.build(self.user_id, 'reporter', '报告者', '', 'read', false, false) : team | |||
| TeamProject.build(self.user_id, team.id, self.id) | |||
| if team.nil? | |||
| team = Team.build(self.user_id, 'reporter', '报告者', '', 'read', false, false) | |||
| gteam = $gitea_client.post_orgs_teams_by_org(self.owner.login, {body: team.to_gitea_hash.to_json}) rescue nil | |||
| team.update_attributes!({gtid: gteam["id"]}) unless gteam.nil? | |||
| end | |||
| # 设置项目在团队中的访问权限 | |||
| team_project = TeamProject.build(self.user_id, team.id, self.id) | |||
| tp_result = $gitea_client.put_teams_repos_by_id_org_repo(team.gtid, self.owner.login, self.identifier) rescue nil | |||
| # 更改对应的团队成员 | |||
| team_user = member.team_user | |||
| $gitea_client.delete_teams_members_by_id_username(team_user.team.gtid, team_user.user&.login) rescue nil # 移除旧的 | |||
| $gitea_client.put_teams_members_by_id_username(team&.gtid, team_user.user&.login) rescue nil # 新增新的 | |||
| team_user.update_attributes!({team_id: team.id}) | |||
| # 确保组织成员中有该用户 | |||
| OrganizationUser.build(self.user_id, user_id) | |||
| team_user = member.team_user.update(team_id: team&.id) | |||
| end | |||
| end | |||
| member.member_roles.last.update_attributes!(role: role) | |||
| @@ -11,4 +11,7 @@ | |||
| class Ignore < ApplicationRecord | |||
| include Projectable | |||
| validates :name, :content, presence: true | |||
| validates :name, uniqueness: { case_sensitive: false } | |||
| end | |||
| @@ -11,4 +11,8 @@ | |||
| class License < ApplicationRecord | |||
| include Projectable | |||
| validates :name, :content, presence: true | |||
| validates :name, uniqueness: { case_sensitive: false } | |||
| end | |||
| @@ -13,7 +13,7 @@ | |||
| # | |||
| class MessageTemplate < ApplicationRecord | |||
| self.inheritance_column = nil | |||
| # self.inheritance_column = nil | |||
| PLATFORM = 'GitLink' | |||
| def self.build_init_data | |||
| @@ -12,4 +12,6 @@ | |||
| class ProjectLanguage < ApplicationRecord | |||
| include Projectable | |||
| validates :name, uniqueness: { message: "已存在" } | |||
| end | |||
| @@ -70,4 +70,15 @@ class Team < ApplicationRecord | |||
| end | |||
| end | |||
| def to_gitea_hash | |||
| { | |||
| can_create_org_repo: self.can_create_org_project, | |||
| description: self.description || "", | |||
| includes_all_repositories: self.includes_all_project, | |||
| name: self.name, | |||
| permission: self.authorize, | |||
| units: self.team_units.pluck(:unit_type).map{|i| "repo.#{i}"} | |||
| } | |||
| end | |||
| end | |||
| @@ -29,6 +29,8 @@ class Projects::ListMyQuery < ApplicationQuery | |||
| projects = projects.where(user_id: user.id) | |||
| elsif params[:category].to_s == "watched" #我关注的 | |||
| projects = projects.where.not(user_id: user.id).joins(:watchers).where(watchers: {watchable_type: "Project", user_id: user.id}) | |||
| elsif params[:category].to_s == 'only_watched' | |||
| projects = projects.joins(:watchers).where(watchers: {watchable_type: "Project", user_id: user.id}) | |||
| elsif params[:category].to_s == "forked" #我fork的 | |||
| fork_ids = user.fork_users.select(:id, :fork_project_id).pluck(:fork_project_id) | |||
| projects = projects.where(id: fork_ids) | |||
| @@ -53,6 +53,8 @@ class Api::V1::Users::Projects::ListService < ApplicationService | |||
| projects = Project.from("( #{normal_projects} UNION #{org_projects} ) AS projects").distinct | |||
| when 'watched' | |||
| projects = projects.where.not(user_id: observe_user.id).joins(:watchers).where(watchers: {watchable_type: "Project", user_id: observe_user.id}) | |||
| when 'only_watched' | |||
| projects = projects.where.joins(:watchers).where(watchers: {watchable_type: "Project", user_id: observe_user.id}) | |||
| when 'forked' | |||
| fork_ids = observe_user.fork_users.select(:id, :fork_project_id).pluck(:fork_project_id) | |||
| projects = projects.where(id: fork_ids) | |||
| @@ -20,10 +20,13 @@ class Api::V1::Users::UpdateEmailService < ApplicationService | |||
| 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? | |||
| exist_owner = Owner.find_by(mail: @mail) | |||
| raise Error, "邮箱已被使用." if exist_owner | |||
| is_debug = @code == "123123" && EduSetting.get("code_debug") # 万能验证码,用于测试 # TODO 万能验证码,用于测试 | |||
| raise Error, "验证码不正确." if @verify_code&.code != @code && !is_debug | |||
| raise Error, "验证码已失效." if !@verify_code&.effective? && !is_debug | |||
| # begin | |||
| begin | |||
| ActiveRecord::Base.transaction do | |||
| change_user_email | |||
| excute_data_to_gitea | |||
| @@ -32,15 +35,15 @@ class Api::V1::Users::UpdateEmailService < ApplicationService | |||
| return gitea_data | |||
| # rescue | |||
| # raise Error, "服务器错误,请联系系统管理员!" | |||
| # end | |||
| rescue | |||
| raise Error, "服务器错误,请联系系统管理员!" | |||
| end | |||
| end | |||
| private | |||
| def request_params | |||
| { | |||
| access_token: token | |||
| access_token: @user.gitea_token | |||
| } | |||
| end | |||
| @@ -0,0 +1,23 @@ | |||
| class Gitea::Repository::Tags::ListNameService < Gitea::ClientService | |||
| attr_reader :user, :repo, :name | |||
| def initialize(user, repo, name=nil) | |||
| @user = user | |||
| @repo = repo | |||
| @name = name | |||
| end | |||
| def call | |||
| response = get(url, params) | |||
| render_200_response(response) | |||
| end | |||
| private | |||
| def params | |||
| Hash.new.merge(token: user.gitea_token, name: name) | |||
| end | |||
| def url | |||
| "/repos/#{user.login}/#{repo}/tag_name_set".freeze | |||
| end | |||
| end | |||
| @@ -24,9 +24,11 @@ class Projects::TransferService < ApplicationService | |||
| private | |||
| def update_owner | |||
| # 转移项目需要移除原来的权限 | |||
| project.members.update_all(team_user_id: nil) | |||
| project.members.map{|m| m.destroy! if m.user_id == owner.id || project.member(new_owner.id) || (new_owner.is_a?(Organization) && new_owner.is_member?(m.user_id)) } | |||
| project.set_owner_permission(new_owner) | |||
| project.update!(user_id: new_owner.id) | |||
| project.set_owner_permission(new_owner) | |||
| end | |||
| def update_repo_url | |||
| @@ -49,7 +51,8 @@ class Projects::TransferService < ApplicationService | |||
| def gitea_update_owner | |||
| begin | |||
| @gitea_repo = Gitea::Repository::TransferService.call(owner&.gitea_token, owner&.login, project.identifier, new_owner&.login) | |||
| @gitea_repo = $gitea_client.post_repos_transfer_by_owner_repo(owner&.login, project.identifier, {body: {new_owner: new_owner&.login}.to_json}) | |||
| # @gitea_repo = Gitea::Repository::TransferService.call(owner&.gitea_token, owner&.login, project.identifier, new_owner&.login) | |||
| rescue Exception => e | |||
| Rails.logger.info("##### Project transfer_service, gitea transfer error #{e}") | |||
| end | |||
| @@ -24,6 +24,9 @@ class PullRequests::MergeService < ApplicationService | |||
| result = Gitea::PullRequest::MergeService.call(@current_user.gitea_token, @owner.login, | |||
| @repo.identifier, @pull.gitea_number, gitea_merge_pull_params) | |||
| @status, @message = result | |||
| if @status.to_i == 409 | |||
| @message = "代码冲突,请重新提交合并请求" | |||
| end | |||
| end | |||
| def gitea_merge_pull_params | |||
| @@ -21,6 +21,7 @@ | |||
| </label> | |||
| <%= p.number_field :pinned_index,class: "form-control input-lg",placeholder: "精选等级",required: true%> | |||
| </div> | |||
| <%if false%> | |||
| <div class="logo-item"> | |||
| <% logo_img = @project_category.logo_url %> | |||
| <div class="logo-item-left mr-3 <%= logo_img ? 'has-img' : '' %>"> | |||
| @@ -34,6 +35,7 @@ | |||
| <div>尺寸:高度38px以内,宽等比例缩放</div> | |||
| </div> | |||
| </div> | |||
| <% end %> | |||
| </div> | |||
| <div class="modal-footer"> | |||
| <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button> | |||
| @@ -13,7 +13,7 @@ | |||
| </span> | |||
| </label> | |||
| <div class="mt-10"> | |||
| <%= f.text_field :name, class: "form-control input-lg", maxlength: "60", placeholder: "请输入忽略文件的全称" %> | |||
| <%= f.text_field :name, class: "form-control input-lg", maxlength: "60", placeholder: "请输入忽略文件的全称", required: true%> | |||
| </div> | |||
| </div> | |||
| @@ -25,7 +25,7 @@ | |||
| </span> | |||
| </label> | |||
| <div class="mt-10"> | |||
| <%= f.text_area :content,class:"form-control", rows: "10", cols: "20",placeholer: "忽略文件的简要介绍,不得超过500字" %> | |||
| <%= f.text_area :content,class:"form-control", rows: "10", cols: "20",placeholer: "忽略文件的简要介绍,不得超过500字", required: true %> | |||
| </div> | |||
| @@ -13,7 +13,7 @@ | |||
| </span> | |||
| </label> | |||
| <div class="mt-10"> | |||
| <%= f.text_field :name, class: "form-control input-lg", maxlength: "60", placeholder: "请输入开源许可证的全称" %> | |||
| <%= f.text_field :name, class: "form-control input-lg", maxlength: "60", placeholder: "请输入开源许可证的全称", required: true %> | |||
| </div> | |||
| </div> | |||
| @@ -25,7 +25,7 @@ | |||
| </span> | |||
| </label> | |||
| <div class="mt-10"> | |||
| <%= f.text_area :content,class:"form-control", rows: "10", cols: "20",placeholer: "许可证的简要介绍,不得超过500字" %> | |||
| <%= f.text_area :content,class:"form-control", rows: "10", cols: "20",placeholer: "许可证的简要介绍,不得超过500字", required: true %> | |||
| </div> | |||
| @@ -14,7 +14,7 @@ | |||
| <th width="5%">成员</th> | |||
| <th width="12%">管理员</th> | |||
| <th width="15%"><%= sort_tag('创建时间', name: 'created_on', path: admins_projects_path) %></th> | |||
| <th width="25%">操作</th> | |||
| <th width="15%">操作</th> | |||
| </tr> | |||
| </thead> | |||
| <tbody> | |||
| @@ -2,7 +2,7 @@ | |||
| <thead class="thead-light"> | |||
| <tr> | |||
| <th width="4%">序号</th> | |||
| <th width="8%" class="text-left">真实姓名</th> | |||
| <th width="8%" class="text-left">昵称</th> | |||
| <th width="13%">邮件地址</th> | |||
| <th width="10%">手机号码</th> | |||
| <th width="7%">角色</th> | |||
| @@ -1,5 +1,6 @@ | |||
| json.array! @tags do |tag| | |||
| if tag.present? | |||
| json.total_count @tag_names.present? ? @tag_names.count : @tags.count | |||
| json.tags @tags do |tag| | |||
| if tag.present? && tag.is_a?(Hash) | |||
| json.name tag['name'] | |||
| json.id tag['id'] | |||
| json.zipball_url render_zip_url(@owner, @repository, tag['name']) | |||
| @@ -22,6 +23,8 @@ json.array! @tags do |tag| | |||
| json.partial! 'commit_author', user: render_cache_commit_author(tag['commit']['author']), name: tag['commit']['author']['name'] | |||
| end | |||
| end | |||
| else | |||
| json.name tag | |||
| end | |||
| end | |||
| @@ -3,3 +3,4 @@ json.login @user.login | |||
| json.user_id @user.id | |||
| json.image_url url_to_avatar(@user) | |||
| json.admin @user.admin | |||
| json.email @user.mail | |||
| @@ -361,7 +361,7 @@ Doorkeeper.configure do | |||
| # https://datatracker.ietf.org/doc/html/rfc6819#section-4.4.3 | |||
| # | |||
| # | |||
| grant_flows %w[authorization_code client_credentials password] | |||
| grant_flows %w[authorization_code client_credentials password refresh_token] | |||
| # Allows to customize OAuth grant flows that +each+ application support. | |||
| # You can configure a custom block (or use a class respond to `#call`) that must | |||
| @@ -223,6 +223,14 @@ zh-CN: | |||
| platform: '直播平台' | |||
| live_time: '开播时间' | |||
| duration: '直播时长' | |||
| project_language: | |||
| name: '项目语言' | |||
| license: | |||
| name: '许可证名称' | |||
| content: '许可证内容' | |||
| ignore: | |||
| name: 'git忽略文件名称' | |||
| content: 'git忽略文件内容' | |||
| close_pr: 合并请求 | |||
| roles: | |||
| Developer: 开发者 | |||
| @@ -4,6 +4,37 @@ desc "初始化数据同步到gitea平台" | |||
| # 再同步项目及项目成员 | |||
| namespace :sync_data_to_gitea do | |||
| desc "同步组织数据" | |||
| # 同步组织成员,并仅保留最高权限 | |||
| task organizations: :environment do | |||
| Organization.includes(:organization_users, teams: [:team_users, :team_projects]).find_each do |org| | |||
| ActiveRecord::Base.transaction do | |||
| org.teams.each do |team| | |||
| if team.gtid.blank? | |||
| gteam = $gitea_client.post_orgs_teams_by_org(org.login, {body: team.to_gitea_hash.to_json}) rescue nil | |||
| team.update_attributes!({gtid: gteam["id"]}) unless gteam.nil? | |||
| end | |||
| team.team_users.each do |teamuser| | |||
| userlogin = teamuser&.user&.login | |||
| ou = org.organization_users.find_by(user_id: teamuser.user_id) | |||
| OrganizationUser.build(org.id, teamuser.user_id) unless ou.present? | |||
| next if ($gitea_client.get_teams_members_by_id_username(team.gtid, userlogin) rescue nil) | |||
| tu_result = $gitea_client.put_teams_members_by_id_username(team.gtid, userlogin) rescue nil | |||
| raise ActiveRecord::Rollback if tu_result.nil? | |||
| end | |||
| team.team_projects.each do |teamp| | |||
| tp_result = $gitea_client.put_teams_repos_by_id_org_repo(team.gtid, org.login, teamp&.project.identifier) rescue nil | |||
| raise ActiveRecord::Rollback if tp_result.nil? | |||
| end | |||
| end | |||
| org.organization_users.each do |user| | |||
| $gitea_client.get_orgs_members_by_org_username(org.login, user.login) rescue next | |||
| user.destroy! | |||
| end | |||
| end | |||
| end | |||
| end | |||
| desc "同步用户" | |||
| task users: :environment do | |||
| users = User.where.not(mail: [nil, ""], type: 'Anonymous').or(User.where.not(login: [nil, ""])).distinct | |||