forked from Gitlink/forgeplus
Merge pull request '20221101版本' (#312) from Trustie/forgeplus:trustie_server into master
This commit is contained in:
commit
991516ed70
2
Gemfile
2
Gemfile
|
@ -135,4 +135,4 @@ gem 'doorkeeper'
|
||||||
|
|
||||||
gem 'doorkeeper-jwt'
|
gem 'doorkeeper-jwt'
|
||||||
|
|
||||||
gem 'gitea-client', '~> 0.10.2'
|
gem 'gitea-client', '~> 0.10.5'
|
|
@ -1,136 +1,137 @@
|
||||||
//= require rails-ujs
|
//= require rails-ujs
|
||||||
//= require activestorage
|
//= require activestorage
|
||||||
//= require turbolinks
|
//= require turbolinks
|
||||||
//= require jquery3
|
//= require jquery3
|
||||||
//= require popper
|
//= require popper
|
||||||
//= require bootstrap-sprockets
|
//= require bootstrap-sprockets
|
||||||
//= require jquery.validate.min
|
//= require jquery.validate.min
|
||||||
//= require additional-methods.min
|
//= require additional-methods.min
|
||||||
//= require bootstrap-notify
|
//= require bootstrap-notify
|
||||||
//= require jquery.cookie.min
|
//= require jquery.cookie.min
|
||||||
//= require select2
|
//= require select2
|
||||||
//= require moment.min
|
//= require moment.min
|
||||||
//= require jquery.cxselect
|
//= require jquery.cxselect
|
||||||
//= require bootstrap-datepicker
|
//= require bootstrap-datepicker
|
||||||
//= require bootstrap-datetimepicker
|
//= require bootstrap-datetimepicker
|
||||||
//= require bootstrap.viewer
|
//= require bootstrap.viewer
|
||||||
//= require jquery.mloading
|
//= require bootstrap/bootstrap-toggle
|
||||||
//= require jquery-confirm.min
|
//= require jquery.mloading
|
||||||
//= require common
|
//= require jquery-confirm.min
|
||||||
|
//= require common
|
||||||
//= require echarts
|
|
||||||
//= require codemirror/lib/codemirror
|
//= require echarts
|
||||||
//= require codemirror/mode/shell/shell
|
//= require codemirror/lib/codemirror
|
||||||
//= require editormd/editormd
|
//= require codemirror/mode/shell/shell
|
||||||
//= require editormd/languages/zh-tw
|
//= require editormd/editormd
|
||||||
//= require dragula/dragula
|
//= require editormd/languages/zh-tw
|
||||||
|
//= require dragula/dragula
|
||||||
//= require_tree ./i18n
|
|
||||||
//= require_tree ./admins
|
//= require_tree ./i18n
|
||||||
|
//= require_tree ./admins
|
||||||
|
|
||||||
$.ajaxSetup({
|
|
||||||
beforeSend: function(xhr) {
|
$.ajaxSetup({
|
||||||
xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
|
beforeSend: function(xhr) {
|
||||||
}
|
xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
|
||||||
});
|
}
|
||||||
|
});
|
||||||
// ******** select2 global config ********
|
|
||||||
$.fn.select2.defaults.set('theme', 'bootstrap4');
|
// ******** select2 global config ********
|
||||||
$.fn.select2.defaults.set('language', 'zh-CN');
|
$.fn.select2.defaults.set('theme', 'bootstrap4');
|
||||||
|
$.fn.select2.defaults.set('language', 'zh-CN');
|
||||||
Turbolinks.setProgressBarDelay(200);
|
|
||||||
|
Turbolinks.setProgressBarDelay(200);
|
||||||
$.notifyDefaults({
|
|
||||||
type: 'success',
|
$.notifyDefaults({
|
||||||
z_index: 9999,
|
type: 'success',
|
||||||
delay: 2000
|
z_index: 9999,
|
||||||
});
|
delay: 2000
|
||||||
|
});
|
||||||
function show_success_flash(){
|
|
||||||
$.notify({
|
function show_success_flash(){
|
||||||
message: '操作成功'
|
$.notify({
|
||||||
},{
|
message: '操作成功'
|
||||||
type: 'success'
|
},{
|
||||||
});
|
type: 'success'
|
||||||
}
|
});
|
||||||
|
}
|
||||||
$(document).on('turbolinks:load', function(){
|
|
||||||
$('[data-toggle="tooltip"]').tooltip({ trigger : 'hover' });
|
$(document).on('turbolinks:load', function(){
|
||||||
$('[data-toggle="popover"]').popover();
|
$('[data-toggle="tooltip"]').tooltip({ trigger : 'hover' });
|
||||||
|
$('[data-toggle="popover"]').popover();
|
||||||
// 图片查看大图
|
|
||||||
$('img.preview-image').bootstrapViewer();
|
// 图片查看大图
|
||||||
|
$('img.preview-image').bootstrapViewer();
|
||||||
// flash alert提示框自动关闭
|
|
||||||
if($('.admin-alert-container .alert').length > 0){
|
// flash alert提示框自动关闭
|
||||||
setTimeout(function(){
|
if($('.admin-alert-container .alert').length > 0){
|
||||||
$('.admin-alert-container .alert:not(.alert-danger)').alert('close');
|
setTimeout(function(){
|
||||||
}, 2000);
|
$('.admin-alert-container .alert:not(.alert-danger)').alert('close');
|
||||||
setTimeout(function(){
|
}, 2000);
|
||||||
$('.admin-alert-container .alert.alert-danger').alert('close');
|
setTimeout(function(){
|
||||||
}, 5000);
|
$('.admin-alert-container .alert.alert-danger').alert('close');
|
||||||
}
|
}, 5000);
|
||||||
});
|
}
|
||||||
|
});
|
||||||
$(document).on("turbolinks:before-cache", function () {
|
|
||||||
$('[data-toggle="tooltip"]').tooltip('hide');
|
$(document).on("turbolinks:before-cache", function () {
|
||||||
$('[data-toggle="popover"]').popover('hide');
|
$('[data-toggle="tooltip"]').tooltip('hide');
|
||||||
});
|
$('[data-toggle="popover"]').popover('hide');
|
||||||
// var progressBar = new Turbolinks.ProgressBar();
|
});
|
||||||
|
// var progressBar = new Turbolinks.ProgressBar();
|
||||||
// $(document).on('ajax:send', function(event){
|
|
||||||
// console.log('ajax send', event);
|
// $(document).on('ajax:send', function(event){
|
||||||
// progressBar.setValue(0)
|
// console.log('ajax send', event);
|
||||||
// progressBar.show()
|
// progressBar.setValue(0)
|
||||||
// });
|
// progressBar.show()
|
||||||
//
|
// });
|
||||||
// $(document).on('ajax:complete', function(event){
|
//
|
||||||
// console.log('ajax complete', event);
|
// $(document).on('ajax:complete', function(event){
|
||||||
// progressBar.setValue(1)
|
// console.log('ajax complete', event);
|
||||||
// progressBar.hide() // 分页时不触发,奇怪
|
// progressBar.setValue(1)
|
||||||
// });
|
// progressBar.hide() // 分页时不触发,奇怪
|
||||||
// $(document).on('ajax:success', function(event){
|
// });
|
||||||
// console.log('ajax success', event);
|
// $(document).on('ajax:success', function(event){
|
||||||
// });
|
// console.log('ajax success', event);
|
||||||
// $(document).on('ajax:error', function(event){
|
// });
|
||||||
// console.log('ajax error', event);
|
// $(document).on('ajax:error', function(event){
|
||||||
// });
|
// console.log('ajax error', event);
|
||||||
|
// });
|
||||||
$(function () {
|
|
||||||
});
|
$(function () {
|
||||||
|
});
|
||||||
$(document).on('turbolinks:load', function() {
|
|
||||||
|
$(document).on('turbolinks:load', function() {
|
||||||
$('.logo-item-left').on("change", 'input[type="file"]', function () {
|
|
||||||
var $fileInput = $(this);
|
$('.logo-item-left').on("change", 'input[type="file"]', function () {
|
||||||
var file = this.files[0];
|
var $fileInput = $(this);
|
||||||
var imageType = /image.*/;
|
var file = this.files[0];
|
||||||
if (file && file.type.match(imageType)) {
|
var imageType = /image.*/;
|
||||||
var reader = new FileReader();
|
if (file && file.type.match(imageType)) {
|
||||||
reader.onload = function () {
|
var reader = new FileReader();
|
||||||
var $box = $fileInput.parent();
|
reader.onload = function () {
|
||||||
$box.find('img').attr('src', reader.result).css('display', 'block');
|
var $box = $fileInput.parent();
|
||||||
$box.addClass('has-img');
|
$box.find('img').attr('src', reader.result).css('display', 'block');
|
||||||
};
|
$box.addClass('has-img');
|
||||||
reader.readAsDataURL(file);
|
};
|
||||||
} else {
|
reader.readAsDataURL(file);
|
||||||
}
|
} else {
|
||||||
});
|
}
|
||||||
|
});
|
||||||
$('.attachment-item-left').on("change", 'input[type="file"]', function () {
|
|
||||||
var $fileInput = $(this);
|
$('.attachment-item-left').on("change", 'input[type="file"]', function () {
|
||||||
var file = this.files[0];
|
var $fileInput = $(this);
|
||||||
var imageType = /image.*/;
|
var file = this.files[0];
|
||||||
if (file && file.type.match(imageType)) {
|
var imageType = /image.*/;
|
||||||
var reader = new FileReader();
|
if (file && file.type.match(imageType)) {
|
||||||
reader.onload = function () {
|
var reader = new FileReader();
|
||||||
var $box = $fileInput.parent();
|
reader.onload = function () {
|
||||||
$box.find('img').attr('src', reader.result).css('display', 'block');
|
var $box = $fileInput.parent();
|
||||||
$box.addClass('has-img');
|
$box.find('img').attr('src', reader.result).css('display', 'block');
|
||||||
};
|
$box.addClass('has-img');
|
||||||
reader.readAsDataURL(file);
|
};
|
||||||
} else {
|
reader.readAsDataURL(file);
|
||||||
}
|
} else {
|
||||||
});
|
}
|
||||||
|
});
|
||||||
})
|
})
|
|
@ -0,0 +1,180 @@
|
||||||
|
/*! ========================================================================
|
||||||
|
* Bootstrap Toggle: bootstrap-toggle.js v2.2.0
|
||||||
|
* http://www.bootstraptoggle.com
|
||||||
|
* ========================================================================
|
||||||
|
* Copyright 2014 Min Hur, The New York Times Company
|
||||||
|
* Licensed under MIT
|
||||||
|
* ======================================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
+function ($) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// TOGGLE PUBLIC CLASS DEFINITION
|
||||||
|
// ==============================
|
||||||
|
|
||||||
|
var Toggle = function (element, options) {
|
||||||
|
this.$element = $(element)
|
||||||
|
this.options = $.extend({}, this.defaults(), options)
|
||||||
|
this.render()
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.VERSION = '2.2.0'
|
||||||
|
|
||||||
|
Toggle.DEFAULTS = {
|
||||||
|
on: 'On',
|
||||||
|
off: 'Off',
|
||||||
|
onstyle: 'primary',
|
||||||
|
offstyle: 'default',
|
||||||
|
size: 'normal',
|
||||||
|
style: '',
|
||||||
|
width: null,
|
||||||
|
height: null
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.defaults = function() {
|
||||||
|
return {
|
||||||
|
on: this.$element.attr('data-on') || Toggle.DEFAULTS.on,
|
||||||
|
off: this.$element.attr('data-off') || Toggle.DEFAULTS.off,
|
||||||
|
onstyle: this.$element.attr('data-onstyle') || Toggle.DEFAULTS.onstyle,
|
||||||
|
offstyle: this.$element.attr('data-offstyle') || Toggle.DEFAULTS.offstyle,
|
||||||
|
size: this.$element.attr('data-size') || Toggle.DEFAULTS.size,
|
||||||
|
style: this.$element.attr('data-style') || Toggle.DEFAULTS.style,
|
||||||
|
width: this.$element.attr('data-width') || Toggle.DEFAULTS.width,
|
||||||
|
height: this.$element.attr('data-height') || Toggle.DEFAULTS.height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.render = function () {
|
||||||
|
this._onstyle = 'btn-' + this.options.onstyle
|
||||||
|
this._offstyle = 'btn-' + this.options.offstyle
|
||||||
|
var size = this.options.size === 'large' ? 'btn-lg'
|
||||||
|
: this.options.size === 'small' ? 'btn-sm'
|
||||||
|
: this.options.size === 'mini' ? 'btn-xs'
|
||||||
|
: ''
|
||||||
|
var $toggleOn = $('<label class="btn">').html(this.options.on)
|
||||||
|
.addClass(this._onstyle + ' ' + size)
|
||||||
|
var $toggleOff = $('<label class="btn">').html(this.options.off)
|
||||||
|
.addClass(this._offstyle + ' ' + size + ' active')
|
||||||
|
var $toggleHandle = $('<span class="toggle-handle btn btn-default">')
|
||||||
|
.addClass(size)
|
||||||
|
var $toggleGroup = $('<div class="toggle-group">')
|
||||||
|
.append($toggleOn, $toggleOff, $toggleHandle)
|
||||||
|
var $toggle = $('<div class="toggle btn" data-toggle="toggle">')
|
||||||
|
.addClass( this.$element.prop('checked') ? this._onstyle : this._offstyle+' off' )
|
||||||
|
.addClass(size).addClass(this.options.style)
|
||||||
|
|
||||||
|
this.$element.wrap($toggle)
|
||||||
|
$.extend(this, {
|
||||||
|
$toggle: this.$element.parent(),
|
||||||
|
$toggleOn: $toggleOn,
|
||||||
|
$toggleOff: $toggleOff,
|
||||||
|
$toggleGroup: $toggleGroup
|
||||||
|
})
|
||||||
|
this.$toggle.append($toggleGroup)
|
||||||
|
|
||||||
|
var width = this.options.width || Math.max($toggleOn.outerWidth(), $toggleOff.outerWidth())+($toggleHandle.outerWidth()/2)
|
||||||
|
var height = this.options.height || Math.max($toggleOn.outerHeight(), $toggleOff.outerHeight())
|
||||||
|
$toggleOn.addClass('toggle-on')
|
||||||
|
$toggleOff.addClass('toggle-off')
|
||||||
|
this.$toggle.css({ width: width, height: height })
|
||||||
|
if (this.options.height) {
|
||||||
|
$toggleOn.css('line-height', $toggleOn.height() + 'px')
|
||||||
|
$toggleOff.css('line-height', $toggleOff.height() + 'px')
|
||||||
|
}
|
||||||
|
this.update(true)
|
||||||
|
this.trigger(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.toggle = function () {
|
||||||
|
if (this.$element.prop('checked')) this.off()
|
||||||
|
else this.on()
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.on = function (silent) {
|
||||||
|
if (this.$element.prop('disabled')) return false
|
||||||
|
this.$toggle.removeClass(this._offstyle + ' off').addClass(this._onstyle)
|
||||||
|
this.$element.prop('checked', true)
|
||||||
|
if (!silent) this.trigger()
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.off = function (silent) {
|
||||||
|
if (this.$element.prop('disabled')) return false
|
||||||
|
this.$toggle.removeClass(this._onstyle).addClass(this._offstyle + ' off')
|
||||||
|
this.$element.prop('checked', false)
|
||||||
|
if (!silent) this.trigger()
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.enable = function () {
|
||||||
|
this.$toggle.removeAttr('disabled')
|
||||||
|
this.$element.prop('disabled', false)
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.disable = function () {
|
||||||
|
this.$toggle.attr('disabled', 'disabled')
|
||||||
|
this.$element.prop('disabled', true)
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.update = function (silent) {
|
||||||
|
if (this.$element.prop('disabled')) this.disable()
|
||||||
|
else this.enable()
|
||||||
|
if (this.$element.prop('checked')) this.on(silent)
|
||||||
|
else this.off(silent)
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.trigger = function (silent) {
|
||||||
|
this.$element.off('change.bs.toggle')
|
||||||
|
if (!silent) this.$element.change()
|
||||||
|
this.$element.on('change.bs.toggle', $.proxy(function() {
|
||||||
|
this.update()
|
||||||
|
}, this))
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.destroy = function() {
|
||||||
|
this.$element.off('change.bs.toggle')
|
||||||
|
this.$toggleGroup.remove()
|
||||||
|
this.$element.removeData('bs.toggle')
|
||||||
|
this.$element.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TOGGLE PLUGIN DEFINITION
|
||||||
|
// ========================
|
||||||
|
|
||||||
|
function Plugin(option) {
|
||||||
|
return this.each(function () {
|
||||||
|
var $this = $(this)
|
||||||
|
var data = $this.data('bs.toggle')
|
||||||
|
var options = typeof option == 'object' && option
|
||||||
|
|
||||||
|
if (!data) $this.data('bs.toggle', (data = new Toggle(this, options)))
|
||||||
|
if (typeof option == 'string' && data[option]) data[option]()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var old = $.fn.bootstrapToggle
|
||||||
|
|
||||||
|
$.fn.bootstrapToggle = Plugin
|
||||||
|
$.fn.bootstrapToggle.Constructor = Toggle
|
||||||
|
|
||||||
|
// TOGGLE NO CONFLICT
|
||||||
|
// ==================
|
||||||
|
|
||||||
|
$.fn.toggle.noConflict = function () {
|
||||||
|
$.fn.bootstrapToggle = old
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
// TOGGLE DATA-API
|
||||||
|
// ===============
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
$('input[type=checkbox][data-toggle^=toggle]').bootstrapToggle()
|
||||||
|
})
|
||||||
|
|
||||||
|
$(document).on('click.bs.toggle', 'div[data-toggle^=toggle]', function(e) {
|
||||||
|
var $checkbox = $(this).find('input[type=checkbox]')
|
||||||
|
$checkbox.bootstrapToggle('toggle')
|
||||||
|
e.preventDefault()
|
||||||
|
})
|
||||||
|
|
||||||
|
}(jQuery);
|
|
@ -0,0 +1,9 @@
|
||||||
|
/*! ========================================================================
|
||||||
|
* Bootstrap Toggle: bootstrap-toggle.js v2.2.0
|
||||||
|
* http://www.bootstraptoggle.com
|
||||||
|
* ========================================================================
|
||||||
|
* Copyright 2014 Min Hur, The New York Times Company
|
||||||
|
* Licensed under MIT
|
||||||
|
* ======================================================================== */
|
||||||
|
+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.toggle"),f="object"==typeof b&&b;e||d.data("bs.toggle",e=new c(this,f)),"string"==typeof b&&e[b]&&e[b]()})}var c=function(b,c){this.$element=a(b),this.options=a.extend({},this.defaults(),c),this.render()};c.VERSION="2.2.0",c.DEFAULTS={on:"On",off:"Off",onstyle:"primary",offstyle:"default",size:"normal",style:"",width:null,height:null},c.prototype.defaults=function(){return{on:this.$element.attr("data-on")||c.DEFAULTS.on,off:this.$element.attr("data-off")||c.DEFAULTS.off,onstyle:this.$element.attr("data-onstyle")||c.DEFAULTS.onstyle,offstyle:this.$element.attr("data-offstyle")||c.DEFAULTS.offstyle,size:this.$element.attr("data-size")||c.DEFAULTS.size,style:this.$element.attr("data-style")||c.DEFAULTS.style,width:this.$element.attr("data-width")||c.DEFAULTS.width,height:this.$element.attr("data-height")||c.DEFAULTS.height}},c.prototype.render=function(){this._onstyle="btn-"+this.options.onstyle,this._offstyle="btn-"+this.options.offstyle;var b="large"===this.options.size?"btn-lg":"small"===this.options.size?"btn-sm":"mini"===this.options.size?"btn-xs":"",c=a('<label class="btn">').html(this.options.on).addClass(this._onstyle+" "+b),d=a('<label class="btn">').html(this.options.off).addClass(this._offstyle+" "+b+" active"),e=a('<span class="toggle-handle btn btn-default">').addClass(b),f=a('<div class="toggle-group">').append(c,d,e),g=a('<div class="toggle btn" data-toggle="toggle">').addClass(this.$element.prop("checked")?this._onstyle:this._offstyle+" off").addClass(b).addClass(this.options.style);this.$element.wrap(g),a.extend(this,{$toggle:this.$element.parent(),$toggleOn:c,$toggleOff:d,$toggleGroup:f}),this.$toggle.append(f);var h=this.options.width||Math.max(c.outerWidth(),d.outerWidth())+e.outerWidth()/2,i=this.options.height||Math.max(c.outerHeight(),d.outerHeight());c.addClass("toggle-on"),d.addClass("toggle-off"),this.$toggle.css({width:h,height:i}),this.options.height&&(c.css("line-height",c.height()+"px"),d.css("line-height",d.height()+"px")),this.update(!0),this.trigger(!0)},c.prototype.toggle=function(){this.$element.prop("checked")?this.off():this.on()},c.prototype.on=function(a){return this.$element.prop("disabled")?!1:(this.$toggle.removeClass(this._offstyle+" off").addClass(this._onstyle),this.$element.prop("checked",!0),void(a||this.trigger()))},c.prototype.off=function(a){return this.$element.prop("disabled")?!1:(this.$toggle.removeClass(this._onstyle).addClass(this._offstyle+" off"),this.$element.prop("checked",!1),void(a||this.trigger()))},c.prototype.enable=function(){this.$toggle.removeAttr("disabled"),this.$element.prop("disabled",!1)},c.prototype.disable=function(){this.$toggle.attr("disabled","disabled"),this.$element.prop("disabled",!0)},c.prototype.update=function(a){this.$element.prop("disabled")?this.disable():this.enable(),this.$element.prop("checked")?this.on(a):this.off(a)},c.prototype.trigger=function(b){this.$element.off("change.bs.toggle"),b||this.$element.change(),this.$element.on("change.bs.toggle",a.proxy(function(){this.update()},this))},c.prototype.destroy=function(){this.$element.off("change.bs.toggle"),this.$toggleGroup.remove(),this.$element.removeData("bs.toggle"),this.$element.unwrap()};var d=a.fn.bootstrapToggle;a.fn.bootstrapToggle=b,a.fn.bootstrapToggle.Constructor=c,a.fn.toggle.noConflict=function(){return a.fn.bootstrapToggle=d,this},a(function(){a("input[type=checkbox][data-toggle^=toggle]").bootstrapToggle()}),a(document).on("click.bs.toggle","div[data-toggle^=toggle]",function(b){var c=a(this).find("input[type=checkbox]");c.bootstrapToggle("toggle"),b.preventDefault()})}(jQuery);
|
||||||
|
//# sourceMappingURL=bootstrap-toggle.min.js.map
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"bootstrap-toggle.min.js","sources":["bootstrap-toggle.js"],"names":["$","Plugin","option","this","each","$this","data","options","Toggle","element","$element","extend","defaults","render","VERSION","DEFAULTS","on","off","onstyle","offstyle","size","style","width","height","prototype","attr","_onstyle","_offstyle","$toggleOn","html","addClass","$toggleOff","$toggleHandle","$toggleGroup","append","$toggle","prop","wrap","parent","Math","max","outerWidth","outerHeight","css","update","trigger","toggle","silent","removeClass","enable","removeAttr","disable","change","proxy","destroy","remove","removeData","unwrap","old","fn","bootstrapToggle","Constructor","noConflict","document","e","$checkbox","find","preventDefault","jQuery"],"mappings":";;;;;;;CASE,SAAUA,GACV,YAoID,SAASC,GAAOC,GACf,MAAOC,MAAKC,KAAK,WAChB,GAAIC,GAAUL,EAAEG,MACZG,EAAUD,EAAMC,KAAK,aACrBC,EAA2B,gBAAVL,IAAsBA,CAEtCI,IAAMD,EAAMC,KAAK,YAAcA,EAAO,GAAIE,GAAOL,KAAMI,IACvC,gBAAVL,IAAsBI,EAAKJ,IAASI,EAAKJ,OAtItD,GAAIM,GAAS,SAAUC,EAASF,GAC/BJ,KAAKO,SAAYV,EAAES,GACnBN,KAAKI,QAAYP,EAAEW,UAAWR,KAAKS,WAAYL,GAC/CJ,KAAKU,SAGNL,GAAOM,QAAW,QAElBN,EAAOO,UACNC,GAAI,KACJC,IAAK,MACLC,QAAS,UACTC,SAAU,UACVC,KAAM,SACNC,MAAO,GACPC,MAAO,KACPC,OAAQ,MAGTf,EAAOgB,UAAUZ,SAAW,WAC3B,OACCI,GAAIb,KAAKO,SAASe,KAAK,YAAcjB,EAAOO,SAASC,GACrDC,IAAKd,KAAKO,SAASe,KAAK,aAAejB,EAAOO,SAASE,IACvDC,QAASf,KAAKO,SAASe,KAAK,iBAAmBjB,EAAOO,SAASG,QAC/DC,SAAUhB,KAAKO,SAASe,KAAK,kBAAoBjB,EAAOO,SAASI,SACjEC,KAAMjB,KAAKO,SAASe,KAAK,cAAgBjB,EAAOO,SAASK,KACzDC,MAAOlB,KAAKO,SAASe,KAAK,eAAiBjB,EAAOO,SAASM,MAC3DC,MAAOnB,KAAKO,SAASe,KAAK,eAAiBjB,EAAOO,SAASO,MAC3DC,OAAQpB,KAAKO,SAASe,KAAK,gBAAkBjB,EAAOO,SAASQ,SAI/Df,EAAOgB,UAAUX,OAAS,WACzBV,KAAKuB,SAAW,OAASvB,KAAKI,QAAQW,QACtCf,KAAKwB,UAAY,OAASxB,KAAKI,QAAQY,QACvC,IAAIC,GAA6B,UAAtBjB,KAAKI,QAAQa,KAAmB,SAClB,UAAtBjB,KAAKI,QAAQa,KAAmB,SACV,SAAtBjB,KAAKI,QAAQa,KAAkB,SAC/B,GACCQ,EAAY5B,EAAE,uBAAuB6B,KAAK1B,KAAKI,QAAQS,IACzDc,SAAS3B,KAAKuB,SAAW,IAAMN,GAC7BW,EAAa/B,EAAE,uBAAuB6B,KAAK1B,KAAKI,QAAQU,KAC1Da,SAAS3B,KAAKwB,UAAY,IAAMP,EAAO,WACrCY,EAAgBhC,EAAE,gDACpB8B,SAASV,GACPa,EAAejC,EAAE,8BACnBkC,OAAON,EAAWG,EAAYC,GAC5BG,EAAUnC,EAAE,iDACd8B,SAAU3B,KAAKO,SAAS0B,KAAK,WAAajC,KAAKuB,SAAWvB,KAAKwB,UAAU,QACzEG,SAASV,GAAMU,SAAS3B,KAAKI,QAAQc,MAEvClB,MAAKO,SAAS2B,KAAKF,GACnBnC,EAAEW,OAAOR,MACRgC,QAAShC,KAAKO,SAAS4B,SACvBV,UAAWA,EACXG,WAAYA,EACZE,aAAcA,IAEf9B,KAAKgC,QAAQD,OAAOD,EAEpB,IAAIX,GAAQnB,KAAKI,QAAQe,OAASiB,KAAKC,IAAIZ,EAAUa,aAAcV,EAAWU,cAAeT,EAAcS,aAAa,EACpHlB,EAASpB,KAAKI,QAAQgB,QAAUgB,KAAKC,IAAIZ,EAAUc,cAAeX,EAAWW,cACjFd,GAAUE,SAAS,aACnBC,EAAWD,SAAS,cACpB3B,KAAKgC,QAAQQ,KAAMrB,MAAOA,EAAOC,OAAQA,IACrCpB,KAAKI,QAAQgB,SAChBK,EAAUe,IAAI,cAAef,EAAUL,SAAW,MAClDQ,EAAWY,IAAI,cAAeZ,EAAWR,SAAW,OAErDpB,KAAKyC,QAAO,GACZzC,KAAK0C,SAAQ,IAGdrC,EAAOgB,UAAUsB,OAAS,WACrB3C,KAAKO,SAAS0B,KAAK,WAAYjC,KAAKc,MACnCd,KAAKa,MAGXR,EAAOgB,UAAUR,GAAK,SAAU+B,GAC/B,MAAI5C,MAAKO,SAAS0B,KAAK,aAAoB,GAC3CjC,KAAKgC,QAAQa,YAAY7C,KAAKwB,UAAY,QAAQG,SAAS3B,KAAKuB,UAChEvB,KAAKO,SAAS0B,KAAK,WAAW,QACzBW,GAAQ5C,KAAK0C,aAGnBrC,EAAOgB,UAAUP,IAAM,SAAU8B,GAChC,MAAI5C,MAAKO,SAAS0B,KAAK,aAAoB,GAC3CjC,KAAKgC,QAAQa,YAAY7C,KAAKuB,UAAUI,SAAS3B,KAAKwB,UAAY,QAClExB,KAAKO,SAAS0B,KAAK,WAAW,QACzBW,GAAQ5C,KAAK0C,aAGnBrC,EAAOgB,UAAUyB,OAAS,WACzB9C,KAAKgC,QAAQe,WAAW,YACxB/C,KAAKO,SAAS0B,KAAK,YAAY,IAGhC5B,EAAOgB,UAAU2B,QAAU,WAC1BhD,KAAKgC,QAAQV,KAAK,WAAY,YAC9BtB,KAAKO,SAAS0B,KAAK,YAAY,IAGhC5B,EAAOgB,UAAUoB,OAAS,SAAUG,GAC/B5C,KAAKO,SAAS0B,KAAK,YAAajC,KAAKgD,UACpChD,KAAK8C,SACN9C,KAAKO,SAAS0B,KAAK,WAAYjC,KAAKa,GAAG+B,GACtC5C,KAAKc,IAAI8B,IAGfvC,EAAOgB,UAAUqB,QAAU,SAAUE,GACpC5C,KAAKO,SAASO,IAAI,oBACb8B,GAAQ5C,KAAKO,SAAS0C,SAC3BjD,KAAKO,SAASM,GAAG,mBAAoBhB,EAAEqD,MAAM,WAC5ClD,KAAKyC,UACHzC,QAGJK,EAAOgB,UAAU8B,QAAU,WAC1BnD,KAAKO,SAASO,IAAI,oBAClBd,KAAK8B,aAAasB,SAClBpD,KAAKO,SAAS8C,WAAW,aACzBrD,KAAKO,SAAS+C,SAiBf,IAAIC,GAAM1D,EAAE2D,GAAGC,eAEf5D,GAAE2D,GAAGC,gBAA8B3D,EACnCD,EAAE2D,GAAGC,gBAAgBC,YAAcrD,EAKnCR,EAAE2D,GAAGb,OAAOgB,WAAa,WAExB,MADA9D,GAAE2D,GAAGC,gBAAkBF,EAChBvD,MAMRH,EAAE,WACDA,EAAE,6CAA6C4D,oBAGhD5D,EAAE+D,UAAU/C,GAAG,kBAAmB,2BAA4B,SAASgD,GACtE,GAAIC,GAAYjE,EAAEG,MAAM+D,KAAK,uBAC7BD,GAAUL,gBAAgB,UAC1BI,EAAEG,oBAGFC"}
|
|
@ -0,0 +1,180 @@
|
||||||
|
/*! ========================================================================
|
||||||
|
* Bootstrap Toggle: bootstrap2-toggle.js v2.2.0
|
||||||
|
* http://www.bootstraptoggle.com
|
||||||
|
* ========================================================================
|
||||||
|
* Copyright 2014 Min Hur, The New York Times Company
|
||||||
|
* Licensed under MIT
|
||||||
|
* ======================================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
+function ($) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// TOGGLE PUBLIC CLASS DEFINITION
|
||||||
|
// ==============================
|
||||||
|
|
||||||
|
var Toggle = function (element, options) {
|
||||||
|
this.$element = $(element)
|
||||||
|
this.options = $.extend({}, this.defaults(), options)
|
||||||
|
this.render()
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.VERSION = '2.2.0'
|
||||||
|
|
||||||
|
Toggle.DEFAULTS = {
|
||||||
|
on: 'On',
|
||||||
|
off: 'Off',
|
||||||
|
onstyle: 'primary',
|
||||||
|
offstyle: 'default',
|
||||||
|
size: 'normal',
|
||||||
|
style: '',
|
||||||
|
width: null,
|
||||||
|
height: null
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.defaults = function() {
|
||||||
|
return {
|
||||||
|
on: this.$element.attr('data-on') || Toggle.DEFAULTS.on,
|
||||||
|
off: this.$element.attr('data-off') || Toggle.DEFAULTS.off,
|
||||||
|
onstyle: this.$element.attr('data-onstyle') || Toggle.DEFAULTS.onstyle,
|
||||||
|
offstyle: this.$element.attr('data-offstyle') || Toggle.DEFAULTS.offstyle,
|
||||||
|
size: this.$element.attr('data-size') || Toggle.DEFAULTS.size,
|
||||||
|
style: this.$element.attr('data-style') || Toggle.DEFAULTS.style,
|
||||||
|
width: this.$element.attr('data-width') || Toggle.DEFAULTS.width,
|
||||||
|
height: this.$element.attr('data-height') || Toggle.DEFAULTS.height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.render = function () {
|
||||||
|
this._onstyle = 'btn-' + this.options.onstyle
|
||||||
|
this._offstyle = 'btn-' + this.options.offstyle
|
||||||
|
var size = this.options.size === 'large' ? 'btn-large'
|
||||||
|
: this.options.size === 'small' ? 'btn-small'
|
||||||
|
: this.options.size === 'mini' ? 'btn-mini'
|
||||||
|
: ''
|
||||||
|
var $toggleOn = $('<label class="btn">').html(this.options.on)
|
||||||
|
.addClass(this._onstyle + ' ' + size)
|
||||||
|
var $toggleOff = $('<label class="btn">').html(this.options.off)
|
||||||
|
.addClass(this._offstyle + ' ' + size + ' active')
|
||||||
|
var $toggleHandle = $('<span class="toggle-handle btn btn-default">')
|
||||||
|
.addClass(size)
|
||||||
|
var $toggleGroup = $('<div class="toggle-group">')
|
||||||
|
.append($toggleOn, $toggleOff, $toggleHandle)
|
||||||
|
var $toggle = $('<div class="toggle btn" data-toggle="toggle">')
|
||||||
|
.addClass( this.$element.prop('checked') ? this._onstyle : this._offstyle+' off' )
|
||||||
|
.addClass(size).addClass(this.options.style)
|
||||||
|
|
||||||
|
this.$element.wrap($toggle)
|
||||||
|
$.extend(this, {
|
||||||
|
$toggle: this.$element.parent(),
|
||||||
|
$toggleOn: $toggleOn,
|
||||||
|
$toggleOff: $toggleOff,
|
||||||
|
$toggleGroup: $toggleGroup
|
||||||
|
})
|
||||||
|
this.$toggle.append($toggleGroup)
|
||||||
|
|
||||||
|
var width = this.options.width || Math.max($toggleOn.width(), $toggleOff.width())+($toggleHandle.outerWidth()/2)
|
||||||
|
var height = this.options.height || Math.max($toggleOn.height(), $toggleOff.height())
|
||||||
|
$toggleOn.addClass('toggle-on')
|
||||||
|
$toggleOff.addClass('toggle-off')
|
||||||
|
this.$toggle.css({ width: width, height: height })
|
||||||
|
if (this.options.height) {
|
||||||
|
$toggleOn.css('line-height', $toggleOn.height() + 'px')
|
||||||
|
$toggleOff.css('line-height', $toggleOff.height() + 'px')
|
||||||
|
}
|
||||||
|
this.update(true)
|
||||||
|
this.trigger(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.toggle = function () {
|
||||||
|
if (this.$element.prop('checked')) this.off()
|
||||||
|
else this.on()
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.on = function (silent) {
|
||||||
|
if (this.$element.prop('disabled')) return false
|
||||||
|
this.$toggle.removeClass(this._offstyle + ' off').addClass(this._onstyle)
|
||||||
|
this.$element.prop('checked', true)
|
||||||
|
if (!silent) this.trigger()
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.off = function (silent) {
|
||||||
|
if (this.$element.prop('disabled')) return false
|
||||||
|
this.$toggle.removeClass(this._onstyle).addClass(this._offstyle + ' off')
|
||||||
|
this.$element.prop('checked', false)
|
||||||
|
if (!silent) this.trigger()
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.enable = function () {
|
||||||
|
this.$toggle.removeAttr('disabled')
|
||||||
|
this.$element.prop('disabled', false)
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.disable = function () {
|
||||||
|
this.$toggle.attr('disabled', 'disabled')
|
||||||
|
this.$element.prop('disabled', true)
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.update = function (silent) {
|
||||||
|
if (this.$element.prop('disabled')) this.disable()
|
||||||
|
else this.enable()
|
||||||
|
if (this.$element.prop('checked')) this.on(silent)
|
||||||
|
else this.off(silent)
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.trigger = function (silent) {
|
||||||
|
this.$element.off('change.bs.toggle')
|
||||||
|
if (!silent) this.$element.change()
|
||||||
|
this.$element.on('change.bs.toggle', $.proxy(function() {
|
||||||
|
this.update()
|
||||||
|
}, this))
|
||||||
|
}
|
||||||
|
|
||||||
|
Toggle.prototype.destroy = function() {
|
||||||
|
this.$element.off('change.bs.toggle')
|
||||||
|
this.$toggleGroup.remove()
|
||||||
|
this.$element.removeData('bs.toggle')
|
||||||
|
this.$element.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TOGGLE PLUGIN DEFINITION
|
||||||
|
// ========================
|
||||||
|
|
||||||
|
function Plugin(option) {
|
||||||
|
return this.each(function () {
|
||||||
|
var $this = $(this)
|
||||||
|
var data = $this.data('bs.toggle')
|
||||||
|
var options = typeof option == 'object' && option
|
||||||
|
|
||||||
|
if (!data) $this.data('bs.toggle', (data = new Toggle(this, options)))
|
||||||
|
if (typeof option == 'string' && data[option]) data[option]()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var old = $.fn.bootstrapToggle
|
||||||
|
|
||||||
|
$.fn.bootstrapToggle = Plugin
|
||||||
|
$.fn.bootstrapToggle.Constructor = Toggle
|
||||||
|
|
||||||
|
// TOGGLE NO CONFLICT
|
||||||
|
// ==================
|
||||||
|
|
||||||
|
$.fn.toggle.noConflict = function () {
|
||||||
|
$.fn.bootstrapToggle = old
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
// TOGGLE DATA-API
|
||||||
|
// ===============
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
$('input[type=checkbox][data-toggle^=toggle]').bootstrapToggle()
|
||||||
|
})
|
||||||
|
|
||||||
|
$(document).on('click.bs.toggle', 'div[data-toggle^=toggle]', function(e) {
|
||||||
|
var $checkbox = $(this).find('input[type=checkbox]')
|
||||||
|
$checkbox.bootstrapToggle('toggle')
|
||||||
|
e.preventDefault()
|
||||||
|
})
|
||||||
|
|
||||||
|
}(jQuery);
|
|
@ -0,0 +1,9 @@
|
||||||
|
/*! ========================================================================
|
||||||
|
* Bootstrap Toggle: bootstrap2-toggle.js v2.2.0
|
||||||
|
* http://www.bootstraptoggle.com
|
||||||
|
* ========================================================================
|
||||||
|
* Copyright 2014 Min Hur, The New York Times Company
|
||||||
|
* Licensed under MIT
|
||||||
|
* ======================================================================== */
|
||||||
|
+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.toggle"),f="object"==typeof b&&b;e||d.data("bs.toggle",e=new c(this,f)),"string"==typeof b&&e[b]&&e[b]()})}var c=function(b,c){this.$element=a(b),this.options=a.extend({},this.defaults(),c),this.render()};c.VERSION="2.2.0",c.DEFAULTS={on:"On",off:"Off",onstyle:"primary",offstyle:"default",size:"normal",style:"",width:null,height:null},c.prototype.defaults=function(){return{on:this.$element.attr("data-on")||c.DEFAULTS.on,off:this.$element.attr("data-off")||c.DEFAULTS.off,onstyle:this.$element.attr("data-onstyle")||c.DEFAULTS.onstyle,offstyle:this.$element.attr("data-offstyle")||c.DEFAULTS.offstyle,size:this.$element.attr("data-size")||c.DEFAULTS.size,style:this.$element.attr("data-style")||c.DEFAULTS.style,width:this.$element.attr("data-width")||c.DEFAULTS.width,height:this.$element.attr("data-height")||c.DEFAULTS.height}},c.prototype.render=function(){this._onstyle="btn-"+this.options.onstyle,this._offstyle="btn-"+this.options.offstyle;var b="large"===this.options.size?"btn-large":"small"===this.options.size?"btn-small":"mini"===this.options.size?"btn-mini":"",c=a('<label class="btn">').html(this.options.on).addClass(this._onstyle+" "+b),d=a('<label class="btn">').html(this.options.off).addClass(this._offstyle+" "+b+" active"),e=a('<span class="toggle-handle btn btn-default">').addClass(b),f=a('<div class="toggle-group">').append(c,d,e),g=a('<div class="toggle btn" data-toggle="toggle">').addClass(this.$element.prop("checked")?this._onstyle:this._offstyle+" off").addClass(b).addClass(this.options.style);this.$element.wrap(g),a.extend(this,{$toggle:this.$element.parent(),$toggleOn:c,$toggleOff:d,$toggleGroup:f}),this.$toggle.append(f);var h=this.options.width||Math.max(c.width(),d.width())+e.outerWidth()/2,i=this.options.height||Math.max(c.height(),d.height());c.addClass("toggle-on"),d.addClass("toggle-off"),this.$toggle.css({width:h,height:i}),this.options.height&&(c.css("line-height",c.height()+"px"),d.css("line-height",d.height()+"px")),this.update(!0),this.trigger(!0)},c.prototype.toggle=function(){this.$element.prop("checked")?this.off():this.on()},c.prototype.on=function(a){return this.$element.prop("disabled")?!1:(this.$toggle.removeClass(this._offstyle+" off").addClass(this._onstyle),this.$element.prop("checked",!0),void(a||this.trigger()))},c.prototype.off=function(a){return this.$element.prop("disabled")?!1:(this.$toggle.removeClass(this._onstyle).addClass(this._offstyle+" off"),this.$element.prop("checked",!1),void(a||this.trigger()))},c.prototype.enable=function(){this.$toggle.removeAttr("disabled"),this.$element.prop("disabled",!1)},c.prototype.disable=function(){this.$toggle.attr("disabled","disabled"),this.$element.prop("disabled",!0)},c.prototype.update=function(a){this.$element.prop("disabled")?this.disable():this.enable(),this.$element.prop("checked")?this.on(a):this.off(a)},c.prototype.trigger=function(b){this.$element.off("change.bs.toggle"),b||this.$element.change(),this.$element.on("change.bs.toggle",a.proxy(function(){this.update()},this))},c.prototype.destroy=function(){this.$element.off("change.bs.toggle"),this.$toggleGroup.remove(),this.$element.removeData("bs.toggle"),this.$element.unwrap()};var d=a.fn.bootstrapToggle;a.fn.bootstrapToggle=b,a.fn.bootstrapToggle.Constructor=c,a.fn.toggle.noConflict=function(){return a.fn.bootstrapToggle=d,this},a(function(){a("input[type=checkbox][data-toggle^=toggle]").bootstrapToggle()}),a(document).on("click.bs.toggle","div[data-toggle^=toggle]",function(b){var c=a(this).find("input[type=checkbox]");c.bootstrapToggle("toggle"),b.preventDefault()})}(jQuery);
|
||||||
|
//# sourceMappingURL=bootstrap2-toggle.min.js.map
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"bootstrap2-toggle.min.js","sources":["bootstrap2-toggle.js"],"names":["$","Plugin","option","this","each","$this","data","options","Toggle","element","$element","extend","defaults","render","VERSION","DEFAULTS","on","off","onstyle","offstyle","size","style","width","height","prototype","attr","_onstyle","_offstyle","$toggleOn","html","addClass","$toggleOff","$toggleHandle","$toggleGroup","append","$toggle","prop","wrap","parent","Math","max","outerWidth","css","update","trigger","toggle","silent","removeClass","enable","removeAttr","disable","change","proxy","destroy","remove","removeData","unwrap","old","fn","bootstrapToggle","Constructor","noConflict","document","e","$checkbox","find","preventDefault","jQuery"],"mappings":";;;;;;;CASE,SAAUA,GACV,YAoID,SAASC,GAAOC,GACf,MAAOC,MAAKC,KAAK,WAChB,GAAIC,GAAUL,EAAEG,MACZG,EAAUD,EAAMC,KAAK,aACrBC,EAA2B,gBAAVL,IAAsBA,CAEtCI,IAAMD,EAAMC,KAAK,YAAcA,EAAO,GAAIE,GAAOL,KAAMI,IACvC,gBAAVL,IAAsBI,EAAKJ,IAASI,EAAKJ,OAtItD,GAAIM,GAAS,SAAUC,EAASF,GAC/BJ,KAAKO,SAAYV,EAAES,GACnBN,KAAKI,QAAYP,EAAEW,UAAWR,KAAKS,WAAYL,GAC/CJ,KAAKU,SAGNL,GAAOM,QAAW,QAElBN,EAAOO,UACNC,GAAI,KACJC,IAAK,MACLC,QAAS,UACTC,SAAU,UACVC,KAAM,SACNC,MAAO,GACPC,MAAO,KACPC,OAAQ,MAGTf,EAAOgB,UAAUZ,SAAW,WAC3B,OACCI,GAAIb,KAAKO,SAASe,KAAK,YAAcjB,EAAOO,SAASC,GACrDC,IAAKd,KAAKO,SAASe,KAAK,aAAejB,EAAOO,SAASE,IACvDC,QAASf,KAAKO,SAASe,KAAK,iBAAmBjB,EAAOO,SAASG,QAC/DC,SAAUhB,KAAKO,SAASe,KAAK,kBAAoBjB,EAAOO,SAASI,SACjEC,KAAMjB,KAAKO,SAASe,KAAK,cAAgBjB,EAAOO,SAASK,KACzDC,MAAOlB,KAAKO,SAASe,KAAK,eAAiBjB,EAAOO,SAASM,MAC3DC,MAAOnB,KAAKO,SAASe,KAAK,eAAiBjB,EAAOO,SAASO,MAC3DC,OAAQpB,KAAKO,SAASe,KAAK,gBAAkBjB,EAAOO,SAASQ,SAI/Df,EAAOgB,UAAUX,OAAS,WACzBV,KAAKuB,SAAW,OAASvB,KAAKI,QAAQW,QACtCf,KAAKwB,UAAY,OAASxB,KAAKI,QAAQY,QACvC,IAAIC,GAA6B,UAAtBjB,KAAKI,QAAQa,KAAmB,YAClB,UAAtBjB,KAAKI,QAAQa,KAAmB,YACV,SAAtBjB,KAAKI,QAAQa,KAAkB,WAC/B,GACCQ,EAAY5B,EAAE,uBAAuB6B,KAAK1B,KAAKI,QAAQS,IACzDc,SAAS3B,KAAKuB,SAAW,IAAMN,GAC7BW,EAAa/B,EAAE,uBAAuB6B,KAAK1B,KAAKI,QAAQU,KAC1Da,SAAS3B,KAAKwB,UAAY,IAAMP,EAAO,WACrCY,EAAgBhC,EAAE,gDACpB8B,SAASV,GACPa,EAAejC,EAAE,8BACnBkC,OAAON,EAAWG,EAAYC,GAC5BG,EAAUnC,EAAE,iDACd8B,SAAU3B,KAAKO,SAAS0B,KAAK,WAAajC,KAAKuB,SAAWvB,KAAKwB,UAAU,QACzEG,SAASV,GAAMU,SAAS3B,KAAKI,QAAQc,MAEvClB,MAAKO,SAAS2B,KAAKF,GACnBnC,EAAEW,OAAOR,MACRgC,QAAShC,KAAKO,SAAS4B,SACvBV,UAAWA,EACXG,WAAYA,EACZE,aAAcA,IAEf9B,KAAKgC,QAAQD,OAAOD,EAEpB,IAAIX,GAAQnB,KAAKI,QAAQe,OAASiB,KAAKC,IAAIZ,EAAUN,QAASS,EAAWT,SAAUU,EAAcS,aAAa,EAC1GlB,EAASpB,KAAKI,QAAQgB,QAAUgB,KAAKC,IAAIZ,EAAUL,SAAUQ,EAAWR,SAC5EK,GAAUE,SAAS,aACnBC,EAAWD,SAAS,cACpB3B,KAAKgC,QAAQO,KAAMpB,MAAOA,EAAOC,OAAQA,IACrCpB,KAAKI,QAAQgB,SAChBK,EAAUc,IAAI,cAAed,EAAUL,SAAW,MAClDQ,EAAWW,IAAI,cAAeX,EAAWR,SAAW,OAErDpB,KAAKwC,QAAO,GACZxC,KAAKyC,SAAQ,IAGdpC,EAAOgB,UAAUqB,OAAS,WACrB1C,KAAKO,SAAS0B,KAAK,WAAYjC,KAAKc,MACnCd,KAAKa,MAGXR,EAAOgB,UAAUR,GAAK,SAAU8B,GAC/B,MAAI3C,MAAKO,SAAS0B,KAAK,aAAoB,GAC3CjC,KAAKgC,QAAQY,YAAY5C,KAAKwB,UAAY,QAAQG,SAAS3B,KAAKuB,UAChEvB,KAAKO,SAAS0B,KAAK,WAAW,QACzBU,GAAQ3C,KAAKyC,aAGnBpC,EAAOgB,UAAUP,IAAM,SAAU6B,GAChC,MAAI3C,MAAKO,SAAS0B,KAAK,aAAoB,GAC3CjC,KAAKgC,QAAQY,YAAY5C,KAAKuB,UAAUI,SAAS3B,KAAKwB,UAAY,QAClExB,KAAKO,SAAS0B,KAAK,WAAW,QACzBU,GAAQ3C,KAAKyC,aAGnBpC,EAAOgB,UAAUwB,OAAS,WACzB7C,KAAKgC,QAAQc,WAAW,YACxB9C,KAAKO,SAAS0B,KAAK,YAAY,IAGhC5B,EAAOgB,UAAU0B,QAAU,WAC1B/C,KAAKgC,QAAQV,KAAK,WAAY,YAC9BtB,KAAKO,SAAS0B,KAAK,YAAY,IAGhC5B,EAAOgB,UAAUmB,OAAS,SAAUG,GAC/B3C,KAAKO,SAAS0B,KAAK,YAAajC,KAAK+C,UACpC/C,KAAK6C,SACN7C,KAAKO,SAAS0B,KAAK,WAAYjC,KAAKa,GAAG8B,GACtC3C,KAAKc,IAAI6B,IAGftC,EAAOgB,UAAUoB,QAAU,SAAUE,GACpC3C,KAAKO,SAASO,IAAI,oBACb6B,GAAQ3C,KAAKO,SAASyC,SAC3BhD,KAAKO,SAASM,GAAG,mBAAoBhB,EAAEoD,MAAM,WAC5CjD,KAAKwC,UACHxC,QAGJK,EAAOgB,UAAU6B,QAAU,WAC1BlD,KAAKO,SAASO,IAAI,oBAClBd,KAAK8B,aAAaqB,SAClBnD,KAAKO,SAAS6C,WAAW,aACzBpD,KAAKO,SAAS8C,SAiBf,IAAIC,GAAMzD,EAAE0D,GAAGC,eAEf3D,GAAE0D,GAAGC,gBAA8B1D,EACnCD,EAAE0D,GAAGC,gBAAgBC,YAAcpD,EAKnCR,EAAE0D,GAAGb,OAAOgB,WAAa,WAExB,MADA7D,GAAE0D,GAAGC,gBAAkBF,EAChBtD,MAMRH,EAAE,WACDA,EAAE,6CAA6C2D,oBAGhD3D,EAAE8D,UAAU9C,GAAG,kBAAmB,2BAA4B,SAAS+C,GACtE,GAAIC,GAAYhE,EAAEG,MAAM8D,KAAK,uBAC7BD,GAAUL,gBAAgB,UAC1BI,EAAEG,oBAGFC"}
|
|
@ -8,6 +8,7 @@
|
||||||
@import "jquery.mloading";
|
@import "jquery.mloading";
|
||||||
@import "jquery-confirm.min";
|
@import "jquery-confirm.min";
|
||||||
@import "bootstrap-datetimepicker.min";
|
@import "bootstrap-datetimepicker.min";
|
||||||
|
@import "bootstrap/bootstrap-toggle.min";
|
||||||
|
|
||||||
@import "codemirror/lib/codemirror";
|
@import "codemirror/lib/codemirror";
|
||||||
@import "editormd/css/editormd.min";
|
@import "editormd/css/editormd.min";
|
||||||
|
@ -203,4 +204,14 @@ input.form-control {
|
||||||
color: #23272B;
|
color: #23272B;
|
||||||
font-size: 1rem;
|
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;
|
||||||
}
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*! ========================================================================
|
||||||
|
* Bootstrap Toggle: bootstrap-toggle.css v2.2.0
|
||||||
|
* http://www.bootstraptoggle.com
|
||||||
|
* ========================================================================
|
||||||
|
* Copyright 2014 Min Hur, The New York Times Company
|
||||||
|
* Licensed under MIT
|
||||||
|
* ======================================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
.checkbox label .toggle,
|
||||||
|
.checkbox-inline .toggle {
|
||||||
|
margin-left: -20px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.toggle input[type="checkbox"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.toggle-group {
|
||||||
|
position: absolute;
|
||||||
|
width: 200%;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
transition: left 0.35s;
|
||||||
|
-webkit-transition: left 0.35s;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
}
|
||||||
|
.toggle.off .toggle-group {
|
||||||
|
left: -100%;
|
||||||
|
}
|
||||||
|
.toggle-on {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 50%;
|
||||||
|
margin: 0;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
.toggle-off {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
right: 0;
|
||||||
|
margin: 0;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
.toggle-handle {
|
||||||
|
position: relative;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding-top: 0px;
|
||||||
|
padding-bottom: 0px;
|
||||||
|
height: 100%;
|
||||||
|
width: 0px;
|
||||||
|
border-width: 0 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle.btn { min-width: 59px; min-height: 34px; }
|
||||||
|
.toggle-on.btn { padding-right: 24px; }
|
||||||
|
.toggle-off.btn { padding-left: 24px; }
|
||||||
|
|
||||||
|
.toggle.btn-lg { min-width: 79px; min-height: 45px; }
|
||||||
|
.toggle-on.btn-lg { padding-right: 31px; }
|
||||||
|
.toggle-off.btn-lg { padding-left: 31px; }
|
||||||
|
.toggle-handle.btn-lg { width: 40px; }
|
||||||
|
|
||||||
|
.toggle.btn-sm { min-width: 50px; min-height: 30px;}
|
||||||
|
.toggle-on.btn-sm { padding-right: 20px; }
|
||||||
|
.toggle-off.btn-sm { padding-left: 20px; }
|
||||||
|
|
||||||
|
.toggle.btn-xs { min-width: 35px; min-height: 22px;}
|
||||||
|
.toggle-on.btn-xs { padding-right: 12px; }
|
||||||
|
.toggle-off.btn-xs { padding-left: 12px; }
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*! ========================================================================
|
||||||
|
* Bootstrap Toggle: bootstrap-toggle.css v2.2.0
|
||||||
|
* http://www.bootstraptoggle.com
|
||||||
|
* ========================================================================
|
||||||
|
* Copyright 2014 Min Hur, The New York Times Company
|
||||||
|
* Licensed under MIT
|
||||||
|
* ======================================================================== */
|
||||||
|
.checkbox label .toggle,.checkbox-inline .toggle{margin-left:-20px;margin-right:5px}
|
||||||
|
.toggle{position:relative;overflow:hidden}
|
||||||
|
.toggle input[type=checkbox]{display:none}
|
||||||
|
.toggle-group{position:absolute;width:200%;top:0;bottom:0;left:0;transition:left .35s;-webkit-transition:left .35s;-moz-user-select:none;-webkit-user-select:none}
|
||||||
|
.toggle.off .toggle-group{left:-100%}
|
||||||
|
.toggle-on{position:absolute;top:0;bottom:0;left:0;right:50%;margin:0;border:0;border-radius:0}
|
||||||
|
.toggle-off{position:absolute;top:0;bottom:0;left:50%;right:0;margin:0;border:0;border-radius:0}
|
||||||
|
.toggle-handle{position:relative;margin:0 auto;padding-top:0;padding-bottom:0;height:100%;width:0;border-width:0 1px}
|
||||||
|
.toggle.btn{min-width:59px;min-height:34px}
|
||||||
|
.toggle-on.btn{padding-right:24px}
|
||||||
|
.toggle-off.btn{padding-left:24px}
|
||||||
|
.toggle.btn-lg{min-width:79px;min-height:45px}
|
||||||
|
.toggle-on.btn-lg{padding-right:31px}
|
||||||
|
.toggle-off.btn-lg{padding-left:31px}
|
||||||
|
.toggle-handle.btn-lg{width:40px}
|
||||||
|
.toggle.btn-sm{min-width:50px;min-height:30px}
|
||||||
|
.toggle-on.btn-sm{padding-right:20px}
|
||||||
|
.toggle-off.btn-sm{padding-left:20px}
|
||||||
|
.toggle.btn-xs{min-width:35px;min-height:22px}
|
||||||
|
.toggle-on.btn-xs{padding-right:12px}
|
||||||
|
.toggle-off.btn-xs{padding-left:12px}
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*! ========================================================================
|
||||||
|
* Bootstrap Toggle: bootstrap2-toggle.css v2.2.0
|
||||||
|
* http://www.bootstraptoggle.com
|
||||||
|
* ========================================================================
|
||||||
|
* Copyright 2014 Min Hur, The New York Times Company
|
||||||
|
* Licensed under MIT
|
||||||
|
* ======================================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
label.checkbox .toggle,
|
||||||
|
label.checkbox.inline .toggle {
|
||||||
|
margin-left: -20px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
.toggle {
|
||||||
|
min-width: 40px;
|
||||||
|
height: 20px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.toggle input[type="checkbox"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.toggle-group {
|
||||||
|
position: absolute;
|
||||||
|
width: 200%;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
transition: left 0.35s;
|
||||||
|
-webkit-transition: left 0.35s;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
}
|
||||||
|
.toggle.off .toggle-group {
|
||||||
|
left: -100%;
|
||||||
|
}
|
||||||
|
.toggle-on {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 50%;
|
||||||
|
margin: 0;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
.toggle-off {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
right: 0;
|
||||||
|
margin: 0;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
.toggle-handle {
|
||||||
|
position: relative;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding-top: 0px;
|
||||||
|
padding-bottom: 0px;
|
||||||
|
height: 100%;
|
||||||
|
width: 0px;
|
||||||
|
border-width: 0 1px;
|
||||||
|
}
|
||||||
|
.toggle-handle.btn-mini {
|
||||||
|
top: -1px;
|
||||||
|
}
|
||||||
|
.toggle.btn { min-width: 30px; }
|
||||||
|
.toggle-on.btn { padding-right: 24px; }
|
||||||
|
.toggle-off.btn { padding-left: 24px; }
|
||||||
|
|
||||||
|
.toggle.btn-large { min-width: 40px; }
|
||||||
|
.toggle-on.btn-large { padding-right: 35px; }
|
||||||
|
.toggle-off.btn-large { padding-left: 35px; }
|
||||||
|
|
||||||
|
.toggle.btn-small { min-width: 25px; }
|
||||||
|
.toggle-on.btn-small { padding-right: 20px; }
|
||||||
|
.toggle-off.btn-small { padding-left: 20px; }
|
||||||
|
|
||||||
|
.toggle.btn-mini { min-width: 20px; }
|
||||||
|
.toggle-on.btn-mini { padding-right: 12px; }
|
||||||
|
.toggle-off.btn-mini { padding-left: 12px; }
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*! ========================================================================
|
||||||
|
* Bootstrap Toggle: bootstrap2-toggle.css v2.2.0
|
||||||
|
* http://www.bootstraptoggle.com
|
||||||
|
* ========================================================================
|
||||||
|
* Copyright 2014 Min Hur, The New York Times Company
|
||||||
|
* Licensed under MIT
|
||||||
|
* ======================================================================== */
|
||||||
|
label.checkbox .toggle,label.checkbox.inline .toggle{margin-left:-20px;margin-right:5px}
|
||||||
|
.toggle{min-width:40px;height:20px;position:relative;overflow:hidden}
|
||||||
|
.toggle input[type=checkbox]{display:none}
|
||||||
|
.toggle-group{position:absolute;width:200%;top:0;bottom:0;left:0;transition:left .35s;-webkit-transition:left .35s;-moz-user-select:none;-webkit-user-select:none}
|
||||||
|
.toggle.off .toggle-group{left:-100%}
|
||||||
|
.toggle-on{position:absolute;top:0;bottom:0;left:0;right:50%;margin:0;border:0;border-radius:0}
|
||||||
|
.toggle-off{position:absolute;top:0;bottom:0;left:50%;right:0;margin:0;border:0;border-radius:0}
|
||||||
|
.toggle-handle{position:relative;margin:0 auto;padding-top:0;padding-bottom:0;height:100%;width:0;border-width:0 1px}
|
||||||
|
.toggle-handle.btn-mini{top:-1px}
|
||||||
|
.toggle.btn{min-width:30px}
|
||||||
|
.toggle-on.btn{padding-right:24px}
|
||||||
|
.toggle-off.btn{padding-left:24px}
|
||||||
|
.toggle.btn-large{min-width:40px}
|
||||||
|
.toggle-on.btn-large{padding-right:35px}
|
||||||
|
.toggle-off.btn-large{padding-left:35px}
|
||||||
|
.toggle.btn-small{min-width:25px}
|
||||||
|
.toggle-on.btn-small{padding-right:20px}
|
||||||
|
.toggle-off.btn-small{padding-left:20px}
|
||||||
|
.toggle.btn-mini{min-width:20px}
|
||||||
|
.toggle-on.btn-mini{padding-right:12px}
|
||||||
|
.toggle-off.btn-mini{padding-left:12px}
|
|
@ -111,7 +111,9 @@ class AccountsController < ApplicationController
|
||||||
|
|
||||||
sync_params = {
|
sync_params = {
|
||||||
password: params[:password].to_s,
|
password: params[:password].to_s,
|
||||||
email: @user.mail
|
email: @user.mail,
|
||||||
|
login_name: @user.login,
|
||||||
|
source_id: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params)
|
interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params)
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
class Admins::DashboardsController < Admins::BaseController
|
class Admins::DashboardsController < Admins::BaseController
|
||||||
def index
|
def index
|
||||||
# 用户活跃数
|
# 用户活跃数
|
||||||
day_user_ids = CommitLog.where(created_at: today).pluck(:project_id).uniq
|
day_user_ids = CommitLog.where(created_at: today).pluck(:user_id).uniq
|
||||||
weekly_user_ids = CommitLog.where(created_at: current_week).pluck(:project_id).uniq
|
weekly_user_ids = CommitLog.where(created_at: current_week).pluck(:user_id).uniq
|
||||||
month_user_ids = CommitLog.where(created_at: current_month).pluck(:project_id).uniq
|
month_user_ids = CommitLog.where(created_at: current_month).pluck(:user_id).uniq
|
||||||
@active_user_count = User.where(last_login_on: today).or(User.where(id: day_user_ids)).count
|
@active_user_count = User.where(last_login_on: today).or(User.where(id: day_user_ids)).count
|
||||||
@weekly_active_user_count = User.where(last_login_on: current_week).or(User.where(id: weekly_user_ids)).count
|
@weekly_active_user_count = User.where(last_login_on: current_week).or(User.where(id: weekly_user_ids)).count
|
||||||
@month_active_user_count = User.where(last_login_on: current_month).or(User.where(id: month_user_ids)).count
|
@month_active_user_count = User.where(last_login_on: current_month).or(User.where(id: month_user_ids)).count
|
||||||
|
|
|
@ -7,12 +7,12 @@ class Admins::MessageTemplatesController < Admins::BaseController
|
||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@message_template = MessageTemplate::CustomTip.new
|
@message_template = MessageTemplate.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@message_template = MessageTemplate::CustomTip.new(ignore_params)
|
@message_template = MessageTemplate::CustomTip.new(message_template_params)
|
||||||
|
@message_template.type = "MessageTemplate::CustomTip"
|
||||||
if @message_template.save!
|
if @message_template.save!
|
||||||
redirect_to admins_message_templates_path
|
redirect_to admins_message_templates_path
|
||||||
flash[:success] = "创建消息模板成功"
|
flash[:success] = "创建消息模板成功"
|
||||||
|
@ -47,7 +47,9 @@ class Admins::MessageTemplatesController < Admins::BaseController
|
||||||
|
|
||||||
private
|
private
|
||||||
def message_template_params
|
def message_template_params
|
||||||
params.require(@message_template.type.split("::").join("_").underscore.to_sym).permit!
|
# type = @message_template.present? ? @message_template.type : "MessageTemplate::CustomTip"
|
||||||
|
# params.require(type.split("::").join("_").underscore.to_sym).permit!
|
||||||
|
params.require(:message_template).permit!
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_template
|
def get_template
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
class Admins::NpsController < Admins::BaseController
|
||||||
|
def index
|
||||||
|
@on_off_switch = EduSetting.get("nps-on-off-switch").to_s == 'true'
|
||||||
|
@user_nps = UserNp.joins(:user).order(created_at: :desc)
|
||||||
|
keyword = params[:keyword].to_s.strip.presence
|
||||||
|
if keyword
|
||||||
|
sql = 'CONCAT(users.lastname, users.firstname) LIKE :keyword OR users.nickname LIKE :keyword OR users.login LIKE :keyword OR users.mail LIKE :keyword OR users.phone LIKE :keyword'
|
||||||
|
@user_nps = @user_nps.where(sql, keyword: "%#{keyword}%")
|
||||||
|
end
|
||||||
|
@user_nps = @user_nps.where("action_type != 'close'") if params[:done_score].present?
|
||||||
|
@min_score = @user_nps.where("action_type != 'close'").minimum("score")
|
||||||
|
@max_score = @user_nps.where("action_type != 'close'").maximum("score")
|
||||||
|
@score_total_count = UserNp.where("action_type !='close'").count
|
||||||
|
@user_nps = paginate @user_nps.includes(:user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def switch_change
|
||||||
|
edu_setting = EduSetting.find_by(name: "nps-on-off-switch")
|
||||||
|
if edu_setting.blank?
|
||||||
|
edu_setting = EduSetting.new(name: "nps-on-off-switch")
|
||||||
|
end
|
||||||
|
edu_setting.value = params[:switch].to_s
|
||||||
|
edu_setting.save
|
||||||
|
render_ok
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,6 +1,6 @@
|
||||||
class Admins::ProjectIgnoresController < Admins::BaseController
|
class Admins::ProjectIgnoresController < Admins::BaseController
|
||||||
before_action :set_ignore, only: [:edit,:update, :destroy,:show]
|
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
|
def index
|
||||||
sort_by = Ignore.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at'
|
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)
|
@project_ignore = Ignore.new(ignore_params)
|
||||||
|
|
||||||
if @project_ignore.save!
|
if @project_ignore.save
|
||||||
redirect_to admins_project_ignores_path
|
redirect_to admins_project_ignores_path
|
||||||
flash[:success] = "创建成功"
|
flash[:success] = "创建成功"
|
||||||
else
|
else
|
||||||
render :new
|
redirect_to admins_project_ignores_path
|
||||||
flash[:danger] = "创建失败"
|
flash[:danger] = @project_ignore.errors.full_messages.join(",")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -58,8 +58,8 @@ class Admins::ProjectIgnoresController < Admins::BaseController
|
||||||
redirect_to admins_project_ignores_path
|
redirect_to admins_project_ignores_path
|
||||||
flash[:success] = "更新成功"
|
flash[:success] = "更新成功"
|
||||||
else
|
else
|
||||||
render :edit
|
redirect_to admins_project_ignores_path
|
||||||
flash[:danger] = "更新失败"
|
flash[:danger] = @project_ignore.errors.full_messages.join(",")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -98,23 +98,23 @@ class Admins::ProjectIgnoresController < Admins::BaseController
|
||||||
params.require(:ignore).permit(:name,:content)
|
params.require(:ignore).permit(:name,:content)
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_params
|
# def validate_params
|
||||||
name = params[:ignore][:name]
|
# name = params[:ignore][:name]
|
||||||
if name.blank?
|
# if name.blank?
|
||||||
flash[:danger] = "名称不允许为空"
|
# flash[:danger] = "名称不允许为空"
|
||||||
redirect_to admins_project_ignores_path
|
# redirect_to admins_project_ignores_path
|
||||||
elsif check_ignore_present?(name) && @project_ignore.blank?
|
# elsif check_ignore_present?(name) && @project_ignore.blank?
|
||||||
flash[:danger] = "创建失败:名称已存在"
|
# flash[:danger] = "创建失败:名称已存在"
|
||||||
redirect_to admins_project_ignores_path
|
# redirect_to admins_project_ignores_path
|
||||||
end
|
# end
|
||||||
end
|
# end
|
||||||
|
|
||||||
def check_ignore_present?(name)
|
# def check_ignore_present?(name)
|
||||||
return true if name.blank?
|
# return true if name.blank?
|
||||||
name_downcase = name.downcase
|
# name_downcase = name.downcase
|
||||||
name_upcase = name.upcase
|
# name_upcase = name.upcase
|
||||||
name_first_big = name.capitalize
|
# name_first_big = name.capitalize
|
||||||
Ignore.exists?(name: name_downcase) || Ignore.exists?(name: name_upcase) || Ignore.exists?(name: name_first_big)
|
# Ignore.exists?(name: name_downcase) || Ignore.exists?(name: name_upcase) || Ignore.exists?(name: name_first_big)
|
||||||
end
|
# end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,17 +27,18 @@ class Admins::ProjectLanguagesController < Admins::BaseController
|
||||||
flash[:success] = '创建成功'
|
flash[:success] = '创建成功'
|
||||||
else
|
else
|
||||||
redirect_to admins_project_languages_path
|
redirect_to admins_project_languages_path
|
||||||
flash[:danger] = '创建失败'
|
flash[:danger] = @project_language.errors.full_messages.join(",")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
if @project_language.update_attribute(:name, @name)
|
@project_language.attributes = {name: @name}
|
||||||
|
if @project_language.save
|
||||||
redirect_to admins_project_languages_path
|
redirect_to admins_project_languages_path
|
||||||
flash[:success] = '更新成功'
|
flash[:success] = '更新成功'
|
||||||
else
|
else
|
||||||
redirect_to admins_project_languages_path
|
redirect_to admins_project_languages_path
|
||||||
flash[:success] = '更新失败'
|
flash[:danger] = @project_language.errors.full_messages.join(",")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
class Admins::ProjectLicensesController < Admins::BaseController
|
class Admins::ProjectLicensesController < Admins::BaseController
|
||||||
before_action :set_license, only: [:edit,:update, :destroy,:show]
|
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
|
def index
|
||||||
sort_by = License.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at'
|
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
|
# position: max_position
|
||||||
# }
|
# }
|
||||||
@project_license = License.new(license_params)
|
@project_license = License.new(license_params)
|
||||||
|
if @project_license.save
|
||||||
if @project_license.save!
|
|
||||||
redirect_to admins_project_licenses_path
|
redirect_to admins_project_licenses_path
|
||||||
flash[:success] = "创建成功"
|
flash[:success] = "创建成功"
|
||||||
else
|
else
|
||||||
render :new
|
redirect_to admins_project_licenses_path
|
||||||
flash[:danger] = "创建失败"
|
flash[:danger] = @project_license.errors.full_messages.join(",")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -54,12 +53,13 @@ class Admins::ProjectLicensesController < Admins::BaseController
|
||||||
# permissions: permissions.to_s,
|
# permissions: permissions.to_s,
|
||||||
# limitations: limitations.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
|
redirect_to admins_project_licenses_path
|
||||||
flash[:success] = "更新成功"
|
flash[:success] = "更新成功"
|
||||||
else
|
else
|
||||||
render :edit
|
render admins_project_licenses_path
|
||||||
flash[:danger] = "更新失败"
|
flash[:danger] = @project_license.errors.full_messages.join(",")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -98,23 +98,23 @@ class Admins::ProjectLicensesController < Admins::BaseController
|
||||||
params.require(:license).permit(:name,:content)
|
params.require(:license).permit(:name,:content)
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_params
|
# def validate_params
|
||||||
name = params[:license][:name]
|
# name = params[:license][:name]
|
||||||
if name.blank?
|
# if name.blank?
|
||||||
flash[:danger] = "名称不允许为空"
|
# flash[:danger] = "名称不允许为空"
|
||||||
redirect_to admins_project_licenses_path
|
# redirect_to admins_project_licenses_path
|
||||||
elsif check_license_present?(name) && @project_license.blank?
|
# elsif check_license_present?(name) && @project_license.blank?
|
||||||
flash[:danger] = "创建失败:名称已存在"
|
# flash[:danger] = "创建失败:名称已存在"
|
||||||
redirect_to admins_project_licenses_path
|
# redirect_to admins_project_licenses_path
|
||||||
end
|
# end
|
||||||
end
|
# end
|
||||||
|
|
||||||
def check_license_present?(name)
|
# def check_license_present?(name)
|
||||||
return true if name.blank?
|
# return true if name.blank?
|
||||||
name_downcase = name.downcase
|
# name_downcase = name.downcase
|
||||||
name_upcase = name.upcase
|
# name_upcase = name.upcase
|
||||||
name_first_big = name.capitalize
|
# name_first_big = name.capitalize
|
||||||
License.exists?(name: name_downcase) || License.exists?(name: name_upcase) || License.exists?(name: name_first_big)
|
# License.exists?(name: name_downcase) || License.exists?(name: name_upcase) || License.exists?(name: name_first_big)
|
||||||
end
|
# end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
class Admins::Topic::BannersController < Admins::Topic::BaseController
|
class Admins::Topic::BannersController < Admins::Topic::BaseController
|
||||||
before_action :find_banner, only: [:edit, :update, :destroy]
|
before_action :find_banner, only: [:edit, :update, :destroy]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@banners = paginate(::Topic::Banner)
|
@banners = paginate(::Topic::Banner)
|
||||||
|
@banners = paginate(::Topic::Banner.where("title like ?", "%#{params[:search]}%")) if params[:search].present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
|
|
|
@ -2,6 +2,7 @@ class Api::V1::BaseController < ApplicationController
|
||||||
|
|
||||||
include Api::ProjectHelper
|
include Api::ProjectHelper
|
||||||
include Api::UserHelper
|
include Api::UserHelper
|
||||||
|
include Api::PullHelper
|
||||||
|
|
||||||
# before_action :doorkeeper_authorize!
|
# before_action :doorkeeper_authorize!
|
||||||
# skip_before_action :user_setup
|
# skip_before_action :user_setup
|
||||||
|
@ -30,18 +31,25 @@ class Api::V1::BaseController < ApplicationController
|
||||||
# 具有对仓库的管理权限
|
# 具有对仓库的管理权限
|
||||||
def require_manager_above
|
def require_manager_above
|
||||||
@project = load_project
|
@project = load_project
|
||||||
return render_forbidden unless current_user.admin? && @project.manager?(current_user)
|
return render_forbidden if !current_user.admin? && !@project.manager?(current_user)
|
||||||
end
|
end
|
||||||
|
|
||||||
# 具有对仓库的操作权限
|
# 具有对仓库的操作权限
|
||||||
def require_operate_above
|
def require_operate_above
|
||||||
@project = load_project
|
@project = load_project
|
||||||
return render_forbidden unless current_user.admin? && @project.operator?(current_user)
|
return render_forbidden if !current_user.admin? && !@project.operator?(current_user)
|
||||||
|
end
|
||||||
|
|
||||||
|
# 具有仓库的操作权限或者fork仓库的操作权限
|
||||||
|
def require_operate_above_or_fork_project
|
||||||
|
@project = load_project
|
||||||
|
puts !current_user.admin? && !@project.operator?(current_user) && !(@project.fork_project.present? && @project.fork_project.operator?(current_user))
|
||||||
|
return render_forbidden if !current_user.admin? && !@project.operator?(current_user) && !(@project.fork_project.present? && @project.fork_project.operator?(current_user))
|
||||||
end
|
end
|
||||||
|
|
||||||
# 具有对仓库的访问权限
|
# 具有对仓库的访问权限
|
||||||
def require_public_and_member_above
|
def require_public_and_member_above
|
||||||
@project = load_project
|
@project = load_project
|
||||||
return render_forbidden unless @project.is_public || (current_user.admin? && @project.member?(current_user))
|
return render_forbidden if !@project.is_public && !current_user.admin? && !@project.member?(current_user)
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -1,9 +1,13 @@
|
||||||
class Api::V1::Projects::ContentsController < Api::V1::BaseController
|
class Api::V1::Projects::ContentsController < Api::V1::BaseController
|
||||||
before_action :require_operate_above, only: [:batch]
|
before_action :require_operate_above_or_fork_project, only: [:batch]
|
||||||
|
|
||||||
def batch
|
def batch
|
||||||
@result_object = Api::V1::Projects::Contents::BatchCreateService.call(@project, batch_content_params, current_user&.gitea_token)
|
@batch_content_params = batch_content_params
|
||||||
puts @result_object
|
# 处理下author和committer信息,如果没传则默认为当前用户信息
|
||||||
|
@batch_content_params.merge!(author_email: current_user.mail, author_name: current_user.login) if batch_content_params[:author_email].blank? && batch_content_params[:author_name].blank?
|
||||||
|
@batch_content_params.merge!(committer_email: current_user.mail, committer_name: current_user.login) if batch_content_params[:committer_email].blank? && batch_content_params[:committer_name].blank?
|
||||||
|
|
||||||
|
@result_object = Api::V1::Projects::Contents::BatchCreateService.call(@project, @batch_content_params, @project.owner.gitea_token)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
class Api::V1::Projects::Pulls::BaseController < Api::V1::BaseController
|
||||||
|
before_action :require_public_and_member_above
|
||||||
|
before_action :load_pull_request
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,40 @@
|
||||||
|
class Api::V1::Projects::Pulls::JournalsController < Api::V1::Projects::Pulls::BaseController
|
||||||
|
|
||||||
|
def index
|
||||||
|
@journals = Api::V1::Projects::Pulls::Journals::ListService.call(@project, @pull_request, params, current_user)
|
||||||
|
@journals = @journals.limit(200)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@journal = Api::V1::Projects::Pulls::Journals::CreateService.call(@project, @pull_request, create_params, current_user)
|
||||||
|
end
|
||||||
|
|
||||||
|
before_action :find_journal, only: [:update, :destroy]
|
||||||
|
|
||||||
|
def update
|
||||||
|
@journal = Api::V1::Projects::Pulls::Journals::UpdateService.call(@project, @pull_request, @journal, update_params, current_user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
if @journal.destroy
|
||||||
|
render_ok
|
||||||
|
else
|
||||||
|
render_error("删除评论失败!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def create_params
|
||||||
|
params.permit(:parent_id, :line_code, :note, :commit_id, :path, :type, :review_id, :diff => {})
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_params
|
||||||
|
params.permit(:note, :commit_id, :state)
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_journal
|
||||||
|
@journal = @pull_request.journals.find_by_id(params[:id])
|
||||||
|
return render_not_found unless @journal.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,20 @@
|
||||||
|
class Api::V1::Projects::Pulls::PullsController < Api::V1::BaseController
|
||||||
|
before_action :require_public_and_member_above
|
||||||
|
|
||||||
|
def index
|
||||||
|
@pulls = Api::V1::Projects::Pulls::ListService.call(@project, query_params)
|
||||||
|
@pulls = kaminari_paginate(@pulls)
|
||||||
|
end
|
||||||
|
|
||||||
|
before_action :load_pull_request, only: [:show]
|
||||||
|
|
||||||
|
def show
|
||||||
|
@result_object = Api::V1::Projects::Pulls::GetService.call(@project, @pull_request, current_user&.gitea_token)
|
||||||
|
@last_review = @pull_request.reviews.order(created_at: :desc).take
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def query_params
|
||||||
|
params.permit(:status, :keyword, :priority_id, :issue_tag_id, :version_id, :reviewer_id, :sort_by, :sort_direction)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,23 @@
|
||||||
|
class Api::V1::Projects::Pulls::ReviewsController < Api::V1::Projects::Pulls::BaseController
|
||||||
|
|
||||||
|
def index
|
||||||
|
@reviews = @pull_request.reviews
|
||||||
|
@reviews = @reviews.where(status: params[:status]) if params[:status].present?
|
||||||
|
# @reviews = kaminari_paginate(@reviews)
|
||||||
|
end
|
||||||
|
|
||||||
|
before_action :require_reviewer, only: [:create]
|
||||||
|
|
||||||
|
def create
|
||||||
|
@review = Api::V1::Projects::Pulls::Reviews::CreateService.call(@project, @pull_request, review_params, current_user)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def require_reviewer
|
||||||
|
return render_forbidden('您没有审查权限,请联系项目管理员') if !current_user.admin? && !@pull_request.reviewers.exists?(current_user.id) && !@project.manager?(current_user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def review_params
|
||||||
|
params.require(:review).permit(:content, :commit_id, :status)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,10 @@
|
||||||
|
class Api::V1::Projects::Pulls::VersionsController < Api::V1::Projects::Pulls::BaseController
|
||||||
|
|
||||||
|
def index
|
||||||
|
@result_object = Api::V1::Projects::Pulls::Versions::ListService.call(@project, @pull_request, {page: page, limit: limit}, current_user&.gitea_token)
|
||||||
|
end
|
||||||
|
|
||||||
|
def diff
|
||||||
|
@result_object = Api::V1::Projects::Pulls::Versions::GetDiffService.call(@project, @pull_request, params[:id], {filepath: params[:filepath]}, current_user&.gitea_token)
|
||||||
|
end
|
||||||
|
end
|
|
@ -5,11 +5,13 @@ class Api::V1::Projects::WebhooksController < Api::V1::BaseController
|
||||||
def index
|
def index
|
||||||
# @result_object = Api::V1::Projects::Webhooks::ListService.call(@project, current_user&.gitea_token)
|
# @result_object = Api::V1::Projects::Webhooks::ListService.call(@project, current_user&.gitea_token)
|
||||||
@webhooks = @project.webhooks
|
@webhooks = @project.webhooks
|
||||||
|
@webhooks = @webhooks.where(type: params[:type]) if params[:type].present?
|
||||||
@webhooks = kaminari_paginate(@webhooks)
|
@webhooks = kaminari_paginate(@webhooks)
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@result_object = Api::V1::Projects::Webhooks::CreateService.call(@project, webhook_params, current_user&.gitea_token)
|
return render_error("webhooks数量已到上限!请删除暂不使用的webhooks以进行添加操作") if @project.webhooks.size > 49
|
||||||
|
@result_object = Api::V1::Projects::Webhooks::CreateService.call(@project, create_webhook_params, current_user&.gitea_token)
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
|
@ -44,6 +46,10 @@ class Api::V1::Projects::WebhooksController < Api::V1::BaseController
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
def create_webhook_params
|
||||||
|
params.require(:webhook).permit(:active, :branch_filter, :http_method, :url, :content_type, :secret, :type, events: [])
|
||||||
|
end
|
||||||
|
|
||||||
def webhook_params
|
def webhook_params
|
||||||
params.require(:webhook).permit(:active, :branch_filter, :http_method, :url, :content_type, :secret, events: [])
|
params.require(:webhook).permit(:active, :branch_filter, :http_method, :url, :content_type, :secret, events: [])
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,6 +15,5 @@ class Api::V1::ProjectsController < Api::V1::BaseController
|
||||||
|
|
||||||
def blame
|
def blame
|
||||||
@result_object = Api::V1::Projects::BlameService.call(@project, params[:sha], params[:filepath], current_user&.gitea_token)
|
@result_object = Api::V1::Projects::BlameService.call(@project, params[:sha], params[:filepath], current_user&.gitea_token)
|
||||||
puts @result_object
|
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -1,6 +1,81 @@
|
||||||
class Api::V1::UsersController < Api::V1::BaseController
|
class Api::V1::UsersController < Api::V1::BaseController
|
||||||
|
|
||||||
def index
|
before_action :load_observe_user
|
||||||
render_ok
|
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(-2, '请勿频繁操作') if Rails.cache.exist?(send_email_limit_cache_key)
|
||||||
|
send_email_control = LimitForbidControl::SendEmailCode.new(mail)
|
||||||
|
tip_exception(-2, '邮件发送太频繁,请稍后再试') 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}
|
||||||
|
last_code = VerificationCode.where(code_type: code_type, email: mail).last
|
||||||
|
last_code.update_attributes!({created_at: Time.current - 10.minute}) if last_code.present?
|
||||||
|
data = VerificationCode.new(ver_params)
|
||||||
|
if data.save!
|
||||||
|
render_ok
|
||||||
|
else
|
||||||
|
tip_exception(-1, "创建数据失败")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_password
|
||||||
|
password = params[: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 tip_exception(-2, "邮件格式有误") unless mail =~ CustomRegexp::EMAIL
|
||||||
|
|
||||||
|
exist_owner = Owner.find_by(mail: mail)
|
||||||
|
return tip_exception(-2, '邮箱已被使用') 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 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 tip_exception(-6, "验证码不正确") if verifi_code&.code != code
|
||||||
|
return tip_exception(-6, "验证码已失效") 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
|
||||||
end
|
end
|
|
@ -20,9 +20,9 @@ class ApplicationController < ActionController::Base
|
||||||
# TODO
|
# TODO
|
||||||
# check sql query time
|
# check sql query time
|
||||||
before_action do
|
before_action do
|
||||||
if request.subdomain === 'testforgeplus' || request.subdomain === "profiler"
|
# if request.subdomain === 'testforgeplus' || request.subdomain === "profiler"
|
||||||
Rack::MiniProfiler.authorize_request
|
# Rack::MiniProfiler.authorize_request
|
||||||
end
|
# end
|
||||||
end
|
end
|
||||||
|
|
||||||
DCODES = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z)
|
DCODES = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z)
|
||||||
|
@ -173,6 +173,25 @@ class ApplicationController < ActionController::Base
|
||||||
tip_exception(401, "请登录后再操作") unless User.current.logged?
|
tip_exception(401, "请登录后再操作") unless User.current.logged?
|
||||||
end
|
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
|
def require_profile_completed
|
||||||
tip_exception(411, "请完善资料后再操作") unless User.current.profile_is_completed?
|
tip_exception(411, "请完善资料后再操作") unless User.current.profile_is_completed?
|
||||||
end
|
end
|
||||||
|
@ -277,11 +296,11 @@ class ApplicationController < ActionController::Base
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# if !User.current.logged? && Rails.env.development?
|
if !User.current.logged? && Rails.env.development?
|
||||||
# user = User.find 1
|
user = User.find 1
|
||||||
# User.current = user
|
User.current = user
|
||||||
# start_user_session(user)
|
start_user_session(user)
|
||||||
# end
|
end
|
||||||
|
|
||||||
|
|
||||||
# 测试版前端需求
|
# 测试版前端需求
|
||||||
|
@ -619,7 +638,7 @@ class ApplicationController < ActionController::Base
|
||||||
|
|
||||||
def kaminari_paginate(relation)
|
def kaminari_paginate(relation)
|
||||||
limit = params[:limit] || params[:per_page]
|
limit = params[:limit] || params[:per_page]
|
||||||
limit = (limit.to_i.zero? || limit.to_i > 20) ? 20 : limit.to_i
|
limit = (limit.to_i.zero? || limit.to_i > 25) ? 25 : limit.to_i
|
||||||
page = params[:page].to_i.zero? ? 1 : params[:page].to_i
|
page = params[:page].to_i.zero? ? 1 : params[:page].to_i
|
||||||
|
|
||||||
relation.page(page).per(limit)
|
relation.page(page).per(limit)
|
||||||
|
@ -704,9 +723,15 @@ class ApplicationController < ActionController::Base
|
||||||
# @project = nil if !@project.is_public?
|
# @project = nil if !@project.is_public?
|
||||||
# render_forbidden and return
|
# render_forbidden and return
|
||||||
else
|
else
|
||||||
logger.info "###########:project not found"
|
if @project.present?
|
||||||
@project = nil
|
logger.info "###########: has project and but can't read project"
|
||||||
render_not_found and return
|
@project = nil
|
||||||
|
render_forbidden and return
|
||||||
|
else
|
||||||
|
logger.info "###########:project not found"
|
||||||
|
@project = nil
|
||||||
|
render_not_found and return
|
||||||
|
end
|
||||||
end
|
end
|
||||||
@project
|
@project
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,261 +1,261 @@
|
||||||
#coding=utf-8
|
#coding=utf-8
|
||||||
#
|
#
|
||||||
# 文件上传
|
# 文件上传
|
||||||
class AttachmentsController < ApplicationController
|
class AttachmentsController < ApplicationController
|
||||||
before_action :require_login, :check_auth, except: [:show, :preview_attachment, :get_file]
|
before_action :require_login, :check_auth, except: [:show, :preview_attachment, :get_file]
|
||||||
before_action :find_file, only: %i[show destroy]
|
before_action :find_file, only: %i[show destroy]
|
||||||
before_action :attachment_candown, only: [:show]
|
before_action :attachment_candown, only: [:show]
|
||||||
skip_before_action :check_sign, only: [:show, :create]
|
skip_before_action :check_sign, only: [:show, :create]
|
||||||
|
|
||||||
include ApplicationHelper
|
include ApplicationHelper
|
||||||
|
|
||||||
def show
|
def show
|
||||||
# 1. 优先跳到cdn
|
# 1. 优先跳到cdn
|
||||||
# 2. 如果没有cdn,send_file
|
# 2. 如果没有cdn,send_file
|
||||||
if @file.cloud_url.present?
|
if @file.cloud_url.present?
|
||||||
update_downloads(@file)
|
update_downloads(@file)
|
||||||
redirect_to @file.cloud_url and return
|
redirect_to @file.cloud_url and return
|
||||||
end
|
end
|
||||||
|
|
||||||
type_attachment = params[:disposition] || "attachment"
|
type_attachment = params[:disposition] || "attachment"
|
||||||
if type_attachment == "inline"
|
if type_attachment == "inline"
|
||||||
send_file absolute_path(local_path(@file)),filename: @file.title, disposition: 'inline',type: 'application/pdf'
|
send_file absolute_path(local_path(@file)),filename: @file.title, disposition: 'inline',type: 'application/pdf'
|
||||||
elsif type_attachment == "MP4"
|
elsif type_attachment == "MP4"
|
||||||
send_file_with_range absolute_path(local_path(@file)), disposition: 'inline', type: "video/mp4", range: true
|
send_file_with_range absolute_path(local_path(@file)), disposition: 'inline', type: "video/mp4", range: true
|
||||||
else
|
else
|
||||||
send_file(absolute_path(local_path(@file)), filename: @file.title,stream:false, type: @file.content_type.presence || 'application/octet-stream')
|
send_file(absolute_path(local_path(@file)), filename: @file.title,stream:false, type: @file.content_type.presence || 'application/octet-stream')
|
||||||
end
|
end
|
||||||
update_downloads(@file)
|
update_downloads(@file)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def get_file
|
def get_file
|
||||||
normal_status(-1, "参数缺失") if params[:download_url].blank?
|
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)
|
if url.starts_with?(base_url)
|
||||||
domain = GiteaService.gitea_config[:domain]
|
domain = GiteaService.gitea_config[:domain]
|
||||||
api_url = GiteaService.gitea_config[:base_url]
|
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
|
request_url = [domain, api_url, url, "?ref=#{params[:ref]}&access_token=#{current_user&.gitea_token}"].join
|
||||||
response = Faraday.get(request_url)
|
response = Faraday.get(request_url)
|
||||||
filename = url.to_s.split("/").pop()
|
filename = url.to_s.split("/").pop()
|
||||||
else
|
else
|
||||||
response = Faraday.get(url)
|
response = Faraday.get(url)
|
||||||
filename = params[:download_url].to_s.split("/").pop()
|
filename = params[:download_url].to_s.split("/").pop()
|
||||||
end
|
end
|
||||||
send_data(response.body.force_encoding("UTF-8"), filename: filename, type: "application/octet-stream", disposition: 'attachment')
|
send_data(response.body.force_encoding("UTF-8"), filename: filename, type: "application/octet-stream", disposition: 'attachment')
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
# 1. 本地存储
|
# 1. 本地存储
|
||||||
# 2. 上传到云
|
# 2. 上传到云
|
||||||
begin
|
begin
|
||||||
upload_file = params["file"] || params["#{params[:file_param_name]}"]# 这里的file_param_name是为了方便其他插件名称
|
upload_file = params["file"] || params["#{params[:file_param_name]}"]# 这里的file_param_name是为了方便其他插件名称
|
||||||
uid_logger("#########################file_params####{params["#{params[:file_param_name]}"]}")
|
uid_logger("#########################file_params####{params["#{params[:file_param_name]}"]}")
|
||||||
raise "未上传文件" unless upload_file
|
raise "未上传文件" unless upload_file
|
||||||
|
|
||||||
folder = file_storage_directory
|
folder = file_storage_directory
|
||||||
raise "存储目录未定义" unless folder.present?
|
raise "存储目录未定义" unless folder.present?
|
||||||
|
|
||||||
month_folder = current_month_folder
|
month_folder = current_month_folder
|
||||||
save_path = File.join(folder, month_folder)
|
save_path = File.join(folder, month_folder)
|
||||||
|
|
||||||
ext = file_ext(upload_file.original_filename)
|
ext = file_ext(upload_file.original_filename)
|
||||||
|
|
||||||
local_path, digest = file_save_to_local(save_path, upload_file.tempfile, ext)
|
local_path, digest = file_save_to_local(save_path, upload_file.tempfile, ext)
|
||||||
|
|
||||||
content_type = upload_file.content_type.presence || 'application/octet-stream'
|
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 = file_save_to_ucloud(local_path[folder.size, local_path.size], local_path, content_type)
|
||||||
remote_path = nil # TODO 暂时本地上传,待域名配置后方可上传至云端
|
remote_path = nil # TODO 暂时本地上传,待域名配置后方可上传至云端
|
||||||
|
|
||||||
logger.info "local_path: #{local_path}"
|
logger.info "local_path: #{local_path}"
|
||||||
logger.info "remote_path: #{remote_path}"
|
logger.info "remote_path: #{remote_path}"
|
||||||
|
|
||||||
|
|
||||||
disk_filename = local_path[save_path.size + 1, local_path.size]
|
disk_filename = local_path[save_path.size + 1, local_path.size]
|
||||||
#存数据库
|
#存数据库
|
||||||
#
|
#
|
||||||
@attachment = Attachment.where(disk_filename: disk_filename,
|
@attachment = Attachment.where(disk_filename: disk_filename,
|
||||||
author_id: current_user.id,
|
author_id: current_user.id,
|
||||||
cloud_url: remote_path).first
|
cloud_url: remote_path).first
|
||||||
if @attachment.blank?
|
if @attachment.blank?
|
||||||
@attachment = Attachment.new
|
@attachment = Attachment.new
|
||||||
@attachment.filename = upload_file.original_filename
|
@attachment.filename = upload_file.original_filename
|
||||||
@attachment.disk_filename = local_path[save_path.size + 1, local_path.size]
|
@attachment.disk_filename = local_path[save_path.size + 1, local_path.size]
|
||||||
@attachment.filesize = upload_file.tempfile.size
|
@attachment.filesize = upload_file.tempfile.size
|
||||||
@attachment.content_type = content_type
|
@attachment.content_type = content_type
|
||||||
@attachment.digest = digest
|
@attachment.digest = digest
|
||||||
@attachment.author_id = current_user.id
|
@attachment.author_id = current_user.id
|
||||||
@attachment.disk_directory = month_folder
|
@attachment.disk_directory = month_folder
|
||||||
@attachment.cloud_url = remote_path
|
@attachment.cloud_url = remote_path
|
||||||
@attachment.save!
|
@attachment.save!
|
||||||
else
|
else
|
||||||
logger.info "文件已存在,id = #{@attachment.id}, filename = #{@attachment.filename}"
|
logger.info "文件已存在,id = #{@attachment.id}, filename = #{@attachment.filename}"
|
||||||
end
|
end
|
||||||
|
|
||||||
render_json
|
render_json
|
||||||
rescue => e
|
rescue => e
|
||||||
uid_logger_error(e.message)
|
uid_logger_error(e.message)
|
||||||
tip_exception(e.message)
|
tip_exception(e.message)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
begin
|
begin
|
||||||
@file_path = absolute_path(local_path(@file))
|
@file_path = absolute_path(local_path(@file))
|
||||||
#return normal_status(403, "") unless @file.author == current_user
|
#return normal_status(403, "") unless @file.author == current_user
|
||||||
@file.destroy!
|
@file.destroy!
|
||||||
|
|
||||||
delete_file(@file_path)
|
delete_file(@file_path)
|
||||||
normal_status("删除成功")
|
normal_status("删除成功")
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
uid_logger_error(e.message)
|
uid_logger_error(e.message)
|
||||||
tip_exception(e.message)
|
tip_exception(e.message)
|
||||||
raise ActiveRecord::Rollback
|
raise ActiveRecord::Rollback
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# 附件为视频时,点击播放
|
# 附件为视频时,点击播放
|
||||||
def preview_attachment
|
def preview_attachment
|
||||||
attachment = Attachment.find_by(id: params[:id])
|
attachment = Attachment.find_by(id: params[:id])
|
||||||
dir_path = "#{Rails.root}/public/preview"
|
dir_path = "#{Rails.root}/public/preview"
|
||||||
Dir.mkdir(dir_path) unless Dir.exist?(dir_path)
|
Dir.mkdir(dir_path) unless Dir.exist?(dir_path)
|
||||||
if params[:status] == "preview"
|
if params[:status] == "preview"
|
||||||
if system("cp -r #{absolute_path(local_path(attachment))} #{dir_path}/")
|
if system("cp -r #{absolute_path(local_path(attachment))} #{dir_path}/")
|
||||||
render json: {status: 1, url: "/preview/#{attachment.disk_filename}"}
|
render json: {status: 1, url: "/preview/#{attachment.disk_filename}"}
|
||||||
else
|
else
|
||||||
normal_status(-1, "出现错误,请稍后重试")
|
normal_status(-1, "出现错误,请稍后重试")
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if system("rm -rf #{dir_path}/#{attachment.disk_filename}")
|
if system("rm -rf #{dir_path}/#{attachment.disk_filename}")
|
||||||
normal_status(1, "操作成功")
|
normal_status(1, "操作成功")
|
||||||
else
|
else
|
||||||
normal_status(-1, "出现错误,请稍后重试")
|
normal_status(-1, "出现错误,请稍后重试")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def find_file
|
def find_file
|
||||||
@file =
|
@file =
|
||||||
if params[:type] == 'history'
|
if params[:type] == 'history'
|
||||||
AttachmentHistory.find params[:id]
|
AttachmentHistory.find params[:id]
|
||||||
else
|
else
|
||||||
Attachment.find params[:id]
|
Attachment.find params[:id]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete_file(file_path)
|
def delete_file(file_path)
|
||||||
File.delete(file_path) if File.exist?(file_path)
|
File.delete(file_path) if File.exist?(file_path)
|
||||||
end
|
end
|
||||||
|
|
||||||
def current_month_folder
|
def current_month_folder
|
||||||
date = Time.now
|
date = Time.now
|
||||||
"#{date.year}/#{date.month.to_s.rjust(2, '0')}"
|
"#{date.year}/#{date.month.to_s.rjust(2, '0')}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def file_ext(file_name)
|
def file_ext(file_name)
|
||||||
ext = ''
|
ext = ''
|
||||||
exts = file_name.split(".")
|
exts = file_name.split(".")
|
||||||
if exts.size > 1
|
if exts.size > 1
|
||||||
ext = ".#{exts.last}"
|
ext = ".#{exts.last}"
|
||||||
end
|
end
|
||||||
ext
|
ext
|
||||||
end
|
end
|
||||||
|
|
||||||
def file_save_to_local(save_path, temp_file, ext)
|
def file_save_to_local(save_path, temp_file, ext)
|
||||||
unless Dir.exists?(save_path)
|
unless Dir.exists?(save_path)
|
||||||
FileUtils.mkdir_p(save_path) ##不成功这里会抛异常
|
FileUtils.mkdir_p(save_path) ##不成功这里会抛异常
|
||||||
end
|
end
|
||||||
|
|
||||||
digest = md5_file(temp_file)
|
digest = md5_file(temp_file)
|
||||||
digest = "#{digest}_#{(Time.now.to_f * 1000).to_i}"
|
digest = "#{digest}_#{(Time.now.to_f * 1000).to_i}"
|
||||||
local_file_path = File.join(save_path, digest) + ext
|
local_file_path = File.join(save_path, digest) + ext
|
||||||
save_temp_file(temp_file, local_file_path)
|
save_temp_file(temp_file, local_file_path)
|
||||||
|
|
||||||
[local_file_path, digest]
|
[local_file_path, digest]
|
||||||
end
|
end
|
||||||
|
|
||||||
def save_temp_file(temp_file, save_file_path)
|
def save_temp_file(temp_file, save_file_path)
|
||||||
File.open(save_file_path, 'wb') do |f|
|
File.open(save_file_path, 'wb') do |f|
|
||||||
temp_file.rewind
|
temp_file.rewind
|
||||||
while (buffer = temp_file.read(8192))
|
while (buffer = temp_file.read(8192))
|
||||||
f.write(buffer)
|
f.write(buffer)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def md5_file(temp_file)
|
def md5_file(temp_file)
|
||||||
md5 = Digest::MD5.new
|
md5 = Digest::MD5.new
|
||||||
temp_file.rewind
|
temp_file.rewind
|
||||||
while (buffer = temp_file.read(8192))
|
while (buffer = temp_file.read(8192))
|
||||||
md5.update(buffer)
|
md5.update(buffer)
|
||||||
end
|
end
|
||||||
md5.hexdigest
|
md5.hexdigest
|
||||||
end
|
end
|
||||||
|
|
||||||
def file_save_to_ucloud(path, file, content_type)
|
def file_save_to_ucloud(path, file, content_type)
|
||||||
ufile = Gitlink::Ufile.new(
|
ufile = Gitlink::Ufile.new(
|
||||||
ucloud_public_key: edu_setting('public_key'),
|
ucloud_public_key: edu_setting('public_key'),
|
||||||
ucloud_private_key: edu_setting('private_key'),
|
ucloud_private_key: edu_setting('private_key'),
|
||||||
ucloud_public_read: true,
|
ucloud_public_read: true,
|
||||||
ucloud_public_bucket: edu_setting('public_bucket'),
|
ucloud_public_bucket: edu_setting('public_bucket'),
|
||||||
ucloud_public_bucket_host: edu_setting('public_bucket_host'),
|
ucloud_public_bucket_host: edu_setting('public_bucket_host'),
|
||||||
ucloud_public_cdn_host: edu_setting('public_cdn_host'),
|
ucloud_public_cdn_host: edu_setting('public_cdn_host'),
|
||||||
)
|
)
|
||||||
File.open(file) do |f|
|
File.open(file) do |f|
|
||||||
ufile.put(path, f, 'Content-Type' => content_type)
|
ufile.put(path, f, 'Content-Type' => content_type)
|
||||||
end
|
end
|
||||||
edu_setting('public_cdn_host') + "/" + path
|
edu_setting('public_cdn_host') + "/" + path
|
||||||
end
|
end
|
||||||
|
|
||||||
def attachment_candown
|
def attachment_candown
|
||||||
unless current_user.admin? || current_user.business?
|
unless current_user.admin? || current_user.business?
|
||||||
candown = true
|
candown = true
|
||||||
unless params[:type] == 'history'
|
unless params[:type] == 'history'
|
||||||
if @file.container && current_user.logged?
|
if @file.container && current_user.logged?
|
||||||
if @file.container.is_a?(Issue)
|
if @file.container.is_a?(Issue)
|
||||||
course = @file.container.project
|
course = @file.container.project
|
||||||
candown = course.member?(current_user) || course.is_public
|
candown = course.member?(current_user) || course.is_public
|
||||||
elsif @file.container.is_a?(Journal)
|
elsif @file.container.is_a?(Journal)
|
||||||
course = @file.container.issue.project
|
course = @file.container.issue.project
|
||||||
candown = course.member?(current_user)
|
candown = course.member?(current_user) || course.is_public
|
||||||
else
|
else
|
||||||
course = nil
|
course = nil
|
||||||
end
|
end
|
||||||
tip_exception(403, "您没有权限进入") if course.present? && !candown
|
tip_exception(403, "您没有权限进入") if course.present? && !candown
|
||||||
tip_exception(403, "您没有权限进入") if @file.container.is_a?(ApplyUserAuthentication)
|
tip_exception(403, "您没有权限进入") if @file.container.is_a?(ApplyUserAuthentication)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_file_with_range(path, options = {})
|
def send_file_with_range(path, options = {})
|
||||||
logger.info("########request.headers: #{request.headers}")
|
logger.info("########request.headers: #{request.headers}")
|
||||||
logger.info("########request.headers: #{File.exist?(path)}")
|
logger.info("########request.headers: #{File.exist?(path)}")
|
||||||
|
|
||||||
if File.exist?(path)
|
if File.exist?(path)
|
||||||
size = File.size(path)
|
size = File.size(path)
|
||||||
logger.info("########request.headers: #{request.headers}")
|
logger.info("########request.headers: #{request.headers}")
|
||||||
if !request.headers["Range"]
|
if !request.headers["Range"]
|
||||||
status_code = 200 # 200 OK
|
status_code = 200 # 200 OK
|
||||||
offset = 0
|
offset = 0
|
||||||
length = File.size(path)
|
length = File.size(path)
|
||||||
else
|
else
|
||||||
status_code = 206 # 206 Partial Content
|
status_code = 206 # 206 Partial Content
|
||||||
bytes = Rack::Utils.byte_ranges(request.headers, size)[0]
|
bytes = Rack::Utils.byte_ranges(request.headers, size)[0]
|
||||||
offset = bytes.begin
|
offset = bytes.begin
|
||||||
length = bytes.end - bytes.begin
|
length = bytes.end - bytes.begin
|
||||||
end
|
end
|
||||||
response.header["Accept-Ranges"] = "bytes"
|
response.header["Accept-Ranges"] = "bytes"
|
||||||
response.header["Content-Range"] = "bytes #{bytes.begin}-#{bytes.end}/#{size}" if bytes
|
response.header["Content-Range"] = "bytes #{bytes.begin}-#{bytes.end}/#{size}" if bytes
|
||||||
response.header["status"] = status_code
|
response.header["status"] = status_code
|
||||||
|
|
||||||
send_data IO.binread(path, length, offset), options
|
send_data IO.binread(path, length, offset), options
|
||||||
else
|
else
|
||||||
raise ActionController::MissingFile, "Cannot read file #{path}."
|
raise ActionController::MissingFile, "Cannot read file #{path}."
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,12 +15,15 @@ class CommitLogsController < ApplicationController
|
||||||
owner = User.find_by(login: owner_name)
|
owner = User.find_by(login: owner_name)
|
||||||
project = Project.where(identifier: repository_name).where(user_id: owner&.id)&.first
|
project = Project.where(identifier: repository_name).where(user_id: owner&.id)&.first
|
||||||
project = Project.where(identifier: repository_name).where(gpid: repository_id)&.first if project.blank?
|
project = Project.where(identifier: repository_name).where(gpid: repository_id)&.first if project.blank?
|
||||||
|
project.update_column(:updated_on, Time.now) if project.present?
|
||||||
params[:commits].each do |commit|
|
params[:commits].each do |commit|
|
||||||
commit_id = commit[:id]
|
commit_id = commit[:id]
|
||||||
message = commit[:message]
|
message = commit[:message]
|
||||||
CommitLog.create(user: user, project: project, repository_id: repository_id,
|
CommitLog.create(user: user, project: project, repository_id: repository_id,
|
||||||
name: repository_name, full_name: repository_full_name,
|
name: repository_name, full_name: repository_full_name,
|
||||||
ref: ref, commit_id: commit_id, message: message)
|
ref: ref, commit_id: commit_id, message: message)
|
||||||
|
# 统计数据新增
|
||||||
|
CacheAsyncSetJob.perform_later("project_common_service", {commits: 1}, project.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
module Api::PullHelper
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
def load_pull_request
|
||||||
|
pull_request_id = params[:pull_id] || params[:id]
|
||||||
|
@pull_request = @project.pull_requests.where(gitea_number: pull_request_id).where.not(id: pull_request_id).take || PullRequest.find_by_id(pull_request_id)
|
||||||
|
@issue = @pull_request&.issue
|
||||||
|
if @pull_request
|
||||||
|
logger.info "###########pull_request founded"
|
||||||
|
@pull_request
|
||||||
|
else
|
||||||
|
logger.info "###########pull_request not found"
|
||||||
|
@pull_request = nil
|
||||||
|
render_not_found and return
|
||||||
|
end
|
||||||
|
|
||||||
|
@pull_request
|
||||||
|
end
|
||||||
|
end
|
|
@ -16,4 +16,13 @@ module Api::UserHelper
|
||||||
end
|
end
|
||||||
@observe_user
|
@observe_user
|
||||||
end
|
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
|
end
|
|
@ -16,6 +16,7 @@ module RegisterHelper
|
||||||
return unless user.valid?
|
return unless user.valid?
|
||||||
|
|
||||||
interactor = Gitea::RegisterInteractor.call({username: username, email: email, password: password})
|
interactor = Gitea::RegisterInteractor.call({username: username, email: email, password: password})
|
||||||
|
result ={}
|
||||||
if interactor.success?
|
if interactor.success?
|
||||||
gitea_user = interactor.result
|
gitea_user = interactor.result
|
||||||
result = Gitea::User::GenerateTokenService.call(username, password)
|
result = Gitea::User::GenerateTokenService.call(username, password)
|
||||||
|
@ -26,7 +27,7 @@ module RegisterHelper
|
||||||
result[:user] = {id: user.id, token: user.gitea_token}
|
result[:user] = {id: user.id, token: user.gitea_token}
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
result[:message] = interactor.error
|
result[:message] = interactor.result[:message]
|
||||||
end
|
end
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,7 @@ module RenderHelper
|
||||||
render json: { status: 0, message: 'success' }.merge(data)
|
render json: { status: 0, message: 'success' }.merge(data)
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_error(message = '')
|
def render_error(message = '', status = -1)
|
||||||
render json: { status: status, message: message }
|
render json: { status: status, message: message }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ module Repository::LanguagesPercentagable
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_project_language(language)
|
def update_project_language(language)
|
||||||
|
return if @project.project_language.present?
|
||||||
db_language = ProjectLanguage.find_or_create_by!(name: language.keys.first.downcase.upcase_first)
|
db_language = ProjectLanguage.find_or_create_by!(name: language.keys.first.downcase.upcase_first)
|
||||||
@project.update_column(:project_language_id, db_language.id)
|
@project.update_column(:project_language_id, db_language.id)
|
||||||
rescue
|
rescue
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
class MarkFilesController < ApplicationController
|
||||||
|
before_action :require_login
|
||||||
|
before_action :load_project
|
||||||
|
before_action :load_pull_request
|
||||||
|
|
||||||
|
def index
|
||||||
|
@files_result = Gitea::PullRequest::FilesService.call(@owner.login, @project.identifier, @pull_request.gitea_number, current_user&.gitea_token, { "only-file-name": true })
|
||||||
|
@mark_files = MarkFile.where(pull_request_id: @pull_request.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
# unless @pull_request.mark_files.present?
|
||||||
|
# MarkFile.bulk_insert(*%i[pull_request_id, file_path_sha file_path created_at updated_at]) do |worker|
|
||||||
|
# @files_result['Files'].each do |file|
|
||||||
|
# worker.add(pull_request_id: @pull_request.id, file_path_sha: SecureRandom.uuid.gsub("-", ""), file_path: file['Name'])
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
end
|
||||||
|
|
||||||
|
def mark_file_as_unread
|
||||||
|
tip_exception "参数错误" if params[:file_path_sha].blank?
|
||||||
|
file_path = Base64.strict_decode64(params[:file_path_sha].to_s)
|
||||||
|
mark_file = @pull_request.mark_files.find_or_initialize_by(file_path_sha: params[:file_path_sha])
|
||||||
|
mark_file.file_path = file_path
|
||||||
|
mark_file.user_id = current_user.id
|
||||||
|
mark_file.mark_as_read = false
|
||||||
|
mark_file.save
|
||||||
|
render_ok
|
||||||
|
rescue Exception => e
|
||||||
|
tip_exception "参数解析错误"
|
||||||
|
end
|
||||||
|
|
||||||
|
def mark_file_as_read
|
||||||
|
tip_exception "参数错误" if params[:file_path_sha].blank?
|
||||||
|
file_path = Base64.strict_decode64(params[:file_path_sha].to_s)
|
||||||
|
mark_file = @pull_request.mark_files.find_or_initialize_by(file_path_sha: params[:file_path_sha])
|
||||||
|
mark_file.file_path = file_path
|
||||||
|
mark_file.user_id = current_user.id
|
||||||
|
mark_file.mark_as_read = true
|
||||||
|
mark_file.save
|
||||||
|
render_ok
|
||||||
|
rescue Exception => e
|
||||||
|
tip_exception "参数解析错误"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def review_params
|
||||||
|
params.require(:review).permit(:content, :commit_id, :status)
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_pull_request
|
||||||
|
@pull_request = @project.pull_requests.where(gitea_number: params[:id]).where.not(id: params[:id]).take || PullRequest.find_by_id(params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -26,6 +26,9 @@ class MembersController < ApplicationController
|
||||||
|
|
||||||
@total_count = scope.size
|
@total_count = scope.size
|
||||||
@members = paginate(scope)
|
@members = paginate(scope)
|
||||||
|
if @project.owner.is_a?(Organization) && (params[:page].to_i == 1 || params[:page].blank?) && !@project.members.exists?(user_id: current_user.id)
|
||||||
|
@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
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove
|
def remove
|
||||||
|
@ -61,11 +64,14 @@ class MembersController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_member_exists!
|
def check_member_exists!
|
||||||
return render_error("user_id为#{params[:user_id]}的用户已经是项目成员") if 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&.nickname}已经是项目成员") if member_exists? || (params[:user_id].to_i == current_user.id && @current_user_header_team.present?)
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_member_not_exists!
|
def check_member_not_exists!
|
||||||
return render_error("user_id为#{params[:user_id]}的用户还不是项目成员") unless 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("用户为组织成员,请到组织下操作!") if (params[:user_id].to_i == current_user.id && @current_user_header_team.present?) && !member_exists?
|
||||||
|
return render_error("#{@user&.nickname}还不是项目成员") unless member_exists?
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_user_profile_completed
|
def check_user_profile_completed
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
class NpsController < ApplicationController
|
||||||
|
|
||||||
|
before_action :require_login
|
||||||
|
|
||||||
|
# close,关闭
|
||||||
|
# createIssue,创建issue
|
||||||
|
# createPullRequest,创建PR
|
||||||
|
# auditPullRequest,审核PR
|
||||||
|
# indexProject,项目主页
|
||||||
|
# createProject,创建项目
|
||||||
|
# createOrganization,创建组织
|
||||||
|
def create
|
||||||
|
tip_exception "缺少参数" if params[:action_id].blank? || params[:action_type].blank?
|
||||||
|
UserNp.create(:action_id => params[:action_id].to_i, :action_type => params[:action_type], :user_id => User.current.id, :score => params[:score].to_f, memo: params[:memo])
|
||||||
|
render_ok
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,130 @@
|
||||||
|
class ObRepositorySyncsController < ApplicationController
|
||||||
|
before_action :require_login
|
||||||
|
before_action :load_project
|
||||||
|
before_action :load_ob_repository_sync, except: [:create]
|
||||||
|
before_action :authenticate_user!
|
||||||
|
|
||||||
|
def index
|
||||||
|
render_ok(data: @ob_repository_sync)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def create
|
||||||
|
tip_exception "参数错误" if params[:github_address].blank? && params[:gitee_address].blank?
|
||||||
|
project_name ="#{@project.owner.name}:#{@project.identifier}"
|
||||||
|
service = ObRepositorySync::ApiService.new(project_name)
|
||||||
|
domain = GiteaService.gitea_config[:domain]
|
||||||
|
project_params = params.merge({ "gitlink_address": "#{domain}/#{@project.owner&.login}/#{@project.identifier}.git" })
|
||||||
|
res = service.create_projects(project_params)
|
||||||
|
tip_exception "保存失败: #{res["msg"]}" if res["code"].to_s != "200"
|
||||||
|
sync_id = res["data"]["id"]
|
||||||
|
ob_repository_sync = ObRepositorySync.find_or_initialize_by(project_id: @project.id)
|
||||||
|
ob_repository_sync.project_id = @project.id
|
||||||
|
ob_repository_sync.user_id = current_user.id
|
||||||
|
ob_repository_sync.name = project_name
|
||||||
|
ob_repository_sync.github_address = "#{params[:github_address]}"
|
||||||
|
ob_repository_sync.gitee_address = "#{params[:gitee_address]}"
|
||||||
|
ob_repository_sync.github_token = "#{params[:github_token]}"
|
||||||
|
ob_repository_sync.gitee_token = "#{params[:gitee_token]}"
|
||||||
|
ob_repository_sync.sync_id = sync_id
|
||||||
|
ob_repository_sync.save!
|
||||||
|
render_ok
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete
|
||||||
|
service = ObRepositorySync::ApiService.new(@ob_repository_sync.name)
|
||||||
|
res = service.delete_project @ob_repository_sync.sync_id
|
||||||
|
tip_exception "删除失败: #{res["msg"]}" if res["code"].to_s != "200"
|
||||||
|
if res["code"].to_s == "200"
|
||||||
|
@ob_repository_sync.destroy!
|
||||||
|
end
|
||||||
|
render_ok
|
||||||
|
end
|
||||||
|
|
||||||
|
def jobs
|
||||||
|
tip_exception "该项目未创建同步任务" if @ob_repository_sync.blank?
|
||||||
|
page = params[:page] || 1
|
||||||
|
limit = params[:limit] || 10
|
||||||
|
service = ObRepositorySync::ApiService.new(@ob_repository_sync.name)
|
||||||
|
source = ""
|
||||||
|
if params[:type] && params[:type].to_s.downcase == "github"
|
||||||
|
source = "github_branch"
|
||||||
|
elsif params[:type] && params[:type].to_s.downcase == "gitee"
|
||||||
|
source = "gitee_branch"
|
||||||
|
end
|
||||||
|
res = service.get_projects_jobs(source, page, limit)
|
||||||
|
data = res["data"]["list"]
|
||||||
|
render_ok(count: res["data"]["total"], data: data)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_jobs
|
||||||
|
tip_exception "必须配置一个分支" if params[:github_branch].blank? && params[:gitee_branch].blank? && params[:gitlink_branch].blank?
|
||||||
|
ob_jobs = ObRepositorySyncJob.where(ob_repository_sync_id: @ob_repository_sync.id)
|
||||||
|
ob_jobs = ob_jobs.where(job_type: params[:job_type]) if params[:job_type].present?
|
||||||
|
ob_jobs = ob_jobs.where(github_branch: params[:github_branch]) if params[:github_branch].present?
|
||||||
|
ob_jobs = ob_jobs.where(gitee_branch: params[:gitee_branch]) if params[:gitee_branch].present?
|
||||||
|
ob_jobs = ob_jobs.where(gitlink_branch: params[:gitlink_branch]) if params[:gitlink_branch].present?
|
||||||
|
tip_exception "该分支组合已配置,不能重复!" if ob_jobs.count > 0
|
||||||
|
service = ObRepositorySync::ApiService.new(@ob_repository_sync.name)
|
||||||
|
res = service.create_projects_jobs(params)
|
||||||
|
tip_exception "保存失败: #{res["msg"]}" if res["code"].to_s != "200"
|
||||||
|
job_id = res["data"]["id"]
|
||||||
|
job = ObRepositorySyncJob.new
|
||||||
|
job.ob_repository_sync_id = @ob_repository_sync.id
|
||||||
|
job.github_branch = "#{params[:github_branch]}"
|
||||||
|
job.gitee_branch = "#{params[:gitee_branch]}"
|
||||||
|
job.gitlink_branch = "#{params[:gitlink_branch]}"
|
||||||
|
job.job_type = "#{params[:job_type]}"
|
||||||
|
job.base = "#{params[:base]}"
|
||||||
|
job.job_id = job_id
|
||||||
|
job.save
|
||||||
|
render_ok
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def delete_job
|
||||||
|
tip_exception "缺少参数job_id" if params[:job_id].blank?
|
||||||
|
service = ObRepositorySync::ApiService.new(@ob_repository_sync.name)
|
||||||
|
res = service.delete_job params[:job_id]
|
||||||
|
tip_exception "删除失败: #{res["msg"]}" if res["code"].to_s != "200"
|
||||||
|
job = ObRepositorySyncJob.find_by(ob_repository_sync_id: @ob_repository_sync.id, job_id: params[:job_id])
|
||||||
|
job.destroy! if job.present?
|
||||||
|
render_ok
|
||||||
|
end
|
||||||
|
|
||||||
|
def start_job
|
||||||
|
tip_exception "缺少参数job_id" if params[:job_id].blank?
|
||||||
|
service = ObRepositorySync::ApiService.new(@ob_repository_sync.name)
|
||||||
|
res = service.start_job params[:job_id]
|
||||||
|
tip_exception "启动错误: #{res["msg"]}" if res["code"].to_s != "200"
|
||||||
|
render_ok
|
||||||
|
end
|
||||||
|
|
||||||
|
def stop_job
|
||||||
|
tip_exception "缺少参数job_id" if params[:job_id].blank?
|
||||||
|
service = ObRepositorySync::ApiService.new(@ob_repository_sync.name)
|
||||||
|
res = service.stop_job params[:job_id]
|
||||||
|
tip_exception "停止错误: #{res["msg"]}" if res["code"].to_s != "200"
|
||||||
|
render_ok
|
||||||
|
end
|
||||||
|
|
||||||
|
def job_logs
|
||||||
|
tip_exception "该项目未创建同步任务" if @ob_repository_sync.blank?
|
||||||
|
tip_exception "缺少参数job_id" if params[:job_id].blank?
|
||||||
|
service = ObRepositorySync::ApiService.new(@ob_repository_sync.name)
|
||||||
|
res = service.job_logs params[:job_id]
|
||||||
|
tip_exception "请求错误: #{res["msg"]}" if res["code"].to_s != "200"
|
||||||
|
render_ok(count: res["data"]["total"], data: res["data"]["list"])
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def load_ob_repository_sync
|
||||||
|
@ob_repository_sync = ObRepositorySync.find_by(project_id: @project.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def authenticate_user!
|
||||||
|
return if @project.member?(current_user) || current_user.admin?
|
||||||
|
render_forbidden('你没有权限操作')
|
||||||
|
end
|
||||||
|
end
|
|
@ -4,12 +4,14 @@ class Organizations::OrganizationUsersController < Organizations::BaseController
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@organization_users = @organization.organization_users.includes(:user)
|
@organization_users = @organization.organization_users.includes(:user)
|
||||||
search = params[:search].to_s.downcase
|
if params[:search].present?
|
||||||
user_condition_users = User.like(search).to_sql
|
search = params[:search].to_s.downcase
|
||||||
team_condition_teams = User.joins(:teams).merge(@organization.teams.like(search)).to_sql
|
user_condition_users = User.like(search).to_sql
|
||||||
users = User.from("( #{user_condition_users} UNION #{team_condition_teams }) AS users")
|
team_condition_teams = User.joins(:teams).merge(@organization.teams.like(search)).to_sql
|
||||||
|
users = User.from("( #{user_condition_users} UNION #{team_condition_teams }) AS users")
|
||||||
@organization_users = @organization_users.where(user_id: users).distinct
|
|
||||||
|
@organization_users = @organization_users.where(user_id: users).distinct
|
||||||
|
end
|
||||||
|
|
||||||
@organization_users = kaminari_paginate(@organization_users)
|
@organization_users = kaminari_paginate(@organization_users)
|
||||||
end
|
end
|
||||||
|
|
|
@ -31,6 +31,7 @@ class Organizations::OrganizationsController < Organizations::BaseController
|
||||||
Organizations::CreateForm.new(organization_params.merge(original_name: "")).validate!
|
Organizations::CreateForm.new(organization_params.merge(original_name: "")).validate!
|
||||||
@organization = Organizations::CreateService.call(current_user, organization_params)
|
@organization = Organizations::CreateService.call(current_user, organization_params)
|
||||||
Util.write_file(@image, avatar_path(@organization)) if params[:image].present?
|
Util.write_file(@image, avatar_path(@organization)) if params[:image].present?
|
||||||
|
Cache::V2::OwnerCommonService.new(@organization.id).reset
|
||||||
end
|
end
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
uid_logger_error(e.message)
|
uid_logger_error(e.message)
|
||||||
|
@ -48,6 +49,7 @@ class Organizations::OrganizationsController < Organizations::BaseController
|
||||||
|
|
||||||
Gitea::Organization::UpdateService.call(current_user.gitea_token, login, @organization.reload)
|
Gitea::Organization::UpdateService.call(current_user.gitea_token, login, @organization.reload)
|
||||||
Util.write_file(@image, avatar_path(@organization)) if params[:image].present?
|
Util.write_file(@image, avatar_path(@organization)) if params[:image].present?
|
||||||
|
Cache::V2::OwnerCommonService.new(@organization.id).reset
|
||||||
end
|
end
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
uid_logger_error(e.message)
|
uid_logger_error(e.message)
|
||||||
|
|
|
@ -21,6 +21,17 @@ class Organizations::TeamProjectsController < Organizations::BaseController
|
||||||
tip_exception(e.message)
|
tip_exception(e.message)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def create_all
|
||||||
|
tip_exception("该组织团队项目包括组织所有项目,不允许更改") if @team.includes_all_project
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
@organization.projects.each do |project|
|
||||||
|
TeamProject.build(@organization.id, @team.id, project.id)
|
||||||
|
end
|
||||||
|
Gitea::Organization::TeamProject::CreateAllService.call(@organization.gitea_token, @team.gtid, @organization.login)
|
||||||
|
render_ok
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
tip_exception("该组织团队项目包括组织所有项目,不允许更改") if @team.includes_all_project
|
tip_exception("该组织团队项目包括组织所有项目,不允许更改") if @team.includes_all_project
|
||||||
ActiveRecord::Base.transaction do
|
ActiveRecord::Base.transaction do
|
||||||
|
@ -33,6 +44,17 @@ class Organizations::TeamProjectsController < Organizations::BaseController
|
||||||
tip_exception(e.message)
|
tip_exception(e.message)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def destroy_all
|
||||||
|
tip_exception("该组织团队项目包括组织所有项目,不允许更改") if @team.includes_all_project
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
@team.team_projects.each do |project|
|
||||||
|
project.destroy!
|
||||||
|
end
|
||||||
|
Gitea::Organization::TeamProject::DeleteAllService.call(@organization.gitea_token, @team.gtid, @organization.login)
|
||||||
|
render_ok
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def load_organization
|
def load_organization
|
||||||
@organization = Organization.find_by(login: params[:organization_id]) || Organization.find_by(id: params[:organization_id])
|
@organization = Organization.find_by(login: params[:organization_id]) || Organization.find_by(id: params[:organization_id])
|
||||||
|
@ -47,7 +69,7 @@ class Organizations::TeamProjectsController < Organizations::BaseController
|
||||||
end
|
end
|
||||||
|
|
||||||
def load_operate_project
|
def load_operate_project
|
||||||
@operate_project = Project.find_by(id: project_mark) || Project.find_by(identifier: project_mark)
|
@operate_project = @organization.projects.where(id: project_mark).take || @organization.projects.where(identifier: project_mark).take
|
||||||
tip_exception("项目不存在") if @operate_project.nil?
|
tip_exception("项目不存在") if @operate_project.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ class Projects::WebhooksController < Projects::BaseController
|
||||||
|
|
||||||
def create
|
def create
|
||||||
ActiveRecord::Base.transaction do
|
ActiveRecord::Base.transaction do
|
||||||
return render_error("webhooks数量已到上限!请删除暂不使用的webhooks以进行添加操作") if @project.webhooks.size > 19
|
return render_error("webhooks数量已到上限!请删除暂不使用的webhooks以进行添加操作") if @project.webhooks.size > 49
|
||||||
return render_error("参数错误.") unless webhook_params.present?
|
return render_error("参数错误.") unless webhook_params.present?
|
||||||
form = Projects::Webhooks::CreateForm.new(webhook_params)
|
form = Projects::Webhooks::CreateForm.new(webhook_params)
|
||||||
return render json: {status: -1, message: form.errors} unless form.validate!
|
return render json: {status: -1, message: form.errors} unless form.validate!
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
class PublicKeysController < ApplicationController
|
class PublicKeysController < ApplicationController
|
||||||
before_action :require_login
|
before_action :require_login_cloud_ide_saas
|
||||||
before_action :find_public_key, only: [:destroy]
|
before_action :find_public_key, only: [:destroy]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
@ -61,4 +61,6 @@ class PublicKeysController < ApplicationController
|
||||||
def find_public_key
|
def find_public_key
|
||||||
@public_key = current_user.public_keys.find_by_id(params[:id])
|
@public_key = current_user.public_keys.find_by_id(params[:id])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
|
@ -67,6 +67,8 @@ class PullRequestsController < ApplicationController
|
||||||
@pull_request, @gitea_pull_request = PullRequests::CreateService.call(current_user, @owner, @project, params)
|
@pull_request, @gitea_pull_request = PullRequests::CreateService.call(current_user, @owner, @project, params)
|
||||||
if @gitea_pull_request[:status] == :success
|
if @gitea_pull_request[:status] == :success
|
||||||
@pull_request.bind_gitea_pull_request!(@gitea_pull_request[:body]["number"], @gitea_pull_request[:body]["id"])
|
@pull_request.bind_gitea_pull_request!(@gitea_pull_request[:body]["number"], @gitea_pull_request[:body]["id"])
|
||||||
|
reviewers = User.where(id: params[:reviewer_ids])
|
||||||
|
@pull_request.reviewers = reviewers
|
||||||
SendTemplateMessageJob.perform_later('PullRequestAssigned', current_user.id, @pull_request&.id) if Site.has_notice_menu?
|
SendTemplateMessageJob.perform_later('PullRequestAssigned', current_user.id, @pull_request&.id) if Site.has_notice_menu?
|
||||||
SendTemplateMessageJob.perform_later('ProjectPullRequest', current_user.id, @pull_request&.id) if Site.has_notice_menu?
|
SendTemplateMessageJob.perform_later('ProjectPullRequest', current_user.id, @pull_request&.id) if Site.has_notice_menu?
|
||||||
Rails.logger.info "[ATME] maybe to at such users: #{@atme_receivers.pluck(:login)}"
|
Rails.logger.info "[ATME] maybe to at such users: #{@atme_receivers.pluck(:login)}"
|
||||||
|
@ -112,6 +114,9 @@ class PullRequestsController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
reviewers = User.where(id: params[:reviewer_ids])
|
||||||
|
@pull_request.reviewers = reviewers
|
||||||
|
|
||||||
if @issue.update_attributes(@issue_params)
|
if @issue.update_attributes(@issue_params)
|
||||||
if @pull_request.update_attributes(@local_params.compact)
|
if @pull_request.update_attributes(@local_params.compact)
|
||||||
gitea_pull = Gitea::PullRequest::UpdateService.call(@owner.login, @repository.identifier,
|
gitea_pull = Gitea::PullRequest::UpdateService.call(@owner.login, @repository.identifier,
|
||||||
|
@ -181,7 +186,7 @@ class PullRequestsController < ApplicationController
|
||||||
@issue_assign_to = @issue.get_assign_user
|
@issue_assign_to = @issue.get_assign_user
|
||||||
@gitea_pull = Gitea::PullRequest::GetService.call(@owner.login,
|
@gitea_pull = Gitea::PullRequest::GetService.call(@owner.login,
|
||||||
@repository.identifier, @pull_request.gitea_number, current_user&.gitea_token)
|
@repository.identifier, @pull_request.gitea_number, current_user&.gitea_token)
|
||||||
@last_review = @pull_request.issue.reviews.take
|
@last_review = @pull_request.reviews.take
|
||||||
end
|
end
|
||||||
|
|
||||||
def pr_merge
|
def pr_merge
|
||||||
|
@ -268,7 +273,7 @@ class PullRequestsController < ApplicationController
|
||||||
|
|
||||||
def get_relatived
|
def get_relatived
|
||||||
@project_tags = @project.issue_tags&.select(:id,:name, :color).as_json
|
@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_members = @project.all_developers
|
||||||
@project_priories = IssuePriority&.select(:id,:name, :position).as_json
|
@project_priories = IssuePriority&.select(:id,:name, :position).as_json
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,391 +1,407 @@
|
||||||
class RepositoriesController < ApplicationController
|
class RepositoriesController < ApplicationController
|
||||||
include RepositoriesHelper
|
include RepositoriesHelper
|
||||||
include ApplicationHelper
|
include ApplicationHelper
|
||||||
include OperateProjectAbilityAble
|
include OperateProjectAbilityAble
|
||||||
include Repository::LanguagesPercentagable
|
include Repository::LanguagesPercentagable
|
||||||
|
|
||||||
before_action :require_login, only: %i[edit update create_file update_file delete_file sync_mirror]
|
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 :require_profile_completed, only: [:create_file]
|
||||||
before_action :load_repository
|
before_action :load_repository
|
||||||
before_action :authorizate!, except: [:sync_mirror, :tags, :commit, :archive]
|
before_action :authorizate!, except: [:sync_mirror, :tags, :commit, :archive]
|
||||||
before_action :authorizate_user_can_edit_repo!, only: %i[sync_mirror]
|
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_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_latest_commit, only: %i[entries sub_entries top_counts]
|
||||||
before_action :get_statistics, only: %i[top_counts]
|
before_action :get_statistics, only: %i[top_counts]
|
||||||
|
|
||||||
def files
|
def files
|
||||||
result = @project.educoder? ? nil : Gitea::Repository::Files::GetService.call(@owner, @project.identifier, @ref, params[:search], @owner.gitea_token)
|
result = @project.educoder? ? nil : Gitea::Repository::Files::GetService.call(@owner, @project.identifier, @ref, params[:search], @owner.gitea_token)
|
||||||
render json: result
|
render json: result
|
||||||
end
|
end
|
||||||
|
|
||||||
# 新版项目详情
|
# 新版项目详情
|
||||||
def detail
|
def detail
|
||||||
@user = current_user
|
@user = current_user
|
||||||
@result = Repositories::DetailService.call(@owner, @repository, @user)
|
@result = Repositories::DetailService.call(@owner, @repository, @user)
|
||||||
@project_fork_id = @project.try(:forked_from_project_id)
|
@project_fork_id = @project.try(:forked_from_project_id)
|
||||||
if @project_fork_id.present?
|
if @project_fork_id.present?
|
||||||
@fork_project = Project.find_by(id: @project_fork_id)
|
@fork_project = Project.find_by(id: @project_fork_id)
|
||||||
@fork_project_user = @fork_project.owner
|
@fork_project_user = @fork_project.owner
|
||||||
end
|
end
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
uid_logger_error(e.message)
|
uid_logger_error(e.message)
|
||||||
tip_exception(e.message)
|
tip_exception(e.message)
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@user = current_user
|
@user = current_user
|
||||||
@repo = @project.repository
|
@repo = @project.repository
|
||||||
@result = @project.forge? ? Gitea::Repository::GetService.new(@owner, @project.identifier).call : nil
|
@result = @project.forge? ? Gitea::Repository::GetService.new(@owner, @project.identifier).call : nil
|
||||||
@project_fork_id = @project.try(:forked_from_project_id)
|
@project_fork_id = @project.try(:forked_from_project_id)
|
||||||
if @project_fork_id.present?
|
if @project_fork_id.present?
|
||||||
@fork_project = Project.find_by(id: @project_fork_id)
|
@fork_project = Project.find_by(id: @project_fork_id)
|
||||||
@fork_project_user = @fork_project.owner
|
@fork_project_user = @fork_project.owner
|
||||||
end
|
end
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
uid_logger_error(e.message)
|
uid_logger_error(e.message)
|
||||||
tip_exception(e.message)
|
tip_exception(e.message)
|
||||||
end
|
end
|
||||||
|
|
||||||
def entries
|
def entries
|
||||||
@project.increment!(:visits)
|
@week_project_visit_record, @month_project_visit_record = TimeableVisitRecord.build(@project.id)
|
||||||
CacheAsyncSetJob.perform_later("project_common_service", {visits: 1}, @project.id)
|
if @week_project_visit_record.visits < 300 && @month_project_visit_record.visits < 1000
|
||||||
if @project.educoder?
|
@week_project_visit_record.increment!(:visits)
|
||||||
@entries = Educoder::Repository::Entries::ListService.call(@project&.project_educoder.repo_name)
|
@month_project_visit_record.increment!(:visits)
|
||||||
else
|
@project.increment!(:visits)
|
||||||
@entries = Gitea::Repository::Entries::ListService.new(@owner, @project.identifier, ref: @ref).call
|
CacheAsyncSetJob.perform_later("project_common_service", {visits: 1}, @project.id)
|
||||||
@entries = @entries.present? ? @entries.sort_by{ |hash| hash['type'] } : []
|
end
|
||||||
@path = GiteaService.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/"
|
if @project.educoder?
|
||||||
end
|
@entries = Educoder::Repository::Entries::ListService.call(@project&.project_educoder.repo_name)
|
||||||
end
|
else
|
||||||
|
@entries = Gitea::Repository::Entries::ListService.new(@owner, @project.identifier, ref: @ref).call
|
||||||
def top_counts
|
@entries = @entries.present? ? @entries.sort_by{ |hash| hash['type'] } : []
|
||||||
@result = @project.educoder? ? nil : Gitea::Repository::GetService.new(@project.owner, @project.identifier).call
|
@path = GiteaService.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/"
|
||||||
end
|
end
|
||||||
|
end
|
||||||
def sub_entries
|
|
||||||
file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip))
|
def top_counts
|
||||||
|
@result = @project.educoder? ? nil : Gitea::Repository::GetService.new(@project.owner, @project.identifier).call
|
||||||
if @project.educoder?
|
end
|
||||||
if params[:type] === 'file'
|
|
||||||
@sub_entries = Educoder::Repository::Entries::GetService.call(@project&.project_educoder&.repo_name, file_path_uri)
|
def sub_entries
|
||||||
logger.info "######### sub_entries: #{@sub_entries}"
|
file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip))
|
||||||
return render_error('该文件暂未开放,敬请期待.') if @sub_entries['status'].to_i === -1
|
|
||||||
|
if @project.educoder?
|
||||||
tmp_entries = {
|
if params[:type] === 'file'
|
||||||
"content" => @sub_entries['data']['content'],
|
@sub_entries = Educoder::Repository::Entries::GetService.call(@project&.project_educoder&.repo_name, file_path_uri)
|
||||||
"type" => "blob"
|
logger.info "######### sub_entries: #{@sub_entries}"
|
||||||
}
|
return render_error('该文件暂未开放,敬请期待.') if @sub_entries['status'].to_i === -1
|
||||||
@sub_entries = {
|
|
||||||
"trees"=>tmp_entries,
|
tmp_entries = {
|
||||||
"commits" => [{}]
|
"content" => @sub_entries['data']['content'],
|
||||||
}
|
"type" => "blob"
|
||||||
else
|
}
|
||||||
begin
|
@sub_entries = {
|
||||||
@sub_entries = Educoder::Repository::Entries::ListService.call(@project&.project_educoder&.repo_name, {path: file_path_uri})
|
"trees"=>tmp_entries,
|
||||||
if @sub_entries.blank? || @sub_entries['status'].to_i === -1
|
"commits" => [{}]
|
||||||
@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
|
else
|
||||||
tmp_entries = {
|
begin
|
||||||
"content" => @sub_entries['data']['content'],
|
@sub_entries = Educoder::Repository::Entries::ListService.call(@project&.project_educoder&.repo_name, {path: file_path_uri})
|
||||||
"type" => "blob"
|
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)
|
||||||
@sub_entries = {
|
return render_error('该文件暂未开放,敬请期待.') if @sub_entries['status'].to_i === -1
|
||||||
"trees"=>tmp_entries,
|
tmp_entries = {
|
||||||
"commits" => [{}]
|
"content" => @sub_entries['data']['content'],
|
||||||
}
|
"type" => "blob"
|
||||||
end
|
}
|
||||||
rescue
|
@sub_entries = {
|
||||||
return render_error('该文件暂未开放,敬请期待.')
|
"trees"=>tmp_entries,
|
||||||
end
|
"commits" => [{}]
|
||||||
end
|
}
|
||||||
else
|
end
|
||||||
@path = GiteaService.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/"
|
rescue
|
||||||
interactor = Repositories::EntriesInteractor.call(@owner, @project.identifier, file_path_uri, ref: @ref)
|
return render_error('该文件暂未开放,敬请期待.')
|
||||||
if interactor.success?
|
end
|
||||||
result = interactor.result
|
end
|
||||||
@sub_entries = result.is_a?(Array) ? result.sort_by{ |hash| hash['type'] } : result
|
else
|
||||||
else
|
@path = GiteaService.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/"
|
||||||
render_error(interactor.error)
|
interactor = Repositories::EntriesInteractor.call(@owner, @project.identifier, file_path_uri, ref: @ref)
|
||||||
end
|
if interactor.success?
|
||||||
end
|
result = interactor.result
|
||||||
end
|
@sub_entries = result.is_a?(Array) ? result.sort_by{ |hash| hash['type'] } : result
|
||||||
|
else
|
||||||
def commits
|
render_error(interactor.error)
|
||||||
if @project.educoder?
|
end
|
||||||
@commits = Educoder::Repository::Commits::ListService.call(@project&.project_educoder&.repo_name)
|
end
|
||||||
else
|
end
|
||||||
if params[:filepath].present?
|
|
||||||
file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip))
|
def commits
|
||||||
@hash_commit = Gitea::Repository::Commits::FileListService.new(@owner.login, @project.identifier, file_path_uri,
|
if @project.educoder?
|
||||||
sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token).call
|
@commits = Educoder::Repository::Commits::ListService.call(@project&.project_educoder&.repo_name)
|
||||||
else
|
else
|
||||||
@hash_commit = Gitea::Repository::Commits::ListService.new(@owner.login, @project.identifier,
|
if params[:filepath].present?
|
||||||
sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token).call
|
file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip))
|
||||||
end
|
@hash_commit = Gitea::Repository::Commits::FileListService.new(@owner.login, @project.identifier, file_path_uri,
|
||||||
end
|
sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token).call
|
||||||
end
|
else
|
||||||
|
@hash_commit = Gitea::Repository::Commits::ListService.new(@owner.login, @project.identifier,
|
||||||
def commits_slice
|
sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token).call
|
||||||
@hash_commit = Gitea::Repository::Commits::ListSliceService.call(@owner.login, @project.identifier,
|
end
|
||||||
sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token)
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def commit
|
def commits_slice
|
||||||
@sha = params[:sha]
|
@hash_commit = Gitea::Repository::Commits::ListSliceService.call(@owner.login, @project.identifier,
|
||||||
if @project.educoder?
|
sha: params[:sha], page: params[:page], limit: params[:limit], token: current_user&.gitea_token)
|
||||||
return render_error('暂未开放,敬请期待.')
|
end
|
||||||
else
|
|
||||||
@commit = Gitea::Repository::Commits::GetService.call(@owner.login, @repository.identifier, @sha, current_user&.gitea_token)
|
def commit
|
||||||
@commit_diff = Gitea::Repository::Commits::GetService.call(@owner.login, @repository.identifier, @sha, current_user&.gitea_token, {diff: true})
|
@sha = params[:sha]
|
||||||
end
|
if @project.educoder?
|
||||||
end
|
return render_error('暂未开放,敬请期待.')
|
||||||
|
else
|
||||||
def tags
|
@commit = Gitea::Repository::Commits::GetService.call(@owner.login, @repository.identifier, @sha, current_user&.gitea_token)
|
||||||
result = Gitea::Repository::Tags::ListService.call(current_user&.gitea_token, @owner.login, @project.identifier, {page: params[:page], limit: params[:limit]})
|
@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)
|
||||||
@tags = result.is_a?(Hash) && result.key?(:status) ? [] : result
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def contributors
|
def tags
|
||||||
if params[:filepath].present? || @project.educoder?
|
if params[:only_name].present?
|
||||||
@contributors = []
|
result = Gitea::Repository::Tags::ListNameService.call(@owner, @project.identifier, params[:name])
|
||||||
else
|
|
||||||
result = Gitea::Repository::Contributors::GetService.call(@owner, @repository.identifier)
|
@tags = result.is_a?(Hash) && result.key?(:status) ? [] : result
|
||||||
@contributors = result.is_a?(Hash) && result.key?(:status) ? [] : result
|
else
|
||||||
end
|
name_result = Gitea::Repository::Tags::ListNameService.call(@owner, @project.identifier, params[:name])
|
||||||
rescue
|
|
||||||
@contributors = []
|
@tag_names = result.is_a?(Hash) && result.key?(:status) ? [] : name_result
|
||||||
end
|
|
||||||
|
result = Gitea::Repository::Tags::ListService.call(current_user&.gitea_token, @owner.login, @project.identifier, {page: params[:page], limit: params[:limit]})
|
||||||
def edit
|
|
||||||
return render_forbidden if !@project.manager?(current_user) && !current_user.admin?
|
@tags = result.is_a?(Hash) && result.key?(:status) ? [] : result
|
||||||
end
|
end
|
||||||
|
end
|
||||||
def create_file
|
|
||||||
interactor = Gitea::CreateFileInteractor.call(current_user.gitea_token, @owner.login, content_params)
|
def contributors
|
||||||
if interactor.success?
|
if params[:filepath].present? || @project.educoder?
|
||||||
@file = interactor.result
|
@contributors = []
|
||||||
# create_new_pr(params)
|
else
|
||||||
#如果是更新流水线文件
|
result = Gitea::Repository::Contributors::GetService.call(@owner, @repository.identifier)
|
||||||
if params[:pipeline_id]
|
@contributors = result.is_a?(Hash) && result.key?(:status) ? [] : result
|
||||||
update_pipeline(params[:pipeline_id])
|
end
|
||||||
end
|
rescue
|
||||||
else
|
@contributors = []
|
||||||
render_error(interactor.error)
|
end
|
||||||
end
|
|
||||||
end
|
def edit
|
||||||
|
return render_forbidden if !@project.manager?(current_user) && !current_user.admin?
|
||||||
def update_pipeline(pipeline_id)
|
end
|
||||||
pipeline = Ci::Pipeline.find(pipeline_id)
|
|
||||||
if pipeline
|
def create_file
|
||||||
pipeline.update!(sync: 1)
|
interactor = Gitea::CreateFileInteractor.call(current_user.gitea_token, @owner.login, content_params)
|
||||||
end
|
if interactor.success?
|
||||||
end
|
@file = interactor.result
|
||||||
|
# create_new_pr(params)
|
||||||
def update_file
|
#如果是更新流水线文件
|
||||||
interactor = Gitea::UpdateFileInteractor.call(current_user.gitea_token, @owner.login, params.merge(identifier: @project.identifier))
|
if params[:pipeline_id]
|
||||||
if interactor.success?
|
update_pipeline(params[:pipeline_id])
|
||||||
@file = interactor.result
|
end
|
||||||
# TODO: 是否创建pr
|
else
|
||||||
# create_new_pr(params)
|
render_error(interactor.error)
|
||||||
render_result(1, "更新成功")
|
end
|
||||||
else
|
end
|
||||||
render_error(interactor.error)
|
|
||||||
end
|
def update_pipeline(pipeline_id)
|
||||||
end
|
pipeline = Ci::Pipeline.find(pipeline_id)
|
||||||
|
if pipeline
|
||||||
def delete_file
|
pipeline.update!(sync: 1)
|
||||||
interactor = Gitea::DeleteFileInteractor.call(current_user.gitea_token, @owner.login, params.merge(identifier: @project.identifier))
|
end
|
||||||
if interactor.success?
|
end
|
||||||
@file = interactor.result
|
|
||||||
render_result(1, "文件删除成功")
|
def update_file
|
||||||
else
|
interactor = Gitea::UpdateFileInteractor.call(current_user.gitea_token, @owner.login, params.merge(identifier: @project.identifier))
|
||||||
render_error(interactor.error)
|
if interactor.success?
|
||||||
end
|
@file = interactor.result
|
||||||
end
|
# TODO: 是否创建pr
|
||||||
|
# create_new_pr(params)
|
||||||
def repo_hook
|
render_result(1, "更新成功")
|
||||||
|
else
|
||||||
end
|
render_error(interactor.error)
|
||||||
|
end
|
||||||
def sync_mirror
|
end
|
||||||
return render_error("正在镜像中..") if @repository.mirror.waiting?
|
|
||||||
|
def delete_file
|
||||||
@repository.sync_mirror!
|
interactor = Gitea::DeleteFileInteractor.call(current_user.gitea_token, @owner.login, params.merge(identifier: @project.identifier))
|
||||||
SyncMirroredRepositoryJob.perform_later(@repository.id, current_user.id)
|
if interactor.success?
|
||||||
render_ok
|
@file = interactor.result
|
||||||
end
|
render_result(1, "文件删除成功")
|
||||||
|
else
|
||||||
def readme
|
render_error(interactor.error)
|
||||||
if params[:filepath].present?
|
end
|
||||||
result = Gitea::Repository::Readme::DirService.call(@owner.login, @repository.identifier, params[:filepath], params[:ref], current_user&.gitea_token)
|
end
|
||||||
else
|
|
||||||
result = Gitea::Repository::Readme::GetService.call(@owner.login, @repository.identifier, params[:ref], current_user&.gitea_token)
|
def repo_hook
|
||||||
end
|
|
||||||
@path = GiteaService.gitea_config[:domain]+"/#{@owner.login}/#{@repository.identifier}/raw/branch/#{params[:ref]}/"
|
end
|
||||||
@readme = result[:status] === :success ? result[:body] : nil
|
|
||||||
@readme['content'] = decode64_content(@readme, @owner, @repository, params[:ref], @path)
|
def sync_mirror
|
||||||
@readme['replace_content'] = readme_decode64_content(@readme, @owner, @repository, params[:ref], @path)
|
return render_error("正在镜像中..") if @repository.mirror.waiting?
|
||||||
render json: @readme.slice("type", "encoding", "size", "name", "path", "content", "sha", "replace_content")
|
|
||||||
rescue
|
@repository.sync_mirror!
|
||||||
render json: nil
|
SyncMirroredRepositoryJob.perform_later(@repository.id, current_user.id)
|
||||||
end
|
render_ok
|
||||||
|
end
|
||||||
def languages
|
|
||||||
if @project.educoder?
|
def readme
|
||||||
render json: {}
|
if params[:filepath].present?
|
||||||
else
|
result = Gitea::Repository::Readme::DirService.call(@owner.login, @repository.identifier, params[:filepath], params[:ref], current_user&.gitea_token)
|
||||||
render json: languages_precentagable
|
else
|
||||||
end
|
result = Gitea::Repository::Readme::GetService.call(@owner.login, @repository.identifier, params[:ref], current_user&.gitea_token)
|
||||||
end
|
end
|
||||||
|
@path = GiteaService.gitea_config[:domain]+"/#{@owner.login}/#{@repository.identifier}/raw/branch/#{params[:ref]}/"
|
||||||
def archive
|
@readme = result[:status] === :success ? result[:body] : nil
|
||||||
domain = GiteaService.gitea_config[:domain]
|
@readme['content'] = decode64_content(@readme, @owner, @repository, params[:ref], @path)
|
||||||
api_url = GiteaService.gitea_config[:base_url]
|
@readme['replace_content'] = readme_decode64_content(@readme, @owner, @repository, params[:ref], @path)
|
||||||
archive_url = "/repos/#{@owner.login}/#{@repository.identifier}/archive/#{Addressable::URI.escape(params[:archive])}"
|
render json: @readme.slice("type", "encoding", "size", "name", "path", "content", "sha", "replace_content")
|
||||||
|
rescue
|
||||||
file_path = [domain, api_url, archive_url].join
|
render json: nil
|
||||||
file_path = [file_path, "access_token=#{current_user&.gitea_token}"].join("?") if @repository.hidden?
|
end
|
||||||
|
|
||||||
return render_not_found if !request.format.zip? && !request.format.gzip?
|
def languages
|
||||||
|
if @project.educoder?
|
||||||
redirect_to file_path
|
render json: {}
|
||||||
end
|
else
|
||||||
|
render json: languages_precentagable
|
||||||
def raw
|
end
|
||||||
domain = GiteaService.gitea_config[:domain]
|
end
|
||||||
api_url = GiteaService.gitea_config[:base_url]
|
|
||||||
|
def archive
|
||||||
url = "/repos/#{@owner.login}/#{@repository.identifier}/raw/#{Addressable::URI.escape(params[:filepath])}?ref=#{Addressable::URI.escape(params[:ref])}"
|
domain = GiteaService.gitea_config[:domain]
|
||||||
file_path = [domain, api_url, url].join
|
api_url = GiteaService.gitea_config[:base_url]
|
||||||
file_path = [file_path, "access_token=#{current_user&.gitea_token}"].join("&")
|
archive_url = "/repos/#{@owner.login}/#{@repository.identifier}/archive/#{Addressable::URI.escape(params[:archive])}"
|
||||||
|
|
||||||
redirect_to file_path
|
file_path = [domain, api_url, archive_url].join
|
||||||
end
|
file_path = [file_path, "access_token=#{current_user&.gitea_token}"].join("?") if @repository.hidden?
|
||||||
|
|
||||||
private
|
return render_not_found if !request.format.zip? && !request.format.gzip?
|
||||||
|
|
||||||
def find_project
|
redirect_to file_path
|
||||||
@project = Project.find params[:id]
|
end
|
||||||
render_not_found("未找到相关的仓库") unless @project
|
|
||||||
end
|
def raw
|
||||||
|
domain = GiteaService.gitea_config[:domain]
|
||||||
def find_project_with_includes
|
api_url = GiteaService.gitea_config[:base_url]
|
||||||
@project = Project.includes(:repository, :owner, :watchers, :praise_treads).find params[:id]
|
|
||||||
end
|
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
|
||||||
def authorizate!
|
file_path = [file_path, "access_token=#{current_user&.gitea_token}"].join("&")
|
||||||
return if current_user && current_user.admin?
|
|
||||||
if @project.repository.hidden? && !@project.member?(current_user)
|
redirect_to file_path
|
||||||
render_forbidden
|
end
|
||||||
end
|
|
||||||
end
|
private
|
||||||
|
|
||||||
# TODO 获取最新commit信息
|
def find_project
|
||||||
def project_commits
|
@project = Project.find params[:id]
|
||||||
if params[:filepath].present?
|
render_not_found("未找到相关的仓库") unless @project
|
||||||
file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip))
|
end
|
||||||
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
|
def find_project_with_includes
|
||||||
else
|
@project = Project.includes(:repository, :owner, :watchers, :praise_treads).find params[:id]
|
||||||
Gitea::Repository::Commits::ListService.new(@project.owner.login, @project.identifier,
|
end
|
||||||
sha: get_ref, page: 1, limit: 1, token: current_user&.gitea_token).call
|
|
||||||
end
|
def authorizate!
|
||||||
end
|
return if current_user && current_user.admin?
|
||||||
|
if @project.repository.hidden? && !@project.member?(current_user)
|
||||||
def get_statistics
|
render_forbidden
|
||||||
@branches_count = @project.educoder? ? 0 : Gitea::Repository::Branches::ListService.new(@project.owner, @project.identifier).call&.size
|
end
|
||||||
@tags_count = @project.educoder? ? 0 : Gitea::Repository::Tags::ListService.new(current_user&.gitea_token, @project.owner.login, @project.identifier).call&.size
|
end
|
||||||
end
|
|
||||||
|
# TODO 获取最新commit信息
|
||||||
def get_ref
|
def project_commits
|
||||||
@ref = params[:ref] || @project&.default_branch
|
if params[:filepath].present?
|
||||||
end
|
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,
|
||||||
def get_latest_commit
|
sha: get_ref, page: 1, limit: 1, token: current_user&.gitea_token).call
|
||||||
latest_commit = @project.educoder? ? nil : project_commits
|
else
|
||||||
@latest_commit = latest_commit.present? ? latest_commit[:body][0] : nil
|
Gitea::Repository::Commits::ListService.new(@project.owner.login, @project.identifier,
|
||||||
@commits_count = latest_commit.present? ? latest_commit[:total_count] : 0
|
sha: get_ref, page: 1, limit: 1, token: current_user&.gitea_token).call
|
||||||
end
|
end
|
||||||
|
end
|
||||||
def content_params
|
|
||||||
{
|
def get_statistics
|
||||||
filepath: params[:filepath],
|
@branches_count = @project.educoder? ? 0 : Gitea::Repository::Branches::ListService.new(@project.owner, @project.identifier).call&.size
|
||||||
branch: params[:branch],
|
@tags_count = @project.educoder? ? 0 : Gitea::Repository::Tags::ListService.new(current_user&.gitea_token, @project.owner.login, @project.identifier).call&.size
|
||||||
new_branch: params[:new_branch],
|
end
|
||||||
content: params[:content],
|
|
||||||
message: params[:message],
|
def get_ref
|
||||||
committer: {
|
@ref = params[:ref] || @project&.default_branch
|
||||||
email: current_user.mail,
|
end
|
||||||
name: current_user.login
|
|
||||||
},
|
def get_latest_commit
|
||||||
identifier: @project.identifier
|
latest_commit = @project.educoder? ? nil : project_commits
|
||||||
}
|
@latest_commit = latest_commit.present? ? latest_commit[:body][0] : nil
|
||||||
end
|
@commits_count = latest_commit.present? ? latest_commit[:total_count] : 0
|
||||||
|
end
|
||||||
def hook_params(hook_type, params)
|
|
||||||
# if hook_type == "push"
|
def content_params
|
||||||
# # TODO hook返回的记录中,暂时没有文件代码数量的增减,暂时根据 commits数量来计算
|
{
|
||||||
# uploadPushInfo = {
|
filepath: params[:filepath],
|
||||||
# "sha": params["commits"].present? ? params["commits"].last : "",
|
branch: params[:branch],
|
||||||
# "branch": params["ref"].to_s.split("/").last,
|
new_branch: params[:new_branch],
|
||||||
# "modification_lines": params["commits"].length
|
content: params[:content],
|
||||||
# }
|
message: params[:message],
|
||||||
# elsif hook_type == "pull_request" && params["action"].to_s == "closed" #合并请求合并后才会有上链操作
|
committer: {
|
||||||
# uploadPushInfo = {
|
email: current_user.mail,
|
||||||
# "branch": params["base"]["ref"].to_s.split("/").last,
|
name: current_user.login
|
||||||
# "sha": params["pull_request"]["merge_base"],
|
},
|
||||||
# "modification_lines": 1 #pull_request中没有commits数量
|
identifier: @project.identifier
|
||||||
# }
|
}
|
||||||
# else
|
end
|
||||||
# uploadPushInfo = {}
|
|
||||||
# end
|
def hook_params(hook_type, params)
|
||||||
|
# if hook_type == "push"
|
||||||
# uploadPushInfo
|
# # TODO hook返回的记录中,暂时没有文件代码数量的增减,暂时根据 commits数量来计算
|
||||||
end
|
# uploadPushInfo = {
|
||||||
|
# "sha": params["commits"].present? ? params["commits"].last : "",
|
||||||
def create_new_pr(params)
|
# "branch": params["ref"].to_s.split("/").last,
|
||||||
if params[:new_branch].present? && params[:new_branch] != params[:branch]
|
# "modification_lines": params["commits"].length
|
||||||
local_params = {
|
# }
|
||||||
title: params[:message], #标题
|
# elsif hook_type == "pull_request" && params["action"].to_s == "closed" #合并请求合并后才会有上链操作
|
||||||
body: params[:content], #内容
|
# uploadPushInfo = {
|
||||||
head: params[:new_branch], #源分支
|
# "branch": params["base"]["ref"].to_s.split("/").last,
|
||||||
base: params[:branch], #目标分支
|
# "sha": params["pull_request"]["merge_base"],
|
||||||
milestone: 0 #里程碑,未与本地的里程碑关联
|
# "modification_lines": 1 #pull_request中没有commits数量
|
||||||
|
# }
|
||||||
}
|
# else
|
||||||
requests_params = local_params.merge({
|
# uploadPushInfo = {}
|
||||||
assignee: current_user.try(:login),
|
# end
|
||||||
assignees: [],
|
|
||||||
labels: [],
|
# uploadPushInfo
|
||||||
due_date: Time.now
|
end
|
||||||
})
|
|
||||||
|
def create_new_pr(params)
|
||||||
issue_params = {
|
if params[:new_branch].present? && params[:new_branch] != params[:branch]
|
||||||
author_id: current_user.id,
|
local_params = {
|
||||||
project_id: @project.id,
|
title: params[:message], #标题
|
||||||
subject: params[:message],
|
body: params[:content], #内容
|
||||||
description: params[:content],
|
head: params[:new_branch], #源分支
|
||||||
assigned_to_id: nil,
|
base: params[:branch], #目标分支
|
||||||
fixed_version_id: nil,
|
milestone: 0 #里程碑,未与本地的里程碑关联
|
||||||
issue_tags_value: nil,
|
|
||||||
issue_classify: "pull_request",
|
}
|
||||||
issue_type: "1",
|
requests_params = local_params.merge({
|
||||||
tracker_id: 2,
|
assignee: current_user.try(:login),
|
||||||
status_id: 1,
|
assignees: [],
|
||||||
priority_id: params[:priority_id] || "2"
|
labels: [],
|
||||||
}
|
due_date: Time.now
|
||||||
@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))
|
issue_params = {
|
||||||
if local_requests.save
|
author_id: current_user.id,
|
||||||
gitea_request = Gitea::PullRequest::CreateService.new(current_user.try(:gitea_token), @owner.login, @project.try(:identifier), requests_params).call
|
project_id: @project.id,
|
||||||
if gitea_request[:status] == :success && local_requests.update_attributes(gpid: gitea_request["body"]["number"])
|
subject: params[:message],
|
||||||
local_requests.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create")
|
description: params[:content],
|
||||||
end
|
assigned_to_id: nil,
|
||||||
end
|
fixed_version_id: nil,
|
||||||
end
|
issue_tags_value: nil,
|
||||||
end
|
issue_classify: "pull_request",
|
||||||
end
|
issue_type: "1",
|
||||||
|
tracker_id: 2,
|
||||||
end
|
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
|
||||||
|
|
|
@ -5,7 +5,7 @@ class ReviewsController < ApplicationController
|
||||||
|
|
||||||
def create
|
def create
|
||||||
return render_forbidden('您不是审查人员,无法进行审查!') if current_user&.id != @pull_request.issue.assigned_to_id
|
return render_forbidden('您不是审查人员,无法进行审查!') if current_user&.id != @pull_request.issue.assigned_to_id
|
||||||
@journal, @review = Api::V1::Projects::PullRequests::Reviews::CreateService.call(@project, @pull_request, review_params, current_user)
|
@review = Api::V1::Projects::Pulls::Reviews::CreateService.call(@project, @pull_request, review_params, current_user)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
class Traces::BaseController < ApplicationController
|
class Traces::BaseController < ApplicationController
|
||||||
|
|
||||||
helper_method :observed_logged_user?, :observed_user
|
helper_method :observed_logged_user?, :observed_user
|
||||||
|
before_action :check_trace_system
|
||||||
|
|
||||||
def observed_user
|
def observed_user
|
||||||
@_observed_user ||= (User.find_by_login(params[:user_id]) || User.find_by_id(params[:user_id]))
|
@_observed_user ||= (User.find_by_login(params[:user_id]) || User.find_by_id(params[:user_id]))
|
||||||
|
@ -15,4 +15,12 @@ class Traces::BaseController < ApplicationController
|
||||||
def check_auth
|
def check_auth
|
||||||
return render_forbidden unless current_user.admin? || observed_logged_user?
|
return render_forbidden unless current_user.admin? || observed_logged_user?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def check_trace_system
|
||||||
|
code, data, error = Trace::SystemInfoService.call(current_user.trace_token)
|
||||||
|
return render_ok({code: 501, data: {operate_time: data['operate_time']}, message: '系统维护中'}) if data['status'] === 0
|
||||||
|
rescue
|
||||||
|
# 这里根据需求跳转到404
|
||||||
|
return render_not_found
|
||||||
|
end
|
||||||
end
|
end
|
|
@ -3,6 +3,8 @@ class Traces::ProjectsController < Traces::BaseController
|
||||||
|
|
||||||
before_action :require_login
|
before_action :require_login
|
||||||
before_action :load_project
|
before_action :load_project
|
||||||
|
before_action :require_project_not_be_forked_project
|
||||||
|
before_action :set_trace_token_to_cookie
|
||||||
before_action :authorizate_user_can_edit_project!, except: [:task_results]
|
before_action :authorizate_user_can_edit_project!, except: [:task_results]
|
||||||
|
|
||||||
def tasks
|
def tasks
|
||||||
|
@ -35,7 +37,7 @@ class Traces::ProjectsController < Traces::BaseController
|
||||||
return render :json => {left_tasks_count: 5, data: []} if current_user.trace_user.nil?
|
return render :json => {left_tasks_count: 5, data: []} if current_user.trace_user.nil?
|
||||||
code, data, error = Trace::CheckResultService.call(current_user.trace_token, @project, nil, page, limit)
|
code, data, error = Trace::CheckResultService.call(current_user.trace_token, @project, nil, page, limit)
|
||||||
if code == 200
|
if code == 200
|
||||||
render :json => {left_tasks_count: 5 - @project.user_trace_tasks.size, data: data}
|
render :json => {left_tasks_count: 5 - @project.user_trace_tasks.size, data: data, view_base: "#{Trace.trace_config[:view_domain]}/analysis_ccf/analysis-results/" }
|
||||||
else
|
else
|
||||||
render_error("获取检测记录失败 Error:#{error}")
|
render_error("获取检测记录失败 Error:#{error}")
|
||||||
end
|
end
|
||||||
|
@ -86,4 +88,16 @@ class Traces::ProjectsController < Traces::BaseController
|
||||||
puts exception.message
|
puts exception.message
|
||||||
normal_status(-1, exception.message)
|
normal_status(-1, exception.message)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_trace_token_to_cookie
|
||||||
|
cookies[:vue_admin_template_token] = {
|
||||||
|
:value => current_user&.trace_token,
|
||||||
|
:expires => 1.hours.from_now,
|
||||||
|
:domain => Trace.trace_config[:cookie_domain]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def require_project_not_be_forked_project
|
||||||
|
return render_error('fork仓库暂不支持代码溯源服务,敬请谅解。') if @project.forked_from_project_id.present?
|
||||||
|
end
|
||||||
end
|
end
|
|
@ -1,7 +1,10 @@
|
||||||
class Users::IsPinnedProjectsController < Users::BaseController
|
class Users::IsPinnedProjectsController < Users::BaseController
|
||||||
before_action :private_user_resources!, only: [:pin]
|
before_action :private_user_resources!, only: [:pin]
|
||||||
def index
|
def index
|
||||||
@is_pinned_projects = observed_user.pinned_projects.order(position: :desc, created_at: :asc).includes(project: [:project_category, :project_language, :repository]).order(position: :desc)
|
@is_pinned_projects = observed_user.pinned_projects.left_joins(:project)
|
||||||
|
.where("projects.is_public = TRUE")
|
||||||
|
.order(position: :desc, created_at: :asc)
|
||||||
|
.includes(project: [:project_category, :project_language, :repository]).order(position: :desc)
|
||||||
@is_pinned_projects = kaminari_paginate(@is_pinned_projects)
|
@is_pinned_projects = kaminari_paginate(@is_pinned_projects)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -109,6 +109,19 @@ class UsersController < ApplicationController
|
||||||
@user = current_user
|
@user = current_user
|
||||||
end
|
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
|
def get_user_info
|
||||||
begin
|
begin
|
||||||
|
@ -349,7 +362,7 @@ class UsersController < ApplicationController
|
||||||
|
|
||||||
# 通过login参数查询头歌账号信息,注册并登录
|
# 通过login参数查询头歌账号信息,注册并登录
|
||||||
def autologin_register_by_educoder(edu_login)
|
def autologin_register_by_educoder(edu_login)
|
||||||
req_params = { "login" => "#{edu_login}", "private_token" => "hriEn3UwXfJs3PmyXnSH" }
|
req_params = { "login" => "#{edu_login}", "private_token" => "hriEn3UwXfJs3PmyXnqQ" }
|
||||||
api_url= "https://data.educoder.net"
|
api_url= "https://data.educoder.net"
|
||||||
client = Faraday.new(url: api_url)
|
client = Faraday.new(url: api_url)
|
||||||
response = client.public_send("get", "/api/sources/get_user_info_by_login", req_params)
|
response = client.public_send("get", "/api/sources/get_user_info_by_login", req_params)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1126,21 +1126,21 @@ await octokit.request('POST /api/v1/yystopf/ceshi/contents/batch.json')
|
||||||
### 请求参数:
|
### 请求参数:
|
||||||
参数 | 必选 | 默认 | 类型 | 字段说明
|
参数 | 必选 | 默认 | 类型 | 字段说明
|
||||||
--------- | ------- | ------- | -------- | ----------
|
--------- | ------- | ------- | -------- | ----------
|
||||||
|owner |是| |string |用户登录名 |
|
|owner |是| |string |用户登录名 |
|
||||||
|repo |是| |string |项目标识identifier |
|
|repo |是| |string |项目标识identifier |
|
||||||
|files.action_type |是| |string|操作类型 create: 创建 update: 更新 delete: 删除|
|
|files.action_type |是| |string|操作类型 create: 创建 update: 更新 delete: 删除|
|
||||||
|files.content |是| |string|文件内容|
|
|files.content |是| |string|文件内容|
|
||||||
|files.encoding |是| |string|文件编码方式 text 文本 base64 加密|
|
|files.encoding |是| |string|文件编码方式 text 文本 base64 加密|
|
||||||
|files.file_path |是| |string|文件路径|
|
|files.file_path |是| |string|文件路径|
|
||||||
|author_email |是| |string|作者邮箱|
|
|author_email |否| 当前用户邮箱 |string|作者邮箱,不填时需要与作者名称同时为空|
|
||||||
|author_name |是| |string|作者名称|
|
|author_name |否| 当前用户标识 |string|作者名称,不填时需要与作者邮箱同时为空|
|
||||||
|author_timeunix |是| |int|编码时间,精确到秒|
|
|author_timeunix |否| 当前时间戳 |int|编码时间,精确到秒|
|
||||||
|committer_email |是| |string|提交者邮箱|
|
|committer_email |否| 当前用户邮箱 |string|提交者邮箱,不填时需要与提交者名称同时为空|
|
||||||
|committer_name |是| |string|提交者名称|
|
|committer_name |否| 当前用户标识 |string|提交者名称,不填时需要与提交者邮箱同时为空|
|
||||||
|committer_timeunix|是| |int|提交时间戳,精确到秒|
|
|committer_timeunix|否| 当前时间戳 |int|提交时间戳,精确到秒|
|
||||||
|branch |是| |string|提交分支|
|
|branch |是| |string|提交分支|
|
||||||
|new_branch |否| |string|如果需要创建新分支,这个需要填|
|
|new_branch |否| |string|如果需要创建新分支,这个需要填|
|
||||||
|message |是| |string|提交信息|
|
|message |是| |string|提交信息|
|
||||||
|
|
||||||
> 请求的JSON示例:
|
> 请求的JSON示例:
|
||||||
|
|
||||||
|
@ -1990,25 +1990,27 @@ await octokit.request('GET /api/v1/yystopf/csfjkkj/compare.json')
|
||||||
|diff.files.is_created|bool|是否为新建文件|
|
|diff.files.is_created|bool|是否为新建文件|
|
||||||
|diff.files.is_deleted|bool|是否为删除文件|
|
|diff.files.is_deleted|bool|是否为删除文件|
|
||||||
|diff.files.is_bin|bool|是否为二进制文件|
|
|diff.files.is_bin|bool|是否为二进制文件|
|
||||||
|diff.files.is_lfs_file|bool||
|
|diff.files.is_lfs_file|bool|是否为LFS文件|
|
||||||
|diff.files.is_renamed|bool|是否重命名|
|
|diff.files.is_renamed|bool|是否重命名|
|
||||||
|diff.files.is_ambiguous|bool||
|
|diff.files.is_ambiguous|bool||
|
||||||
|diff.files.is_submodule|bool|是否为子模块|
|
|diff.files.is_submodule|bool|是否为子模块|
|
||||||
|diff.files.sections.file_name|string|文件名称|
|
|diff.files.sections.file_name|string|文件名称|
|
||||||
|diff.files.sections.name|string||
|
|diff.files.sections.name|string||
|
||||||
|diff.files.sections.lines.left_index|int||
|
|diff.files.sections.lines.left_index|int|文件变动之前所在行数|
|
||||||
|diff.files.sections.lines.right_index|int||
|
|diff.files.sections.lines.right_index|int|文件变动之后所在行数|
|
||||||
|diff.files.sections.lines.match|int||
|
|diff.files.sections.lines.match|int||
|
||||||
|diff.files.sections.lines.type|int||
|
|diff.files.sections.lines.type|int|文件变更类型|
|
||||||
|diff.files.sections.lines.content|string||
|
|diff.files.sections.lines.content|string|文件变更内容|
|
||||||
|diff.files.sections.lines.section_path|string||
|
|diff.files.sections.lines.section_path|string|文件路径|
|
||||||
|diff.files.sections.lines.section_last_left_index|int||
|
|diff.files.sections.lines.section_last_left_index|int||
|
||||||
|diff.files.sections.lines.section_last_right_index|int||
|
|diff.files.sections.lines.section_last_right_index|int||
|
||||||
|diff.files.sections.lines.section_left_index|int||
|
|diff.files.sections.lines.section_left_index|int|文件变更之前所在行数|
|
||||||
|diff.files.sections.lines.section_right_index|int||
|
|diff.files.sections.lines.section_right_index|int|文件变更之后所在行数(即:页面编辑器开始显示的行数)|
|
||||||
|diff.files.sections.lines.section_left_hunk_size|int||
|
|diff.files.sections.lines.section_left_hunk_size|int|文件变更之前的行数|
|
||||||
|diff.files.sections.lines.section_right_hunk_size|int||
|
|diff.files.sections.lines.section_right_hunk_size|int|文件变更之后的行数(及当前页面编辑器显示的总行数)|
|
||||||
|
|diff.files.is_incomplete|bool|是否不完整|
|
||||||
|
|diff.files.is_incomplete_line_too_long|bool|文件是否不完整是因为太长了|
|
||||||
|
|diff.files.is_protected|bool|文件是否被保护|
|
||||||
|
|
||||||
|
|
||||||
> 返回的JSON示例:
|
> 返回的JSON示例:
|
||||||
|
@ -2281,7 +2283,7 @@ await octokit.request('POST /api/v1/yystopf/ceshi/webhooks.json')
|
||||||
|webhook.active |是| | bool | 是否激活|
|
|webhook.active |是| | bool | 是否激活|
|
||||||
|webhook.branch_filter|否| |string|分支过滤|
|
|webhook.branch_filter|否| |string|分支过滤|
|
||||||
|webhook.events |否| |array|触发事件|
|
|webhook.events |否| |array|触发事件|
|
||||||
|
|webhook.type |否| gitea |string| hook类型,gitea slack discord dingtalk telegram msteams feishu matrix jianmu|
|
||||||
触发事件字段说明
|
触发事件字段说明
|
||||||
|
|
||||||
参数| 含义|
|
参数| 含义|
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
# Teams
|
||||||
|
|
||||||
|
## 团队下新增所有的项目
|
||||||
|
团队下新增所有的项目
|
||||||
|
|
||||||
|
> 示例:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -X POST \
|
||||||
|
http://localhost:3000/api/organizations/ceshi_org/teams/28/team_projects/create_all
|
||||||
|
```
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
await octokit.request('POST /api/organizations/ceshi_org/teams/28/team_projects/create_all.json')
|
||||||
|
```
|
||||||
|
|
||||||
|
### HTTP 请求
|
||||||
|
`POST /api/organizations/:organization/teams/:id/team_projects/create_all.json`
|
||||||
|
|
||||||
|
### 请求参数:
|
||||||
|
参数 | 必选 | 默认 | 类型 | 字段说明
|
||||||
|
--------- | ------- | ------- | -------- | ----------
|
||||||
|
|organization |是| | string |组织标识 |
|
||||||
|
|id |是| | integer|团队 ID|
|
||||||
|
|
||||||
|
### 返回字段说明:
|
||||||
|
|
||||||
|
|
||||||
|
> 返回的JSON示例:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": 0,
|
||||||
|
"message": "success"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<aside class="success">
|
||||||
|
Success Data.
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
|
||||||
|
## 团队下删除所有的项目
|
||||||
|
团队下删除所有的项目
|
||||||
|
|
||||||
|
> 示例:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -X DELETE \
|
||||||
|
http://localhost:3000/api/organizations/ceshi_org/teams/28/team_projects/destroy_all
|
||||||
|
```
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
await octokit.request('DELETE /api/organizations/ceshi_org/teams/28/team_projects/destroy_all.json')
|
||||||
|
```
|
||||||
|
|
||||||
|
### HTTP 请求
|
||||||
|
`DELETE /api/organizations/:organization/teams/:id/team_projects/destroy_all.json`
|
||||||
|
|
||||||
|
### 请求参数:
|
||||||
|
参数 | 必选 | 默认 | 类型 | 字段说明
|
||||||
|
--------- | ------- | ------- | -------- | ----------
|
||||||
|
|organization |是| | string |组织标识 |
|
||||||
|
|id |是| | integer|团队 ID|
|
||||||
|
|
||||||
|
### 返回字段说明:
|
||||||
|
|
||||||
|
|
||||||
|
> 返回的JSON示例:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": 0,
|
||||||
|
"message": "success"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<aside class="success">
|
||||||
|
Success Data.
|
||||||
|
</aside>
|
|
@ -2304,4 +2304,189 @@ await octokit.request('GET /api/users/:login/applied_projects/:id/refuse.json')
|
||||||
"created_at": "2021-06-09 16:41",
|
"created_at": "2021-06-09 16:41",
|
||||||
"time_ago": "7分钟前"
|
"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"
|
||||||
|
}
|
||||||
```
|
```
|
|
@ -3,6 +3,8 @@ class Contents::CreateForm < BaseForm
|
||||||
|
|
||||||
validates :filepath, presence: true
|
validates :filepath, presence: true
|
||||||
|
|
||||||
|
validates :new_branch, length: { maximum: 100, too_long: "过长,仅支持%{count}的长度"}
|
||||||
|
|
||||||
validate :check_branch
|
validate :check_branch
|
||||||
|
|
||||||
def check_branch
|
def check_branch
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
module Admins::NpsHelper
|
||||||
|
end
|
|
@ -95,21 +95,31 @@ module ApplicationHelper
|
||||||
timePassed = currentTime - lastUpdateTime
|
timePassed = currentTime - lastUpdateTime
|
||||||
timeIntoFormat = 0
|
timeIntoFormat = 0
|
||||||
updateAtValue = ""
|
updateAtValue = ""
|
||||||
if timePassed < 0
|
|
||||||
|
if timePassed <= 0
|
||||||
updateAtValue = "刚刚"
|
updateAtValue = "刚刚"
|
||||||
|
elsif timePassed < 2 * 1000
|
||||||
|
updateAtValue = "1秒前"
|
||||||
elsif timePassed < ONE_MINUTE
|
elsif timePassed < ONE_MINUTE
|
||||||
updateAtValue = "1分钟前"
|
updateAtValue = "1分钟前"
|
||||||
elsif timePassed < ONE_HOUR
|
elsif timePassed < ONE_HOUR
|
||||||
timeIntoFormat = timePassed / ONE_MINUTE
|
timeIntoFormat = timePassed / ONE_MINUTE
|
||||||
updateAtValue = timeIntoFormat.to_s + "分钟前"
|
updateAtValue = timeIntoFormat.to_s + "分钟前"
|
||||||
elsif (timePassed < ONE_DAY)
|
elsif (timePassed < ONE_DAY)
|
||||||
timeIntoFormat = (timePassed.to_f / ONE_HOUR).ceil
|
timeIntoFormat = (timePassed.to_f / ONE_HOUR).round
|
||||||
|
timeIntoFormat == 1 if timeIntoFormat.to_i == 0
|
||||||
updateAtValue = timeIntoFormat.to_s + "小时前"
|
updateAtValue = timeIntoFormat.to_s + "小时前"
|
||||||
elsif (timePassed < ONE_MONTH)
|
elsif (timePassed < ONE_MONTH)
|
||||||
timeIntoFormat = (timePassed.to_f / ONE_DAY).ceil
|
timeIntoFormat = (timePassed.to_f / ONE_DAY).round
|
||||||
|
timeIntoFormat == 1 if timeIntoFormat.to_i == 0
|
||||||
|
updateAtValue = timeIntoFormat.to_s + "天前"
|
||||||
|
elsif (timePassed < ONE_MONTH)
|
||||||
|
timeIntoFormat = (timePassed.to_f / ONE_DAY).round
|
||||||
|
timeIntoFormat == 1 if timeIntoFormat.to_i == 0
|
||||||
updateAtValue = timeIntoFormat.to_s + "天前"
|
updateAtValue = timeIntoFormat.to_s + "天前"
|
||||||
elsif (timePassed < ONE_YEAR)
|
elsif (timePassed < ONE_YEAR)
|
||||||
timeIntoFormat = (timePassed.to_f / ONE_MONTH).ceil
|
timeIntoFormat = (timePassed.to_f / ONE_MONTH).round
|
||||||
|
timeIntoFormat == 1 if timeIntoFormat.to_i == 0
|
||||||
updateAtValue = timeIntoFormat.to_s + "个月前"
|
updateAtValue = timeIntoFormat.to_s + "个月前"
|
||||||
else
|
else
|
||||||
timeIntoFormat = timePassed / ONE_YEAR
|
timeIntoFormat = timePassed / ONE_YEAR
|
||||||
|
|
|
@ -63,6 +63,9 @@ module ProjectsHelper
|
||||||
project_category_id: project.project_category_id,
|
project_category_id: project.project_category_id,
|
||||||
project_language_id: project.project_language_id,
|
project_language_id: project.project_language_id,
|
||||||
license_id: project.license_id,
|
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
|
ignore_id: project.ignore_id
|
||||||
}).compact
|
}).compact
|
||||||
|
|
||||||
|
@ -98,4 +101,53 @@ module ProjectsHelper
|
||||||
def render_educoder_avatar_url(project_educoder)
|
def render_educoder_avatar_url(project_educoder)
|
||||||
[Rails.application.config_for(:configuration)['educoder']['cdn_url'], project_educoder&.image_url].join('/')
|
[Rails.application.config_for(:configuration)['educoder']['cdn_url'], project_educoder&.image_url].join('/')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# 静默登录方式:
|
||||||
|
#
|
||||||
|
# 数据格式为JSON:
|
||||||
|
# {
|
||||||
|
# "userId": "xxx", // 用户唯一标识
|
||||||
|
# "ref": "xxx", // 仓库唯一标识
|
||||||
|
# "owner": "xxx", // 用户登录名或组织账号
|
||||||
|
# "timestamp": xxx // 当前时间戳,单位:毫秒
|
||||||
|
# }
|
||||||
|
# 加密方式:把数据序列化成JSON字符串,用Client Secret和固定IV(5183666c72eec9e4)对称加密(模式:AES-256-CBC)
|
||||||
|
#
|
||||||
|
# API:
|
||||||
|
# GET:https://ci-v3.test.jianmuhub.com/oauth2/authorize?code=${encode(密文)}
|
||||||
|
def jianmu_devops_code(project, user)
|
||||||
|
if user.admin? || project.member?(user.id)
|
||||||
|
data = { userId: user.id, ref: project.identifier, owner: project.owner.login, timestamp: Time.now.to_i * 1000 }
|
||||||
|
# uid = EduSetting.get("jianmu_oauth2_uid") || 'oedKx4v-WyAfu2oy_AsFpFQCH_-g91ms0PQKN7YcEuw'
|
||||||
|
# app = Doorkeeper::Application.find_by(uid: uid)
|
||||||
|
key = 'bf3c199c2470cb477d907b1e0917c17b'
|
||||||
|
aes_encrypt(key, data.to_json)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def jianmu_devops_url
|
||||||
|
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')
|
||||||
|
des = OpenSSL::Cipher.new('AES-256-CBC')
|
||||||
|
des.encrypt
|
||||||
|
# des.padding =
|
||||||
|
des.key = key
|
||||||
|
des.iv = "5183666c72eec9e4"
|
||||||
|
result = des.update(des_text)
|
||||||
|
result << des.final
|
||||||
|
Base64.strict_encode64 result
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -123,7 +123,7 @@ module TagChosenHelper
|
||||||
cache_key = "project-#{project.id}/all_milestones/size-#{project.versions.size}/#{project.versions.maximum('updated_on')}"
|
cache_key = "project-#{project.id}/all_milestones/size-#{project.versions.size}/#{project.versions.maximum('updated_on')}"
|
||||||
|
|
||||||
Rails.cache.fetch(cache_key) do
|
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,
|
id: event.id,
|
||||||
name: event.name,
|
name: event.name,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
module CustomRegexp
|
module CustomRegexp
|
||||||
PHONE = /1\d{10}/
|
PHONE = /1\d{10}/
|
||||||
EMAIL = /\A[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+\z/
|
EMAIL = /\A[a-zA-Z0-9]+([._\-\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+\z/
|
||||||
LOGIN = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]{4,15}\z/ #只含有数字、字母、下划线不能以下划线开头和结尾
|
LOGIN = /^(?!_)(?!.*?_$)[a-zA-Z0-9_-]{4,15}\z/ #只含有数字、字母、下划线不能以下划线开头和结尾
|
||||||
LASTNAME = /\A[a-zA-Z0-9\u4e00-\u9fa5]+\z/
|
LASTNAME = /\A[a-zA-Z0-9\u4e00-\u9fa5]+\z/
|
||||||
NICKNAME = /\A[\u4e00-\u9fa5_a-zA-Z0-9]+\z/
|
NICKNAME = /\A[\u4e00-\u9fa5_a-zA-Z0-9]+\z/
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
class UserMailer < ApplicationMailer
|
class UserMailer < ApplicationMailer
|
||||||
# 注意:这个地方一定要和你的邮箱服务域名一致
|
# 注意:这个地方一定要和你的邮箱服务域名一致
|
||||||
default from: 'notification@trustie.org'
|
# default from: 'notification@trustie.org'
|
||||||
|
default from: 'noreply@gitlink.org.cn'
|
||||||
# 用户注册验证码
|
|
||||||
def register_email(mail, code)
|
# 用户注册验证码
|
||||||
@code = code
|
def register_email(mail, code)
|
||||||
mail(to: mail, subject: 'Gitink | 注册验证码')
|
@code = code
|
||||||
end
|
mail(to: mail, subject: 'Gitink | 注册验证码')
|
||||||
|
end
|
||||||
end
|
|
||||||
|
def update_email(mail, code)
|
||||||
|
@code = code
|
||||||
|
mail(to: mail, subject: 'Gitink | 更改邮箱验证码')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -17,30 +17,69 @@ module ProjectOperable
|
||||||
owner.build_permit_team_projects!(id)
|
owner.build_permit_team_projects!(id)
|
||||||
# 避免自己创建的项目,却无法拥有访问权,因为该用户所在团队暂未获得项目访问权
|
# 避免自己创建的项目,却无法拥有访问权,因为该用户所在团队暂未获得项目访问权
|
||||||
return if creator.nil? || owner.is_owner?(creator.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
|
end
|
||||||
|
|
||||||
def add_member!(user_id, role_name='Developer')
|
def add_member!(user_id, role_name='Developer')
|
||||||
if self.owner.is_a?(Organization)
|
if self.owner.is_a?(Organization)
|
||||||
case role_name
|
case role_name
|
||||||
when 'Manager'
|
when 'Manager'
|
||||||
|
# 构建相应的团队
|
||||||
team = self.owner.teams.admin.take
|
team = self.owner.teams.admin.take
|
||||||
team = team.nil? ? Team.build(self.user_id, 'admin', '管理员', '', 'admin', false, false) : team
|
if team.nil?
|
||||||
TeamProject.build(self.user_id, team.id, self.id)
|
team = Team.build(self.user_id, 'admin', '管理员', '', 'admin', false, false)
|
||||||
OrganizationUser.build(self.user_id, user_id)
|
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)
|
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'
|
when 'Developer'
|
||||||
|
# 构建相应的团队
|
||||||
team = self.owner.teams.write.take
|
team = self.owner.teams.write.take
|
||||||
team = team.nil? ? Team.build(self.user_id, 'developer', '开发者', '', 'write', false, false) : team
|
if team.nil?
|
||||||
TeamProject.build(self.user_id, team.id, self.id)
|
team = Team.build(self.user_id, 'developer', '开发者', '', 'write', false, false)
|
||||||
OrganizationUser.build(self.user_id, user_id)
|
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)
|
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'
|
when 'Reporter'
|
||||||
|
# 构建相应的团队
|
||||||
team = self.owner.teams.read.take
|
team = self.owner.teams.read.take
|
||||||
team = team.nil? ? Team.build(self.user_id, 'reporter', '报告者', '', 'read', false, false) : team
|
if team.nil?
|
||||||
TeamProject.build(self.user_id, team.id, self.id)
|
team = Team.build(self.user_id, 'reporter', '报告者', '', 'read', false, false)
|
||||||
OrganizationUser.build(self.user_id, user_id)
|
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)
|
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
|
||||||
end
|
end
|
||||||
member = members.create!(user_id: user_id, team_user_id: team_user&.id)
|
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)
|
def change_member_role!(user_id, role)
|
||||||
member = self.member(user_id)
|
member = self.member(user_id)
|
||||||
|
# 所有者为组织,并且该用户属于组织成员
|
||||||
if self.owner.is_a?(Organization) && member.team_user.present?
|
if self.owner.is_a?(Organization) && member.team_user.present?
|
||||||
case role&.name
|
case role&.name
|
||||||
when 'Manager'
|
when 'Manager'
|
||||||
|
# 构建相应的团队
|
||||||
team = self.owner.teams.admin.take
|
team = self.owner.teams.admin.take
|
||||||
team = team.nil? ? Team.build(self.user_id, 'admin', '管理员', '', 'admin', false, false) : team
|
if team.nil?
|
||||||
TeamProject.build(self.user_id, team.id, self.id)
|
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}) unless team.team_users.exists?(user_id: member.user_id)
|
||||||
|
|
||||||
|
# 确保组织成员中有该用户
|
||||||
OrganizationUser.build(self.user_id, user_id)
|
OrganizationUser.build(self.user_id, user_id)
|
||||||
team_user = member.team_user.update(team_id: team&.id)
|
|
||||||
when 'Developer'
|
when 'Developer'
|
||||||
|
# 构建相应的团队
|
||||||
team = self.owner.teams.write.take
|
team = self.owner.teams.write.take
|
||||||
team = team.nil? ? Team.build(self.user_id, 'developer', '开发者', '', 'write', false, false) : team
|
if team.nil?
|
||||||
TeamProject.build(self.user_id, team.id, self.id)
|
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}) unless team.team_users.exists?(user_id: member.user_id)
|
||||||
|
|
||||||
OrganizationUser.build(self.user_id, user_id)
|
OrganizationUser.build(self.user_id, user_id)
|
||||||
team_user = member.team_user.update(team_id: team&.id)
|
|
||||||
when 'Reporter'
|
when 'Reporter'
|
||||||
|
# 构建相应的团队
|
||||||
team = self.owner.teams.read.take
|
team = self.owner.teams.read.take
|
||||||
team = team.nil? ? Team.build(self.user_id, 'reporter', '报告者', '', 'read', false, false) : team
|
if team.nil?
|
||||||
TeamProject.build(self.user_id, team.id, self.id)
|
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}) unless team.team_users.exists?(user_id: member.user_id)
|
||||||
|
|
||||||
|
# 确保组织成员中有该用户
|
||||||
OrganizationUser.build(self.user_id, user_id)
|
OrganizationUser.build(self.user_id, user_id)
|
||||||
team_user = member.team_user.update(team_id: team&.id)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
member.member_roles.last.update_attributes!(role: role)
|
member.member_roles.last.update_attributes!(role: role)
|
||||||
|
|
|
@ -11,4 +11,7 @@
|
||||||
|
|
||||||
class Ignore < ApplicationRecord
|
class Ignore < ApplicationRecord
|
||||||
include Projectable
|
include Projectable
|
||||||
|
|
||||||
|
validates :name, :content, presence: true
|
||||||
|
validates :name, uniqueness: { case_sensitive: false }
|
||||||
end
|
end
|
||||||
|
|
|
@ -69,7 +69,6 @@ class Issue < ApplicationRecord
|
||||||
has_many :issue_tags, through: :issue_tags_relates
|
has_many :issue_tags, through: :issue_tags_relates
|
||||||
has_many :issue_times, dependent: :destroy
|
has_many :issue_times, dependent: :destroy
|
||||||
has_many :issue_depends, dependent: :destroy
|
has_many :issue_depends, dependent: :destroy
|
||||||
has_many :reviews, dependent: :destroy
|
|
||||||
scope :issue_includes, ->{includes(:user)}
|
scope :issue_includes, ->{includes(:user)}
|
||||||
scope :issue_many_includes, ->{includes(journals: :user)}
|
scope :issue_many_includes, ->{includes(journals: :user)}
|
||||||
scope :issue_issue, ->{where(issue_classify: [nil,"issue"])}
|
scope :issue_issue, ->{where(issue_classify: [nil,"issue"])}
|
||||||
|
|
|
@ -13,6 +13,15 @@
|
||||||
# comments_count :integer default("0")
|
# comments_count :integer default("0")
|
||||||
# reply_id :integer
|
# reply_id :integer
|
||||||
# review_id :integer
|
# review_id :integer
|
||||||
|
# commit_id :string(255)
|
||||||
|
# diff :text(4294967295)
|
||||||
|
# line_code :string(255)
|
||||||
|
# path :string(255)
|
||||||
|
# state :integer default("0")
|
||||||
|
# resolve_at :datetime
|
||||||
|
# resolveer_id :integer
|
||||||
|
# need_respond :boolean default("0")
|
||||||
|
# updated_on :datetime
|
||||||
#
|
#
|
||||||
# Indexes
|
# Indexes
|
||||||
#
|
#
|
||||||
|
@ -24,15 +33,22 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
class Journal < ApplicationRecord
|
class Journal < ApplicationRecord
|
||||||
|
serialize :diff, JSON
|
||||||
|
alias_attribute :note, :notes
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
belongs_to :issue, foreign_key: :journalized_id, :touch => true
|
belongs_to :issue, foreign_key: :journalized_id, :touch => true, optional: true
|
||||||
|
belongs_to :journalized, polymorphic: true
|
||||||
|
belongs_to :review, optional: true
|
||||||
|
belongs_to :resolveer, class_name: 'User', foreign_key: :resolveer_id, optional: true
|
||||||
has_many :journal_details, :dependent => :delete_all
|
has_many :journal_details, :dependent => :delete_all
|
||||||
has_many :attachments, as: :container, dependent: :destroy
|
has_many :attachments, as: :container, dependent: :destroy
|
||||||
|
has_many :children_journals, class_name: 'Journal', foreign_key: :parent_id
|
||||||
|
|
||||||
scope :journal_includes, ->{includes(:user, :journal_details, :attachments)}
|
scope :journal_includes, ->{includes(:user, :journal_details, :attachments)}
|
||||||
scope :parent_journals, ->{where(parent_id: nil)}
|
scope :parent_journals, ->{where(parent_id: nil)}
|
||||||
scope :children_journals, lambda{|journal_id| where(parent_id: journal_id)}
|
scope :children_journals, lambda{|journal_id| where(parent_id: journal_id)}
|
||||||
|
|
||||||
|
enum state: {opened: 0, resolved: 1, disabled: 2}
|
||||||
|
|
||||||
def is_journal_detail?
|
def is_journal_detail?
|
||||||
self.notes.blank? && self.journal_details.present?
|
self.notes.blank? && self.journal_details.present?
|
||||||
|
|
|
@ -11,4 +11,8 @@
|
||||||
|
|
||||||
class License < ApplicationRecord
|
class License < ApplicationRecord
|
||||||
include Projectable
|
include Projectable
|
||||||
|
|
||||||
|
validates :name, :content, presence: true
|
||||||
|
validates :name, uniqueness: { case_sensitive: false }
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
class MarkFile < ApplicationRecord
|
||||||
|
belongs_to :pull_request
|
||||||
|
|
||||||
|
|
||||||
|
end
|
|
@ -13,6 +13,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
class MessageTemplate < ApplicationRecord
|
class MessageTemplate < ApplicationRecord
|
||||||
|
# self.inheritance_column = nil
|
||||||
PLATFORM = 'GitLink'
|
PLATFORM = 'GitLink'
|
||||||
|
|
||||||
def self.build_init_data
|
def self.build_init_data
|
||||||
|
@ -113,6 +114,6 @@ class MessageTemplate < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def simple_type
|
def simple_type
|
||||||
self.type.split("::")[-1]
|
self.type.to_s.split("::")[-1]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: ob_repository_syncs
|
||||||
|
#
|
||||||
|
# id :integer not null, primary key
|
||||||
|
# project_id :integer
|
||||||
|
# user_id :integer
|
||||||
|
# name :string(255)
|
||||||
|
# github_address :string(255)
|
||||||
|
# gitee_address :string(255)
|
||||||
|
# github_token :string(255)
|
||||||
|
# gitee_token :string(255)
|
||||||
|
# sync_id :integer
|
||||||
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
|
#
|
||||||
|
# Indexes
|
||||||
|
#
|
||||||
|
# index_ob_repository_syncs_on_project_id (project_id)
|
||||||
|
# index_ob_repository_syncs_on_user_id (user_id)
|
||||||
|
#
|
||||||
|
|
||||||
|
class ObRepositorySync < ApplicationRecord
|
||||||
|
belongs_to :project
|
||||||
|
belongs_to :user
|
||||||
|
|
||||||
|
has_many :ob_repository_sync_jobs, dependent: :destroy
|
||||||
|
end
|
|
@ -0,0 +1,24 @@
|
||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: ob_repository_sync_jobs
|
||||||
|
#
|
||||||
|
# id :integer not null, primary key
|
||||||
|
# ob_repository_sync_id :integer
|
||||||
|
# github_branch :string(255)
|
||||||
|
# gitee_branch :string(255)
|
||||||
|
# gitlink_branch :string(255)
|
||||||
|
# job_type :string(255)
|
||||||
|
# base :string(255)
|
||||||
|
# job_id :integer
|
||||||
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
|
#
|
||||||
|
# Indexes
|
||||||
|
#
|
||||||
|
# index_ob_repository_sync_jobs_on_ob_repository_sync_id (ob_repository_sync_id)
|
||||||
|
#
|
||||||
|
|
||||||
|
class ObRepositorySyncJob < ApplicationRecord
|
||||||
|
belongs_to :ob_repository_sync
|
||||||
|
|
||||||
|
end
|
|
@ -81,15 +81,15 @@ class Organization < Owner
|
||||||
|
|
||||||
scope :with_visibility, ->(visibility) { joins(:organization_extension).where(organization_extensions: {visibility: visibility}) if visibility.present? }
|
scope :with_visibility, ->(visibility) { joins(:organization_extension).where(organization_extensions: {visibility: visibility}) if visibility.present? }
|
||||||
|
|
||||||
after_save :reset_cache_data
|
# after_save :reset_cache_data
|
||||||
|
|
||||||
def gitea_token
|
def gitea_token
|
||||||
team_users.joins(:team).where(teams: {authorize: "owner"}).take&.user&.gitea_token
|
team_users.joins(:team).where(teams: {authorize: "owner"}).take&.user&.gitea_token
|
||||||
end
|
end
|
||||||
|
|
||||||
def reset_cache_data
|
# def reset_cache_data
|
||||||
Cache::V2::OwnerCommonService.new(self.id).reset
|
# Cache::V2::OwnerCommonService.new(self.id).reset
|
||||||
end
|
# end
|
||||||
|
|
||||||
def self.build(name, nickname, gitea_token=nil)
|
def self.build(name, nickname, gitea_token=nil)
|
||||||
self.create!(login: name, nickname: nickname, gitea_token: gitea_token)
|
self.create!(login: name, nickname: nickname, gitea_token: gitea_token)
|
||||||
|
|
|
@ -12,4 +12,6 @@
|
||||||
|
|
||||||
class ProjectLanguage < ApplicationRecord
|
class ProjectLanguage < ApplicationRecord
|
||||||
include Projectable
|
include Projectable
|
||||||
|
|
||||||
|
validates :name, uniqueness: { message: "已存在" }
|
||||||
end
|
end
|
||||||
|
|
|
@ -32,12 +32,18 @@ class PullRequest < ApplicationRecord
|
||||||
belongs_to :issue
|
belongs_to :issue
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
belongs_to :project, counter_cache: true, touch: true
|
belongs_to :project, counter_cache: true, touch: true
|
||||||
# belongs_to :fork_project, foreign_key: :fork_project_id
|
belongs_to :fork_project, class_name: 'Project', foreign_key: :fork_project_id, optional: true
|
||||||
has_many :pull_request_assigns, foreign_key: :pull_request_id
|
has_many :pull_request_assigns, foreign_key: :pull_request_id
|
||||||
has_many :pull_request_tags, foreign_key: :pull_request_id
|
has_many :pull_request_tags, foreign_key: :pull_request_id
|
||||||
has_many :project_trends, as: :trend, dependent: :destroy
|
has_many :project_trends, as: :trend, dependent: :destroy
|
||||||
has_many :attachments, as: :container, dependent: :destroy
|
has_many :attachments, as: :container, dependent: :destroy
|
||||||
has_one :gitea_pull, foreign_key: :id, primary_key: :gitea_id, class_name: 'Gitea::Pull'
|
has_one :gitea_pull, foreign_key: :id, primary_key: :gitea_id, class_name: 'Gitea::Pull'
|
||||||
|
has_many :journals, :as => :journalized, :dependent => :destroy
|
||||||
|
has_many :journal_details, through: :journals
|
||||||
|
has_many :reviews, dependent: :destroy
|
||||||
|
has_many :pull_requests_reviewers, dependent: :destroy
|
||||||
|
has_many :reviewers, through: :pull_requests_reviewers
|
||||||
|
has_many :mark_files, dependent: :destroy
|
||||||
|
|
||||||
scope :merged_and_closed, ->{where.not(status: 0)}
|
scope :merged_and_closed, ->{where.not(status: 0)}
|
||||||
scope :opening, -> {where(status: 0)}
|
scope :opening, -> {where(status: 0)}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: pull_requests_reviewers
|
||||||
|
#
|
||||||
|
# id :integer not null, primary key
|
||||||
|
# pull_request_id :integer
|
||||||
|
# reviewer_id :integer
|
||||||
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
|
#
|
||||||
|
# Indexes
|
||||||
|
#
|
||||||
|
# index_pull_requests_reviewers_on_pull_request_id (pull_request_id)
|
||||||
|
# index_pull_requests_reviewers_on_reviewer_id (reviewer_id)
|
||||||
|
#
|
||||||
|
|
||||||
|
class PullRequestsReviewer < ApplicationRecord
|
||||||
|
|
||||||
|
belongs_to :pull_request
|
||||||
|
belongs_to :reviewers, class_name: 'User', foreign_key: :reviewer_id
|
||||||
|
end
|
|
@ -49,7 +49,7 @@ class Repository < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def url
|
def url
|
||||||
self['url'].blank? ? "#{Rails.application.config_for(:configuration)['platform_url']}/#{self.owner&.login}/#{self.identifier}.git" : self['url']
|
self['url'].blank? ? "#{GiteaService.gitea_config[:domain]}/#{self.owner&.login}/#{self.identifier}.git" : self['url']
|
||||||
end
|
end
|
||||||
|
|
||||||
# with repository is mirror
|
# with repository is mirror
|
||||||
|
|
|
@ -2,24 +2,24 @@
|
||||||
#
|
#
|
||||||
# Table name: reviews
|
# Table name: reviews
|
||||||
#
|
#
|
||||||
# id :integer not null, primary key
|
# id :integer not null, primary key
|
||||||
# issue_id :integer
|
# reviewer_id :integer
|
||||||
# reviewer_id :integer
|
# content :text(65535)
|
||||||
# content :text(65535)
|
# commit_id :string(255)
|
||||||
# commit_id :string(255)
|
# status :integer default("0")
|
||||||
# status :integer default("0")
|
# created_at :datetime not null
|
||||||
# created_at :datetime not null
|
# updated_at :datetime not null
|
||||||
# updated_at :datetime not null
|
# pull_request_id :integer
|
||||||
#
|
#
|
||||||
# Indexes
|
# Indexes
|
||||||
#
|
#
|
||||||
# index_reviews_on_issue_id (issue_id)
|
# index_reviews_on_pull_request_id (pull_request_id)
|
||||||
# index_reviews_on_reviewer_id (reviewer_id)
|
# index_reviews_on_reviewer_id (reviewer_id)
|
||||||
#
|
#
|
||||||
|
|
||||||
class Review < ApplicationRecord
|
class Review < ApplicationRecord
|
||||||
|
|
||||||
belongs_to :issue
|
belongs_to :pull_request
|
||||||
belongs_to :reviewer, class_name: 'User', foreign_key: :reviewer_id
|
belongs_to :reviewer, class_name: 'User', foreign_key: :reviewer_id
|
||||||
has_one :journal, dependent: :destroy
|
has_one :journal, dependent: :destroy
|
||||||
|
|
||||||
|
|
|
@ -70,4 +70,15 @@ class Team < ApplicationRecord
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
|
@ -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
|
|
@ -32,7 +32,7 @@ class TraceUser < ApplicationRecord
|
||||||
self.username = user.login
|
self.username = user.login
|
||||||
self.password = SecureRandom.hex
|
self.password = SecureRandom.hex
|
||||||
self.unit = user.custom_department.blank? ? 'GitLink' : user.custom_department
|
self.unit = user.custom_department.blank? ? 'GitLink' : user.custom_department
|
||||||
self.telnumber = user.phone.blank? ? '13800000000' : user.phone
|
self.telnumber = user.phone || ""
|
||||||
self.email = user.mail
|
self.email = user.mail
|
||||||
self.name = user.nickname.blank? ? user.login : user.nickname
|
self.name = user.nickname.blank? ? user.login : user.nickname
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ class TraceUser < ApplicationRecord
|
||||||
|
|
||||||
|
|
||||||
def build_token
|
def build_token
|
||||||
return if username.blank? || password.blank? || unit.blank? || telnumber.blank? || email.blank? || name.blank?
|
return if username.blank? || password.blank? || unit.blank? || email.blank? || name.blank?
|
||||||
|
|
||||||
response = Trace::AddUserService.call(username, password, unit, telnumber, email, name)
|
response = Trace::AddUserService.call(username, password, unit, telnumber, email, name)
|
||||||
self.token = response[1]['token']
|
self.token = response[1]['token']
|
||||||
|
@ -49,7 +49,7 @@ class TraceUser < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def refresh_token
|
def refresh_token
|
||||||
return if username.blank? || password.blank? || unit.blank? || telnumber.blank? || email.blank? || name.blank?
|
return if username.blank? || password.blank? || unit.blank? || email.blank? || name.blank?
|
||||||
|
|
||||||
response = Trace::LoginService.call(username, password)
|
response = Trace::LoginService.call(username, password)
|
||||||
self.token = response[1]['token']
|
self.token = response[1]['token']
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: user_nps
|
||||||
|
#
|
||||||
|
# id :integer not null, primary key
|
||||||
|
# user_id :integer
|
||||||
|
# action_type :string(255)
|
||||||
|
# action_id :integer
|
||||||
|
# score :float(24)
|
||||||
|
# memo :text(65535)
|
||||||
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
|
#
|
||||||
|
# Indexes
|
||||||
|
#
|
||||||
|
# index_user_nps_on_user_id (user_id)
|
||||||
|
#
|
||||||
|
|
||||||
|
class UserNp < ApplicationRecord
|
||||||
|
belongs_to :user, optional: true
|
||||||
|
end
|
|
@ -32,7 +32,8 @@ class VersionRelease < ApplicationRecord
|
||||||
has_many :attachments, as: :container, dependent: :destroy
|
has_many :attachments, as: :container, dependent: :destroy
|
||||||
|
|
||||||
def update_sha
|
def update_sha
|
||||||
|
return if version_gid.blank?
|
||||||
git_release = Gitea::Versions::GetService.call(user.gitea_token, repository&.owner&.login, repository&.identifier, version_gid)
|
git_release = Gitea::Versions::GetService.call(user.gitea_token, repository&.owner&.login, repository&.identifier, version_gid)
|
||||||
self.update(sha: git_release["sha"])
|
self.update(sha: git_release["sha"]) if git_release.present? && git_release.is_a?(Hash)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,6 +19,9 @@ class Admins::UserQuery < ApplicationQuery
|
||||||
status = params[:status]
|
status = params[:status]
|
||||||
users = users.where(status: status) if status.present?
|
users = users.where(status: status) if status.present?
|
||||||
|
|
||||||
|
# 是否管理员
|
||||||
|
users = users.where(admin: params[:admin]) if params[:admin].present?
|
||||||
|
|
||||||
# 职业
|
# 职业
|
||||||
users = users.joins(:user_extension).where(user_extensions: { identity: params[:identity] }) if params[:identity].present?
|
users = users.joins(:user_extension).where(user_extensions: { identity: params[:identity] }) if params[:identity].present?
|
||||||
|
|
||||||
|
@ -27,6 +30,15 @@ class Admins::UserQuery < ApplicationQuery
|
||||||
users = users.joins(user_extension: :school).where(schools: { auto_users_trial: params[:auto_trial].to_i == 1 })
|
users = users.joins(user_extension: :school).where(schools: { auto_users_trial: params[:auto_trial].to_i == 1 })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# 第三方账户类型
|
||||||
|
if params[:open_user_type].present?
|
||||||
|
if params[:open_user_type] == "Forge"
|
||||||
|
users = users.left_joins(:open_users).where(open_users: {id: nil})
|
||||||
|
else
|
||||||
|
users = users.joins(:open_users).where(open_users: {type: params[:open_user_type]})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# 关键字检索
|
# 关键字检索
|
||||||
keyword = params[:keyword].to_s.strip.presence
|
keyword = params[:keyword].to_s.strip.presence
|
||||||
if keyword
|
if keyword
|
||||||
|
|
|
@ -29,6 +29,8 @@ class Projects::ListMyQuery < ApplicationQuery
|
||||||
projects = projects.where(user_id: user.id)
|
projects = projects.where(user_id: user.id)
|
||||||
elsif params[:category].to_s == "watched" #我关注的
|
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})
|
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的
|
elsif params[:category].to_s == "forked" #我fork的
|
||||||
fork_ids = user.fork_users.select(:id, :fork_project_id).pluck(:fork_project_id)
|
fork_ids = user.fork_users.select(:id, :fork_project_id).pluck(:fork_project_id)
|
||||||
projects = projects.where(id: fork_ids)
|
projects = projects.where(id: fork_ids)
|
||||||
|
|
|
@ -11,7 +11,7 @@ class Projects::ListQuery < ApplicationQuery
|
||||||
end
|
end
|
||||||
|
|
||||||
def call
|
def call
|
||||||
collection = Project.all
|
collection = Project.visible
|
||||||
collection = filter_projects(collection)
|
collection = filter_projects(collection)
|
||||||
|
|
||||||
sort = params[:sort_by] || "updated_on"
|
sort = params[:sort_by] || "updated_on"
|
||||||
|
@ -25,7 +25,7 @@ class Projects::ListQuery < ApplicationQuery
|
||||||
|
|
||||||
def filter_projects(collection)
|
def filter_projects(collection)
|
||||||
# collection = by_pinned(collection)
|
# collection = by_pinned(collection)
|
||||||
collection = by_search(collection)
|
collection = by_search(collection) if params[:search].present?
|
||||||
collection = by_project_type(collection)
|
collection = by_project_type(collection)
|
||||||
collection = by_project_category(collection)
|
collection = by_project_category(collection)
|
||||||
collection = by_project_language(collection)
|
collection = by_project_language(collection)
|
||||||
|
@ -33,7 +33,13 @@ class Projects::ListQuery < ApplicationQuery
|
||||||
end
|
end
|
||||||
|
|
||||||
def by_search(items)
|
def by_search(items)
|
||||||
items.visible.by_name_or_identifier(params[:search])
|
ids = Projects::ElasticsearchService.call(params[:search])
|
||||||
|
items = items.where(platform: 'forge')
|
||||||
|
if ids.present?
|
||||||
|
items.where(id: ids).by_name_or_identifier(params[:search])
|
||||||
|
else
|
||||||
|
items.by_name_or_identifier(params[:search])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def by_project_type(items)
|
def by_project_type(items)
|
||||||
|
|
|
@ -13,7 +13,6 @@ class Api::V1::Projects::Contents::BatchCreateService < ApplicationService
|
||||||
|
|
||||||
|
|
||||||
def initialize(project, params, token=nil)
|
def initialize(project, params, token=nil)
|
||||||
puts params
|
|
||||||
@project = project
|
@project = project
|
||||||
@owner = project&.owner.login
|
@owner = project&.owner.login
|
||||||
@repo = project&.identifier
|
@repo = project&.identifier
|
||||||
|
@ -21,11 +20,11 @@ class Api::V1::Projects::Contents::BatchCreateService < ApplicationService
|
||||||
@files = params[:files]
|
@files = params[:files]
|
||||||
@author_email = params[:author_email]
|
@author_email = params[:author_email]
|
||||||
@author_name = params[:author_name]
|
@author_name = params[:author_name]
|
||||||
@author_timeunix = params[:author_timeunix]
|
@author_timeunix = params[:author_timeunix] || Time.now.to_i
|
||||||
@branch = params[:branch]
|
@branch = params[:branch]
|
||||||
@committer_email = params[:committer_email]
|
@committer_email = params[:committer_email]
|
||||||
@committer_name = params[:committer_name]
|
@committer_name = params[:committer_name]
|
||||||
@committer_timeunix = params[:committer_timeunix]
|
@committer_timeunix = params[:committer_timeunix] || Time.now.to_i
|
||||||
@message = params[:message]
|
@message = params[:message]
|
||||||
@new_branch = params[:new_branch]
|
@new_branch = params[:new_branch]
|
||||||
end
|
end
|
||||||
|
@ -63,6 +62,7 @@ class Api::V1::Projects::Contents::BatchCreateService < ApplicationService
|
||||||
committer: Time.at(committer_timeunix.to_i)
|
committer: Time.at(committer_timeunix.to_i)
|
||||||
},
|
},
|
||||||
message: message,
|
message: message,
|
||||||
|
branch: branch,
|
||||||
new_branch: new_branch,
|
new_branch: new_branch,
|
||||||
signoff: false
|
signoff: false
|
||||||
}
|
}
|
||||||
|
@ -77,15 +77,16 @@ class Api::V1::Projects::Contents::BatchCreateService < ApplicationService
|
||||||
end
|
end
|
||||||
|
|
||||||
def excute_data_to_gitea
|
def excute_data_to_gitea
|
||||||
|
puts request_body.to_json
|
||||||
@gitea_data = $gitea_client.post_repos_contents_batch_by_owner_repo(owner, repo, {body: request_body.to_json, query: request_params}) rescue nil
|
@gitea_data = $gitea_client.post_repos_contents_batch_by_owner_repo(owner, repo, {body: request_body.to_json, query: request_params}) rescue nil
|
||||||
raise Error, '创建文件失败!' unless @gitea_data.is_a?(Hash)
|
raise Error, '提交文件失败!' unless @gitea_data.is_a?(Hash)
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_branch_exist
|
def check_branch_exist
|
||||||
result = $gitea_client.get_repos_branch_name_set_by_owner_repo(owner, repo, {query: request_params} ) rescue nil
|
result = $gitea_client.get_repos_branch_name_set_by_owner_repo(owner, repo, {query: request_params} ) rescue nil
|
||||||
raise Error, '查询分支名称失败!' unless result.is_a?(Hash)
|
raise Error, '查询分支名称失败!' unless result.is_a?(Hash)
|
||||||
raise Error, '分支不存在!' unless result['branch_name'].include?(branch)
|
raise Error, '分支不存在!' unless result['branch_name'].include?(branch)
|
||||||
raise Error, '分支已存在!' if result['branch_name'].include?(new_branch) && new_branch.nil?
|
raise Error, '分支已存在!' if result['branch_name'].include?(new_branch) && !new_branch.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
|
@ -0,0 +1,32 @@
|
||||||
|
class Api::V1::Projects::Pulls::GetService < ApplicationService
|
||||||
|
|
||||||
|
attr_reader :project, :pull_request, :owner, :repo, :index, :token
|
||||||
|
attr_accessor :gitea_data
|
||||||
|
|
||||||
|
def initialize(project, pull_request, token = nil)
|
||||||
|
@project = project
|
||||||
|
@pull_request = pull_request
|
||||||
|
@owner = project&.owner.login
|
||||||
|
@repo = project&.identifier
|
||||||
|
@index = pull_request.gitea_number
|
||||||
|
@token = token
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
load_gitea_data
|
||||||
|
|
||||||
|
gitea_data
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def request_params
|
||||||
|
{
|
||||||
|
access_token: token
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_gitea_data
|
||||||
|
@gitea_data = $gitea_client.get_repos_pulls_by_owner_repo_index(owner, repo, index, {query: request_params})
|
||||||
|
# raise Error, '获取合并请求失败!' unless @gitea_data.is_a?(Hash)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,48 @@
|
||||||
|
class Api::V1::Projects::Pulls::Journals::CreateService < ApplicationService
|
||||||
|
include ActiveModel::Model
|
||||||
|
|
||||||
|
attr_reader :project, :pull_request, :issue, :parent_id, :line_code, :note, :commit_id, :path, :type, :diff, :review_id, :user
|
||||||
|
attr_accessor :journal
|
||||||
|
|
||||||
|
validates :type, inclusion: {in: %w(comment problem), message: '请输入正确的Type'}
|
||||||
|
|
||||||
|
def initialize(project, pull_request, params, user)
|
||||||
|
@project = project
|
||||||
|
@pull_request = pull_request
|
||||||
|
@issue = pull_request&.issue
|
||||||
|
@parent_id = params[:parent_id]
|
||||||
|
@line_code = params[:line_code]
|
||||||
|
@note = params[:note]
|
||||||
|
@commit_id = params[:commit_id]
|
||||||
|
@path = params[:path]
|
||||||
|
@type = params[:type] || "comment"
|
||||||
|
@diff = params[:diff]
|
||||||
|
@review_id = params[:review_id]
|
||||||
|
@user = user
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
raise Error, errors.full_messages.join(", ") unless valid?
|
||||||
|
check_review_is_exists if review_id.present?
|
||||||
|
if type == 'problem'
|
||||||
|
create_problem_journal
|
||||||
|
else
|
||||||
|
create_comment_journal
|
||||||
|
end
|
||||||
|
|
||||||
|
journal
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def create_comment_journal
|
||||||
|
@journal = pull_request.journals.create!(user_id: user&.id, notes: note, parent_id: parent_id, review_id: review_id, commit_id: commit_id, diff: diff, line_code: line_code, path: path)
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_review_is_exists
|
||||||
|
raise Error, '合并请求审查不存在!' unless @pull_request.reviews.exists?(review_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_problem_journal
|
||||||
|
@journal = pull_request.journals.create!(user_id: user&.id, notes: note, parent_id: parent_id, review_id: review_id, commit_id: commit_id, diff: diff, line_code: line_code, path: path, need_respond: true)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,57 @@
|
||||||
|
class Api::V1::Projects::Pulls::Journals::ListService < ApplicationService
|
||||||
|
include ActiveModel::Model
|
||||||
|
|
||||||
|
attr_reader :project, :pull_request, :keyword, :review_id, :need_respond, :state, :parent_id, :path, :is_full, :sort_by, :sort_direction, :user
|
||||||
|
attr_accessor :queried_journals
|
||||||
|
|
||||||
|
validates :sort_by, inclusion: {in: Journal.column_names, message: '请输入正确的SortBy'}
|
||||||
|
validates :sort_direction, inclusion: {in: %w(asc desc), message: '请输入正确的SortDirection'}
|
||||||
|
validates :need_respond, inclusion: {in: [true, false], message: '请输入正确的NeedRespond'}, allow_nil: true
|
||||||
|
validates :is_full, inclusion: {in: [true, false], message: '请输入正确的IsFull'}
|
||||||
|
validates :state, inclusion: {in: %w(opened resolved disabled)}, allow_nil: true
|
||||||
|
|
||||||
|
def initialize(project, pull_request, params, user)
|
||||||
|
@project = project
|
||||||
|
@pull_request = pull_request
|
||||||
|
@keyword = params[:keyword]
|
||||||
|
@review_id = params[:review_id]
|
||||||
|
@need_respond = ActiveModel::Type::Boolean.new.cast(params[:need_respond])
|
||||||
|
@state = params[:state]
|
||||||
|
@parent_id = params[:parent_id]
|
||||||
|
@sort_by = params[:sort_by] || 'created_on'
|
||||||
|
@sort_direction = params[:sort_direction] || 'asc'
|
||||||
|
@is_full = ActiveModel::Type::Boolean.new.cast(params[:is_full]) || false
|
||||||
|
@path = params[:path]
|
||||||
|
@user = user
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
raise Error, errors.full_messages.join(",") unless valid?
|
||||||
|
journal_query_data
|
||||||
|
|
||||||
|
queried_journals
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def journal_query_data
|
||||||
|
journals = @pull_request.journals
|
||||||
|
if !is_full
|
||||||
|
if parent_id.present?
|
||||||
|
journals = journals.where(parent_id: parent_id)
|
||||||
|
else
|
||||||
|
journals = journals.parent_journals
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
journals = journals.where(review_id: review_id) if review_id.present?
|
||||||
|
journals = journals.where(need_respond: need_respond) if need_respond.present?
|
||||||
|
journals = journals.where(state: state) if state.present?
|
||||||
|
journals = journals.where(path: path) if path.present?
|
||||||
|
|
||||||
|
q = journals.ransack(notes_cont: keyword)
|
||||||
|
scope = q.result.includes(:user, :resolveer, :children_journals, review: [:reviewer, pull_request: :issue])
|
||||||
|
scope = scope.order("journals.#{sort_by} #{sort_direction}")
|
||||||
|
|
||||||
|
@queried_journals = scope
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,38 @@
|
||||||
|
class Api::V1::Projects::Pulls::Journals::UpdateService < ApplicationService
|
||||||
|
include ActiveModel::Model
|
||||||
|
|
||||||
|
attr_reader :project, :pull_request, :journal, :note, :commit_id, :state, :user
|
||||||
|
attr_accessor :updated_journal
|
||||||
|
|
||||||
|
validates :state, inclusion: {in: %w(opened resolved disabled)}
|
||||||
|
|
||||||
|
def initialize(project, pull_request, journal, params, user)
|
||||||
|
@project = project
|
||||||
|
@pull_request = pull_request
|
||||||
|
@journal = journal
|
||||||
|
@note = params[:note]
|
||||||
|
@commit_id = params[:commit_id]
|
||||||
|
@state = params[:state]
|
||||||
|
@user = user
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
raise Error, errors.full_messages.join(", ") unless valid?
|
||||||
|
|
||||||
|
update_journal
|
||||||
|
|
||||||
|
updated_journal
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def update_journal
|
||||||
|
journal.attributes = {notes: note, commit_id: commit_id, state: state}
|
||||||
|
if state == 'resolved'
|
||||||
|
journal.resolve_at = Time.now
|
||||||
|
journal.resolveer_id = user.id
|
||||||
|
end
|
||||||
|
return Error, '保存评论失败!' unless journal.save
|
||||||
|
|
||||||
|
@updated_journal = journal.reload
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,48 @@
|
||||||
|
class Api::V1::Projects::Pulls::ListService < ApplicationService
|
||||||
|
include ActiveModel::Model
|
||||||
|
|
||||||
|
attr_reader :project, :keyword, :status, :priority_id, :issue_tag_id, :version_id, :reviewer_id, :assign_user_id, :sort_by, :sort_direction
|
||||||
|
attr_accessor :queried_pull_requests
|
||||||
|
|
||||||
|
validates :status, inclusion: {in: [0, 1, 2], message: "请输入正确的Status"}, allow_nil: true
|
||||||
|
validates :sort_by, inclusion: {in: PullRequest.column_names, message: '请输入正确的SortBy'}
|
||||||
|
validates :sort_direction, inclusion: {in: %w(asc desc), message: '请输入正确的SortDirection'}
|
||||||
|
|
||||||
|
def initialize(project, params={})
|
||||||
|
@project = project
|
||||||
|
@keyword = params[:keyword]
|
||||||
|
@status = params[:status].present? ? params[:status].to_i : nil
|
||||||
|
@priority_id = params[:priority_id]
|
||||||
|
@issue_tag_id = params[:issue_tag_id]
|
||||||
|
@version_id = params[:version_id]
|
||||||
|
@reviewer_id = params[:reviewer_id]
|
||||||
|
@assign_user_id = params[:assign_user_id]
|
||||||
|
@sort_by = params[:sort_by] || 'created_at'
|
||||||
|
@sort_direction = params[:sort_direction] || 'desc'
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
raise Error, errors.full_messages.join(",") unless valid?
|
||||||
|
pull_request_query_data
|
||||||
|
|
||||||
|
queried_pull_requests
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def pull_request_query_data
|
||||||
|
pull_requests = @project.pull_requests
|
||||||
|
|
||||||
|
pull_requests = pull_requests.where(status: status) if status.present?
|
||||||
|
pull_requests = pull_requests.where(issues: {priority_id: priority_id}) if priority_id.present?
|
||||||
|
pull_requests = pull_requests.where(issue_tags: {id: issue_tag_id}) if issue_tag_id.present?
|
||||||
|
pull_requests = pull_requests.where(issues: {fixed_version_id: version_id}) if version_id.present?
|
||||||
|
pull_requests = pull_requests.where(users: {id: reviewer_id}) if reviewer_id.present?
|
||||||
|
pull_requests = pull_requests.where(issues: {assigned_to_id: assign_user_id}) if assign_user_id.present?
|
||||||
|
|
||||||
|
q = pull_requests.ransack(title_or_body_cont: keyword)
|
||||||
|
scope = q.result.includes(:fork_project, :journals, :reviews, :reviewers, issue: [:journals, :priority, :version, :issue_tags])
|
||||||
|
scope = scope.order("pull_requests.#{sort_by} #{sort_direction}")
|
||||||
|
|
||||||
|
@queried_pull_requests = scope
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,4 +1,4 @@
|
||||||
class Api::V1::Projects::PullRequests::Reviews::CreateService < ApplicationService
|
class Api::V1::Projects::Pulls::Reviews::CreateService < ApplicationService
|
||||||
include ActiveModel::Model
|
include ActiveModel::Model
|
||||||
|
|
||||||
attr_reader :project, :pull_request, :issue, :status, :commit_id, :content, :current_user
|
attr_reader :project, :pull_request, :issue, :status, :commit_id, :content, :current_user
|
||||||
|
@ -20,21 +20,18 @@ class Api::V1::Projects::PullRequests::Reviews::CreateService < ApplicationServi
|
||||||
raise Error, errors.full_messages.join(", ") unless valid?
|
raise Error, errors.full_messages.join(", ") unless valid?
|
||||||
ActiveRecord::Base.transaction do
|
ActiveRecord::Base.transaction do
|
||||||
create_review
|
create_review
|
||||||
create_journal
|
# create_journal
|
||||||
end
|
end
|
||||||
|
|
||||||
return @journal, @review
|
@review
|
||||||
rescue
|
# rescue
|
||||||
raise Error, '服务器错误,请联系系统管理员!'
|
# raise Error, '服务器错误,请联系系统管理员!'
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def create_review
|
def create_review
|
||||||
@review = issue.reviews.create!(status: status, content: content, commit_id: commit_id, reviewer_id: @current_user.id)
|
@review = pull_request.reviews.create!(status: status, content: content, commit_id: commit_id, reviewer_id: @current_user.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_journal
|
|
||||||
@journal = issue.journals.create!(notes: content, user_id: @current_user.id, review_id: @review.id)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
|
@ -0,0 +1,36 @@
|
||||||
|
class Api::V1::Projects::Pulls::Versions::GetDiffService < ApplicationService
|
||||||
|
|
||||||
|
attr_reader :project, :pull_request, :version_id, :owner, :repo, :index, :filepath, :token
|
||||||
|
attr_accessor :gitea_data
|
||||||
|
|
||||||
|
def initialize(project, pull_request, version_id, params, token=nil)
|
||||||
|
@project = project
|
||||||
|
@pull_request = pull_request
|
||||||
|
@version_id = version_id
|
||||||
|
@owner = project&.owner.login
|
||||||
|
@repo = project&.identifier
|
||||||
|
@index = pull_request.gitea_number
|
||||||
|
@filepath = params[:filepath]
|
||||||
|
@token = token
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
load_gitea_data
|
||||||
|
|
||||||
|
gitea_data
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def request_params
|
||||||
|
params = {
|
||||||
|
access_token: token
|
||||||
|
}
|
||||||
|
params.merge!(filepath: filepath) if filepath.present?
|
||||||
|
params
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_gitea_data
|
||||||
|
@gitea_data = $gitea_client.get_repos_pulls_versions_diff_by_owner_repo_index_version_id(owner, repo, index, version_id, {query: request_params})
|
||||||
|
raise Error, '获取合并请求版本diff失败!' unless @gitea_data.is_a?(Hash)
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,36 @@
|
||||||
|
class Api::V1::Projects::Pulls::Versions::ListService < ApplicationService
|
||||||
|
|
||||||
|
attr_reader :project, :pull_request, :token, :owner, :repo, :index, :page, :limit
|
||||||
|
attr_accessor :gitea_data
|
||||||
|
|
||||||
|
def initialize(project, pull_request, params, token = nil)
|
||||||
|
@project = project
|
||||||
|
@pull_request = pull_request
|
||||||
|
@owner = project&.owner.login
|
||||||
|
@repo = project&.identifier
|
||||||
|
@page = params[:page] || 1
|
||||||
|
@limit = params[:limit] || 15
|
||||||
|
@index = pull_request.gitea_number
|
||||||
|
@token = token
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
load_gitea_data
|
||||||
|
|
||||||
|
gitea_data
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def request_params
|
||||||
|
{
|
||||||
|
access_token: token,
|
||||||
|
page: page,
|
||||||
|
limit: limit
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_gitea_data
|
||||||
|
@gitea_data = $gitea_client.get_repos_pulls_versions_by_owner_repo_index(owner, repo, index, {query: request_params})
|
||||||
|
raise Error, '获取合并请求版本失败!' unless @gitea_data.is_a?(Hash)
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,14 +1,14 @@
|
||||||
class Api::V1::Projects::Webhooks::CreateService < ApplicationService
|
class Api::V1::Projects::Webhooks::CreateService < ApplicationService
|
||||||
include ActiveModel::Model
|
include ActiveModel::Model
|
||||||
|
|
||||||
attr_reader :project, :token, :owner, :repo, :active, :branch_filter, :content_type, :url, :http_method, :secret, :events
|
attr_reader :project, :token, :owner, :repo, :active, :branch_filter, :content_type, :url, :http_method, :secret, :events, :type
|
||||||
attr_accessor :gitea_data
|
attr_accessor :gitea_data
|
||||||
|
|
||||||
validates :url, format: { with: URI::regexp(%w[http https]), message: "请输入正确的地址" }
|
validates :url, format: { with: URI::regexp(%w[http https]), message: "请输入正确的地址" }
|
||||||
validates :active, inclusion: {in: [true, false]}
|
validates :active, inclusion: {in: [true, false]}
|
||||||
validates :http_method, inclusion: { in: %w(POST GET), message: "请输入正确的请求方式"}
|
validates :http_method, inclusion: { in: %w(POST GET), message: "请输入正确的请求方式"}
|
||||||
validates :content_type, inclusion: { in: %w(json form), message: "请输入正确的Content Type"}
|
validates :content_type, inclusion: { in: %w(json form), message: "请输入正确的Content Type"}
|
||||||
|
validates :type, inclusion: {in: %w(gitea slack discord dingtalk telegram msteams feishu matrix jianmu), message: "请输入正确的Webhook Type"}
|
||||||
def initialize(project, params, token=nil)
|
def initialize(project, params, token=nil)
|
||||||
@project = project
|
@project = project
|
||||||
@owner = project&.owner.login
|
@owner = project&.owner.login
|
||||||
|
@ -20,6 +20,7 @@ class Api::V1::Projects::Webhooks::CreateService < ApplicationService
|
||||||
@http_method = params[:http_method]
|
@http_method = params[:http_method]
|
||||||
@secret = params[:secret]
|
@secret = params[:secret]
|
||||||
@events = params[:events]
|
@events = params[:events]
|
||||||
|
@type = params[:type] || "gitea"
|
||||||
@token = token
|
@token = token
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -52,7 +53,7 @@ class Api::V1::Projects::Webhooks::CreateService < ApplicationService
|
||||||
secret: secret
|
secret: secret
|
||||||
},
|
},
|
||||||
events: events || [],
|
events: events || [],
|
||||||
type: 'gitea',
|
type: type,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ class Api::V1::Users::Projects::ListService < ApplicationService
|
||||||
def initialize(observe_user, params, current_user=nil)
|
def initialize(observe_user, params, current_user=nil)
|
||||||
@observe_user = observe_user
|
@observe_user = observe_user
|
||||||
@category = params[:category] || 'all'
|
@category = params[:category] || 'all'
|
||||||
@is_public = params[:is_public]
|
@is_public = ActiveModel::Type::Boolean.new.cast(params[:is_public])
|
||||||
@project_type = params[:project_type]
|
@project_type = params[:project_type]
|
||||||
@sort_by = params[:sort_by] || 'updated_on'
|
@sort_by = params[:sort_by] || 'updated_on'
|
||||||
@sort_direction = params[:sort_direction] || 'desc'
|
@sort_direction = params[:sort_direction] || 'desc'
|
||||||
|
@ -53,6 +53,8 @@ class Api::V1::Users::Projects::ListService < ApplicationService
|
||||||
projects = Project.from("( #{normal_projects} UNION #{org_projects} ) AS projects").distinct
|
projects = Project.from("( #{normal_projects} UNION #{org_projects} ) AS projects").distinct
|
||||||
when 'watched'
|
when 'watched'
|
||||||
projects = projects.where.not(user_id: observe_user.id).joins(:watchers).where(watchers: {watchable_type: "Project", user_id: observe_user.id})
|
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'
|
when 'forked'
|
||||||
fork_ids = observe_user.fork_users.select(:id, :fork_project_id).pluck(:fork_project_id)
|
fork_ids = observe_user.fork_users.select(:id, :fork_project_id).pluck(:fork_project_id)
|
||||||
projects = projects.where(id: fork_ids)
|
projects = projects.where(id: fork_ids)
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue