parent
d92afe5282
commit
5e4bd66c56
@ -0,0 +1,19 @@
|
||||
$(document).on('turbolinks:load', function() {
|
||||
if ($('body.admins-mirror-repositories-edit-page, body.admins-mirror-repositories-update-page').length > 0) {
|
||||
var $form = $('form.edit-mirror');
|
||||
|
||||
$form.validate({
|
||||
errorElement: 'span',
|
||||
errorClass: 'danger text-danger',
|
||||
rules: {
|
||||
"mirror_repository[type_name]": {
|
||||
required: true
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$form.submit(function(e){
|
||||
if(!$form.valid()){ e.preventDefault(); }
|
||||
});
|
||||
}
|
||||
});
|
@ -0,0 +1,4 @@
|
||||
$(document).on('turbolinks:load', function() {
|
||||
if ($('body.admins-mirror-repositories-index-page').length > 0) {
|
||||
}
|
||||
});
|
@ -0,0 +1,32 @@
|
||||
$(document).on('turbolinks:load', function() {
|
||||
$('.admin-modal-container').on('show.bs.modal', '.modal.admin-choose-mirror-modal', function(){
|
||||
var $modal = $('.modal.admin-choose-mirror-modal');
|
||||
var $form = $modal.find('form.admin-choose-mirror-form');
|
||||
|
||||
var validateForm = function(){
|
||||
var checkedValue = $form.find('input[name="mirror_number"]:checked').val();
|
||||
|
||||
if(checkedValue == undefined){
|
||||
$modal.find('.error').html('必须选择一种镜像保存!');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
$modal.on('click', '.submit-btn', function(){
|
||||
$form.find('.error').html('');
|
||||
var url = $form.attr('action');
|
||||
|
||||
if (validateForm()) {
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
dataType: 'script',
|
||||
url: url,
|
||||
data: $form.serialize(),
|
||||
}).done(function(){
|
||||
$modal.modal('hide');
|
||||
});
|
||||
}
|
||||
});
|
||||
})
|
||||
});
|
@ -0,0 +1,89 @@
|
||||
$(document).on('turbolinks:load', function() {
|
||||
var $modal = $('.modal.admin-replace-mirror-modal');
|
||||
if ($modal.length > 0) {
|
||||
var $form = $modal.find('form.admin-replace-mirror-form');
|
||||
var $mirrorIdInput = $modal.find('.modal-body input[name="mirror_id"]');
|
||||
var $mirrorSelect = $modal.find('.new-mirror-select');
|
||||
|
||||
var setMirror = function(id, name){
|
||||
$mirrorIdInput.val(id);
|
||||
$form.find('.mirror-id-container').html(id);
|
||||
$form.find('.mirror-name-container').html(name);
|
||||
}
|
||||
|
||||
$form.validate({
|
||||
errorElement: 'span',
|
||||
errorClass: 'danger text-danger',
|
||||
rules: {
|
||||
new_mirror_id: {
|
||||
required: true
|
||||
},
|
||||
},
|
||||
messages: {
|
||||
new_mirror_id: {
|
||||
required: '请选择新镜像'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// modal ready fire
|
||||
$modal.on('show.bs.modal', function (event) {
|
||||
var $link = $(event.relatedTarget);
|
||||
|
||||
var mirrorId = $link.data('id');
|
||||
var mirrorName = $link.data('name');
|
||||
|
||||
setMirror(mirrorId, mirrorName);
|
||||
$mirrorSelect.select2('val', ' ');
|
||||
});
|
||||
$modal.on('hide.bs.modal', function () {
|
||||
setMirror('', '');
|
||||
$mirrorSelect.select2('val', ' ');
|
||||
$('#new_mirror_id-error').remove();
|
||||
});
|
||||
|
||||
$mirrorSelect.select2({
|
||||
theme: 'bootstrap4',
|
||||
placeholder: '输入要合并的镜像名',
|
||||
minimumInputLength: 1,
|
||||
ajax: {
|
||||
url: '/admins/mirror_repositories/for_select',
|
||||
dataType: 'json',
|
||||
data: function(params){
|
||||
return { keyword: params.term };
|
||||
},
|
||||
processResults: function(data){
|
||||
return { results: data.mirrors }
|
||||
}
|
||||
},
|
||||
templateResult: function (item) {
|
||||
if(!item.id || item.id === '') return item.text;
|
||||
return item.name;
|
||||
},
|
||||
templateSelection: function(item){
|
||||
if (item.id) {
|
||||
$('#new_mirror_id-error').remove();
|
||||
$('#new_mirror_id').val(item.id);
|
||||
}
|
||||
return item.name || item.text;
|
||||
}
|
||||
});
|
||||
|
||||
$modal.on('click', '.submit-btn', function(){
|
||||
$form.find('.error').html('');
|
||||
|
||||
if ($form.valid()) {
|
||||
var url = $form.data('url');
|
||||
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
dataType: 'script',
|
||||
url: url,
|
||||
data: $form.serialize(),
|
||||
}).done(function(){
|
||||
$modal.modal('hide');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
@ -0,0 +1,11 @@
|
||||
class Admins::ChooseMirrorRepositoriesController < Admins::BaseController
|
||||
def new
|
||||
@mirror = MirrorRepository.find(params[:mirror_id])
|
||||
@new_mirror = MirrorOperationRecord.where(mirror_repository_id: @mirror.id, status: 1, user_id: -1).first
|
||||
end
|
||||
|
||||
def create
|
||||
mirror = MirrorRepository.find(params[:mirror_id])
|
||||
Admins::ChooseMirrorService.call(mirror, current_user, params[:mirror_number])
|
||||
end
|
||||
end
|
@ -0,0 +1,96 @@
|
||||
class Admins::MirrorRepositoriesController < Admins::BaseController
|
||||
before_action :check_shixun_mirrors!, only: [:index]
|
||||
|
||||
def index
|
||||
mirrors = MirrorRepository.all
|
||||
mirrors = mirrors.reorder(status: :desc, main_type: :desc, type_name: :asc)
|
||||
|
||||
@mirrors = paginate mirrors.includes(:mirror_scripts)
|
||||
@error_mirror_names = MirrorRepository.where(status: 5).pluck(:name)
|
||||
end
|
||||
|
||||
def new
|
||||
@mirror = MirrorRepository.new
|
||||
end
|
||||
|
||||
def create
|
||||
@mirror = MirrorRepository.new
|
||||
Admins::SaveMirrorRepositoryService.call(@mirror, current_user, form_params)
|
||||
|
||||
flash[:success] = '保存成功'
|
||||
redirect_to edit_admins_mirror_repository_path(@mirror)
|
||||
rescue ActiveRecord::RecordInvalid
|
||||
flash.now[:danger] = '保存失败'
|
||||
render 'new'
|
||||
rescue Admins::SaveMirrorRepositoryService::Error => ex
|
||||
flash.now[:danger] = ex.message
|
||||
render 'new'
|
||||
end
|
||||
|
||||
def edit
|
||||
@mirror = current_mirror
|
||||
end
|
||||
|
||||
def update
|
||||
@mirror = current_mirror
|
||||
|
||||
Admins::SaveMirrorRepositoryService.call(current_mirror, current_user, form_params)
|
||||
|
||||
flash[:success] = '保存成功'
|
||||
redirect_to edit_admins_mirror_repository_path(current_mirror)
|
||||
rescue ActiveRecord::RecordInvalid
|
||||
flash.now[:danger] = '保存失败'
|
||||
render 'edit'
|
||||
rescue Admins::SaveMirrorRepositoryService::Error => ex
|
||||
flash.now[:danger] = ex.message
|
||||
render 'edit'
|
||||
end
|
||||
|
||||
def destroy
|
||||
return render_js_error('该状态下不允许删除') unless current_mirror.deletable?
|
||||
|
||||
current_mirror.destroy!
|
||||
|
||||
render_delete_success
|
||||
end
|
||||
|
||||
def for_select
|
||||
mirrors = MirrorRepository.all
|
||||
|
||||
keyword = params[:keyword].to_s.strip
|
||||
mirrors = mirrors.where('name LIKE ?', "%#{keyword}%") if keyword.present?
|
||||
|
||||
@mirrors = paginate mirrors
|
||||
|
||||
render_ok(count: @mirrors.total_count, mirrors: @mirrors.as_json(only: %i[id name]))
|
||||
end
|
||||
|
||||
def merge
|
||||
origin_mirror = MirrorRepository.find(params[:mirror_id])
|
||||
mirror = MirrorRepository.find(params[:new_mirror_id])
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
origin_mirror.update!(name: mirror.name, mirrorID: mirror.mirrorID)
|
||||
mirror.destroy!
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def current_mirror
|
||||
@_current_mirror ||= MirrorRepository.find(params[:id])
|
||||
end
|
||||
|
||||
def form_params
|
||||
columns = %i[type_name main_type time_limit resource_limit cpu_limit memory_limit description status]
|
||||
params.require(:mirror_repository).permit(*columns)
|
||||
end
|
||||
|
||||
def check_shixun_mirrors!
|
||||
return unless request.format.html?
|
||||
|
||||
Admins::CheckShixunMirrorsService.call
|
||||
rescue Admins::CheckShixunMirrorsService::Error => e
|
||||
internal_server_error(e.message)
|
||||
end
|
||||
end
|
@ -0,0 +1,23 @@
|
||||
module Admins::MirrorRepositoriesHelper
|
||||
def mirror_type_tag(mirror)
|
||||
case mirror.main_type
|
||||
when '1' then '<i class="fa fa-star text-success font-16" aria-hidden="true" data-toggle="tooltip" data-title="主类别"></i>'.html_safe
|
||||
when '0' then '<i class="fa fa-star text-secondary font-16" aria-hidden="true" data-toggle="tooltip" data-title="子类别"></i>'.html_safe
|
||||
end
|
||||
end
|
||||
|
||||
def mirror_status_tag(mirror)
|
||||
case mirror.status
|
||||
when 0
|
||||
'<i class="fa fa-check-circle text-secondary font-16" data-toggle="tooltip" data-title="未发布"></i>'.html_safe
|
||||
when 1
|
||||
'<i class="fa fa-check-circle text-success font-16" data-toggle="tooltip" data-title="已发布"></i>'.html_safe
|
||||
when 2, 3
|
||||
'<i class="fa fa-exclamation-circle text-danger font-16" data-toggle="tooltip" data-title="被修改"></i>'.html_safe
|
||||
when 4
|
||||
'<i class="fa fa-times-circle text-danger font-18" data-toggle="tooltip" data-title="被删除"></i>'.html_safe
|
||||
when 5
|
||||
'<i class="fa fa-exclamation-circle text-warning font-16" data-toggle="tooltip" data-title="子节点异常"></i>'.html_safe
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,21 @@
|
||||
class Admins::ChooseMirrorService < ApplicationService
|
||||
attr_reader :mirror, :user, :number
|
||||
|
||||
def initialize(mirror, user, mirror_number)
|
||||
@mirror = mirror
|
||||
@user = user
|
||||
@number = mirror_number
|
||||
end
|
||||
|
||||
def call
|
||||
if mirror.mirrorID == number
|
||||
mirror.update_column(:status, 1)
|
||||
return
|
||||
end
|
||||
|
||||
old_number = mirror.mirrorID
|
||||
mirror.update!(mirrorID: number, status: 1)
|
||||
MirrorOperationRecord.create!(mirror_repository_id: mirror.id, mirror_id: number, mirror_name: mirror.name,
|
||||
status: 1, user_id: user.id, old_tag: old_number, new_tag: mirror.mirrorID)
|
||||
end
|
||||
end
|
@ -0,0 +1,37 @@
|
||||
class Admins::SaveMirrorRepositoryService < ApplicationService
|
||||
Error = Class.new(StandardError)
|
||||
|
||||
attr_reader :mirror, :user, :params
|
||||
|
||||
def initialize(mirror, user, params)
|
||||
@mirror = mirror
|
||||
@user = user
|
||||
@params = params
|
||||
end
|
||||
|
||||
def call
|
||||
mirror.assign_attributes(params)
|
||||
|
||||
raise Error, '镜像别名重复' if MirrorRepository.where.not(id: mirror.id).exists?(type_name: params[:type_name])
|
||||
|
||||
ActiveRecord::Base.transaction do
|
||||
record_operation! if mirror.persisted?
|
||||
|
||||
mirror.save!
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def record_operation!
|
||||
if mirror.type_name_changed?
|
||||
MirrorOperationRecord.create!(mirror_repository_id: mirror.id, status: 5,
|
||||
user_id: user.id, old_tag: mirror.type_name_in_database,
|
||||
new_tag: mirror.type_name)
|
||||
elsif mirror.status_changed?
|
||||
MirrorOperationRecord.create!(mirror_repository_id: mirror.id, status: 5,
|
||||
user_id: user.id, old_tag: mirror.status_in_database,
|
||||
new_tag: mirror.status)
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,5 @@
|
||||
$.notify({ message: '操作成功' },{ type: 'success' });
|
||||
|
||||
setTimeout(function(){
|
||||
window.location.reload();
|
||||
}, 500)
|
@ -0,0 +1,2 @@
|
||||
$('.admin-modal-container').html("<%= j( render partial: 'admins/mirror_repositories/shared/choose_mirror_modal', locals: { mirror: @mirror, new_mirror: @new_mirror } ) %>");
|
||||
$('.modal.admin-choose-mirror-modal').modal('show');
|
@ -0,0 +1,8 @@
|
||||
<%
|
||||
define_admin_breadcrumbs do
|
||||
add_admin_breadcrumb('镜像管理', admins_mirror_repositories_path)
|
||||
add_admin_breadcrumb('镜像详情')
|
||||
end
|
||||
%>
|
||||
|
||||
<%= render partial: 'admins/mirror_repositories/shared/form', locals: { mirror: @mirror, form_action: 'update' } %>
|
@ -0,0 +1,23 @@
|
||||
<% define_admin_breadcrumbs do %>
|
||||
<% add_admin_breadcrumb('镜像管理') %>
|
||||
<% end %>
|
||||
|
||||
<div class="box search-form-container mirror-repository-list-form">
|
||||
<form class="flex-1"></form>
|
||||
<%= link_to '新建', new_admins_mirror_repository_path, class: 'btn btn-primary' %>
|
||||
</div>
|
||||
|
||||
<% if @error_mirror_names.present? %>
|
||||
<div class="box pb-0">
|
||||
以下镜像异常:
|
||||
<% @error_mirror_names.each do |mirror_name| %>
|
||||
<span class="ml-2 text-danger"><%= mirror_name %></span>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="box mirror-repository-list-container">
|
||||
<%= render partial: 'admins/mirror_repositories/shared/list', locals: { mirrors: @mirrors } %>
|
||||
</div>
|
||||
|
||||
<%= render 'admins/mirror_repositories/shared/replace_mirror_modal' %>
|
@ -0,0 +1 @@
|
||||
$('.mirror-repository-list-container').html("<%= j( render partial: 'admins/mirror_repositories/shared/list', locals: { mirrors: @mirrors } ) %>");
|
@ -0,0 +1,5 @@
|
||||
$.notify({ message: '操作成功' },{ type: 'success' });
|
||||
|
||||
setTimeout(function(){
|
||||
window.location.reload();
|
||||
}, 500)
|
@ -0,0 +1,8 @@
|
||||
<%
|
||||
define_admin_breadcrumbs do
|
||||
add_admin_breadcrumb('镜像管理', admins_mirror_repositories_path)
|
||||
add_admin_breadcrumb('新建镜像')
|
||||
end
|
||||
%>
|
||||
|
||||
<%= render partial: 'admins/mirror_repositories/shared/form', locals: { mirror: @mirror, form_action: 'create' } %>
|
@ -0,0 +1,42 @@
|
||||
<div class="modal fade admin-choose-mirror-modal" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">更新镜像仓库</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<%= form_tag(admins_choose_mirror_repositories_path(mirror_id: mirror.id), method: :post, class: 'admin-choose-mirror-form') do %>
|
||||
<div class="form-group row">
|
||||
<div class="col-md-2"></div>
|
||||
<div class="col-md-5">ID</div>
|
||||
<div class="col-md-5">名称</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-md-2">旧镜像</div>
|
||||
<div class="col-md-5 form-check">
|
||||
<input class="form-check-input" type="radio" name="mirror_number" id="old-mirror-check" value="<%= mirror.mirrorID %>">
|
||||
<label class="form-check-label" for="old-mirror-check"><%= mirror.mirrorID %></label>
|
||||
</div>
|
||||
<div class="col-md-5"><%= mirror.name %></div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col-md-2">新镜像</div>
|
||||
<div class="col-md-5 form-check">
|
||||
<input class="form-check-input" type="radio" name="mirror_number" id="new-mirror-check" value="<%= new_mirror.mirror_id %>">
|
||||
<label class="form-check-label" for="new-mirror-check"><%= new_mirror.mirror_id %></label>
|
||||
</div>
|
||||
<div class="col-md-5"><%= new_mirror.mirror_name %></div>
|
||||
</div>
|
||||
<div class="mt-2 error text-danger"></div>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
|
||||
<button type="button" class="btn btn-primary submit-btn">确认</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,42 @@
|
||||
<div class="box edit-mirror-repository-container">
|
||||
<%= simple_form_for([:admins, mirror], url: { action: form_action }, html: { class: 'edit-mirror col-md-12' }, defaults: { wrapper_html: { class: 'col-md-4' } }) do |f| %>
|
||||
<% unless mirror.new_record? %>
|
||||
<div class="row">
|
||||
<%= f.input :mirrorID, label: '镜像ID', input_html: { readonly: true, class: 'form-control-plaintext' } %>
|
||||
<%= f.input :name, label: '镜像名称', input_html: { readonly: true, class: 'form-control-plaintext' } %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="row">
|
||||
<%= f.input :type_name, as: :string, label: '镜像别名 *' %>
|
||||
|
||||
<div class="form-group select optional col-md-4">
|
||||
<%= f.label :main_type, label: '类别' %>
|
||||
<%= f.select :main_type, [['主类别', 1],['小类别', 0]], {}, class: 'form-control optional' %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<%= f.input :time_limit, as: :integer, label: '评测时限(S)' %>
|
||||
<%= f.input :resource_limit, as: :integer, label: '磁盘限制(K)' %>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<%= f.input :cpu_limit, as: :integer, label: 'CPU限制(核)' %>
|
||||
<%= f.input :memory_limit, as: :integer, label: '内存限制(M)' %>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<%= f.input :description, as: :text, label: '描述', wrapper_html: { class: 'col-md-8' } %>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<%= f.input :status, as: :radio_buttons, label: '状态', collection: [%w(未发布 0), %w(已发布 1)], wrapper_html: { class: 'col-md-4' } %>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<%= f.button :submit, value: '保存', class: 'btn-primary mr-3 px-4', 'data-disable-with': '保存中...' %>
|
||||
<%= link_to '取消', admins_mirror_repositories_path, class: 'btn btn-secondary px-4' %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
@ -0,0 +1,54 @@
|
||||
<table class="table table-hover text-center mirror-repository-list-table">
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th width="6%">ID</th>
|
||||
<th width="6%">类别</th>
|
||||
<th width="12%" class="text-left">镜像别名</th>
|
||||
<th width="16%" class="text-left">镜像名称</th>
|
||||
<th width="22%" class="text-left">镜像描述</th>
|
||||
<th width="14%">修改时间</th>
|
||||
<th width="6%">脚本</th>
|
||||
<th width="6%">状态</th>
|
||||
<th width="12%">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% if mirrors.present? %>
|
||||
<% mirrors.each do |mirror| %>
|
||||
<tr class="mirror-repository-item-<%= mirror.id %>">
|
||||
<td><%= mirror.id %></td>
|
||||
<td><%= mirror_type_tag(mirror) %></td>
|
||||
<td class="text-left"><%= display_text(mirror.type_name) %></td>
|
||||
<td class="text-left"><%= overflow_hidden_span mirror.name, width: 150 %></td>
|
||||
<td class="text-left"><%= overflow_hidden_span mirror.description, width: 240 %></td>
|
||||
<td><%= mirror.updated_at.strftime('%Y-%m-%d %H:%M') %></td>
|
||||
<td>
|
||||
<% if mirror.main_type == "1" %>
|
||||
<%= link_to "/users/modify_script?mirror_id=#{mirror.id}", target: '_blank' do %>
|
||||
<i class="fa fa-file-text <%= mirror.mirror_scripts.blank? ? 'text-danger' : 'text-success' %>" aria-hidden="true" data-toggle="tooltip" data-title="脚本模板"></i>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</td>
|
||||
<td><%= mirror_status_tag mirror %></td>
|
||||
<td class="action-container">
|
||||
<%= link_to '编辑', edit_admins_mirror_repository_path(mirror), class: 'action edit-action' %>
|
||||
|
||||
<% if mirror.status == 2 %>
|
||||
<%= link_to '同步', new_admins_choose_mirror_repository_path(mirror_id: mirror.id), remote: true, class: 'action sync-action' %>
|
||||
<% end %>
|
||||
|
||||
<%= javascript_void_link '替换', class: 'action replace-action', data: { toggle: 'modal', target: '.admin-replace-mirror-modal', id: mirror.id, name: mirror.name } %>
|
||||
|
||||
<% if mirror.deletable? %>
|
||||
<%= delete_link '删除', admins_mirror_repository_path(mirror, element: ".mirror-repository-item-#{mirror.id}"), class: 'delete-mirror-repository-action' %>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= render 'admins/shared/no_data_for_table' %>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<%= render partial: 'admins/shared/paginate', locals: { objects: mirrors } %>
|
@ -1,5 +1,5 @@
|
||||
<div class="paginate-container">
|
||||
<% if objects.size.nonzero? %>
|
||||
<% if objects && objects.size.nonzero? %>
|
||||
<div class="paginate-total"><%= page_entries_info objects %></div>
|
||||
<% end %>
|
||||
<%= paginate objects, views_prefix: 'admins', remote: true %>
|
||||
|
Loading…
Reference in new issue