Merge pull request '20230112版本' (#314) from Trustie/forgeplus:trustie_server into develop
This commit is contained in:
commit
7a9a107423
6
Gemfile
6
Gemfile
|
@ -118,6 +118,10 @@ gem 'deep_cloneable', '~> 3.0.0'
|
||||||
# oauth2
|
# oauth2
|
||||||
gem 'omniauth', '~> 1.9.0'
|
gem 'omniauth', '~> 1.9.0'
|
||||||
gem 'omniauth-oauth2', '~> 1.6.0'
|
gem 'omniauth-oauth2', '~> 1.6.0'
|
||||||
|
gem "omniauth-github"
|
||||||
|
gem "omniauth-rails_csrf_protection"
|
||||||
|
gem 'omniauth-gitee', '~> 1.0.0'
|
||||||
|
gem "omniauth-wechat-oauth2"
|
||||||
|
|
||||||
# global var
|
# global var
|
||||||
gem 'request_store'
|
gem 'request_store'
|
||||||
|
@ -135,4 +139,4 @@ gem 'doorkeeper'
|
||||||
|
|
||||||
gem 'doorkeeper-jwt'
|
gem 'doorkeeper-jwt'
|
||||||
|
|
||||||
gem 'gitea-client', '~> 0.10.2'
|
gem 'gitea-client', '~> 0.11.1'
|
|
@ -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)
|
||||||
|
@ -139,6 +141,7 @@ class AccountsController < ApplicationController
|
||||||
Register::Form.new(register_params).validate!
|
Register::Form.new(register_params).validate!
|
||||||
|
|
||||||
user = Users::RegisterService.call(register_params)
|
user = Users::RegisterService.call(register_params)
|
||||||
|
user.mail = "#{user.login}@example.org" if user.mail.blank?
|
||||||
password = register_params[:password].strip
|
password = register_params[:password].strip
|
||||||
|
|
||||||
# gitea用户注册, email, username, password
|
# gitea用户注册, email, username, password
|
||||||
|
@ -150,6 +153,10 @@ class AccountsController < ApplicationController
|
||||||
user.gitea_uid = gitea_user[:body]['id']
|
user.gitea_uid = gitea_user[:body]['id']
|
||||||
if user.save!
|
if user.save!
|
||||||
UserExtension.create!(user_id: user.id)
|
UserExtension.create!(user_id: user.id)
|
||||||
|
# 绑定授权账号
|
||||||
|
if ["qq", "wechat", "gitee", "github", "educoder"].include?(params[:type].to_s) && session[:unionid].present?
|
||||||
|
"OpenUsers::#{params[:type].to_s.capitalize}".constantize.create!(user: user, uid: session[:unionid])
|
||||||
|
end
|
||||||
successful_authentication(user)
|
successful_authentication(user)
|
||||||
render_ok
|
render_ok
|
||||||
end
|
end
|
||||||
|
@ -391,7 +398,7 @@ class AccountsController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def register_params
|
def register_params
|
||||||
params.permit(:login, :namespace, :password, :password_confirmation, :code)
|
params.permit(:login, :namespace, :password, :password_confirmation, :code, :type)
|
||||||
end
|
end
|
||||||
|
|
||||||
def reset_password_params
|
def reset_password_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
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
class Admins::FeedbacksController < Admins::BaseController
|
||||||
|
before_action :get_feedback, only: [:new_history, :create_history, :destroy]
|
||||||
|
|
||||||
|
def index
|
||||||
|
sort_by = Feedback.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'created_at'
|
||||||
|
sort_direction = %w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc'
|
||||||
|
feedbacks = Feedback.order("#{sort_by} #{sort_direction}")
|
||||||
|
@feedbacks = paginate(feedbacks)
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
if @feedback.destroy
|
||||||
|
redirect_to admins_feedbacks_path
|
||||||
|
flash[:success] = "反馈意见删除成功"
|
||||||
|
else
|
||||||
|
redirect_to admins_feedbacks_path
|
||||||
|
flash[:danger] = "反馈意见删除失败"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def new_history
|
||||||
|
@feedback_message_history = FeedbackMessageHistory.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_history
|
||||||
|
@feedback_message_history = @feedback.feedback_message_histories.new(feedback_message_history_params)
|
||||||
|
@feedback_message_history.user = current_user
|
||||||
|
if @feedback_message_history.save
|
||||||
|
redirect_to admins_feedbacks_path
|
||||||
|
flash[:success] = "发送通知成功"
|
||||||
|
else
|
||||||
|
redirect_to admins_feedbacks_path
|
||||||
|
flash[:danger] = @feedback_message_history.errors.full_messages.join(", ")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def feedback_params
|
||||||
|
params.require(:feedback).permit!
|
||||||
|
end
|
||||||
|
|
||||||
|
def feedback_message_history_params
|
||||||
|
params.require(:feedback_message_history).permit(:title, :content)
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_feedback
|
||||||
|
@feedback = Feedback.find_by_id(params[:id])
|
||||||
|
end
|
||||||
|
end
|
|
@ -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
|
||||||
|
@ -52,6 +53,6 @@ class Admins::Topic::BannersController < Admins::Topic::BaseController
|
||||||
end
|
end
|
||||||
|
|
||||||
def banner_params
|
def banner_params
|
||||||
params.require(:topic_banner).permit(:title, :order_index)
|
params.require(:topic_banner).permit(:title, :order_index, :url)
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -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
|
|
@ -0,0 +1,8 @@
|
||||||
|
class Api::V1::Projects::CodeStatsController < Api::V1::BaseController
|
||||||
|
before_action :require_public_and_member_above, only: [:index]
|
||||||
|
|
||||||
|
def index
|
||||||
|
@result_object = Api::V1::Projects::CodeStats::ListService.call(@project, {ref: params[:ref]}, current_user&.gitea_token)
|
||||||
|
puts @result_object
|
||||||
|
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
|
|
@ -0,0 +1,16 @@
|
||||||
|
class Api::V1::Users::FeedbacksController < Api::V1::BaseController
|
||||||
|
|
||||||
|
before_action :load_observe_user
|
||||||
|
before_action :check_auth_for_observe_user
|
||||||
|
|
||||||
|
def create
|
||||||
|
@result = Api::V1::Users::Feedbacks::CreateService.call(@observe_user, feedback_params)
|
||||||
|
return render_error("反馈意见创建失败.") if @result.nil?
|
||||||
|
return render_ok
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def feedback_params
|
||||||
|
params.permit(:content)
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,6 +1,105 @@
|
||||||
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 check_phone_verify_code
|
||||||
|
code = strip(params[:code])
|
||||||
|
phone = strip(params[:phone])
|
||||||
|
code_type = params[:code_type]
|
||||||
|
|
||||||
|
return tip_exception(-2, "手机号格式有误") unless phone =~ CustomRegexp::PHONE
|
||||||
|
|
||||||
|
verifi_code = VerificationCode.where(phone: phone, 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
|
||||||
|
|
||||||
|
def update_phone
|
||||||
|
@result_object = Api::V1::Users::UpdatePhoneService.call(@observe_user, params)
|
||||||
|
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)
|
||||||
|
@ -79,8 +79,7 @@ class ApplicationController < ActionController::Base
|
||||||
# 判断用户的邮箱或者手机是否可用
|
# 判断用户的邮箱或者手机是否可用
|
||||||
# params[:type] 1: 注册;2:忘记密码;3:绑定
|
# params[:type] 1: 注册;2:忘记密码;3:绑定
|
||||||
def check_mail_and_phone_valid login, type
|
def check_mail_and_phone_valid login, type
|
||||||
unless login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/ || login =~ /^1\d{10}$/ ||
|
unless login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/ || login =~ /^1\d{10}$/
|
||||||
login =~ /^[a-zA-Z0-9]+([._\\]*[a-zA-Z0-9])$/
|
|
||||||
tip_exception(-2, "请输入正确的手机号或邮箱")
|
tip_exception(-2, "请输入正确的手机号或邮箱")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -103,8 +102,10 @@ class ApplicationController < ActionController::Base
|
||||||
when 1, 2, 4, 9
|
when 1, 2, 4, 9
|
||||||
# 手机类型的发送
|
# 手机类型的发送
|
||||||
sigle_para = {phone: value}
|
sigle_para = {phone: value}
|
||||||
status = Gitlink::Sms.send(mobile: value, code: code)
|
# status = Gitlink::Sms.send(mobile: value, code: code)
|
||||||
tip_exception(-2, code_msg(status)) if status != 0
|
# tip_exception(-2, code_msg(status)) if status != 0
|
||||||
|
status = Sms::UcloudService.call(value, code, send_type)
|
||||||
|
tip_exception(-2, ucloud_code_msg(status)) if status != 0
|
||||||
when 8, 3, 5
|
when 8, 3, 5
|
||||||
# 邮箱类型的发送
|
# 邮箱类型的发送
|
||||||
sigle_para = {email: value}
|
sigle_para = {email: value}
|
||||||
|
@ -116,8 +117,13 @@ class ApplicationController < ActionController::Base
|
||||||
send_email_control = LimitForbidControl::SendEmailCode.new(value)
|
send_email_control = LimitForbidControl::SendEmailCode.new(value)
|
||||||
tip_exception(-1, '邮件发送太频繁,请稍后再试') if send_email_control.forbid?
|
tip_exception(-1, '邮件发送太频繁,请稍后再试') if send_email_control.forbid?
|
||||||
begin
|
begin
|
||||||
UserMailer.register_email(value, code).deliver_now
|
if send_type == 3
|
||||||
|
UserMailer.find_password(value, code).deliver_now
|
||||||
|
elsif send_type == 5
|
||||||
|
UserMailer.bind_email(value, code).deliver_now
|
||||||
|
else
|
||||||
|
UserMailer.register_email(value, code).deliver_now
|
||||||
|
end
|
||||||
Rails.cache.write(send_email_limit_cache_key, 1, expires_in: 1.minute)
|
Rails.cache.write(send_email_limit_cache_key, 1, expires_in: 1.minute)
|
||||||
send_email_control.increment!
|
send_email_control.increment!
|
||||||
# Mailer.run.email_register(code, value)
|
# Mailer.run.email_register(code, value)
|
||||||
|
@ -149,6 +155,27 @@ class ApplicationController < ActionController::Base
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def ucloud_code_msg status
|
||||||
|
case status
|
||||||
|
when 0
|
||||||
|
"验证码已经发送到您的手机,请注意查收"
|
||||||
|
when 171
|
||||||
|
"API签名错误"
|
||||||
|
when 18014
|
||||||
|
"无效手机号码"
|
||||||
|
when 18017
|
||||||
|
"无效模板"
|
||||||
|
when 18018
|
||||||
|
"短信模板参数与短信模板不匹配"
|
||||||
|
when 18023
|
||||||
|
"短信内容中含有运营商拦截的关键词"
|
||||||
|
when 18033
|
||||||
|
"变量内容不符合规范"
|
||||||
|
else
|
||||||
|
"错误码#{status}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def validate_type(object_type)
|
def validate_type(object_type)
|
||||||
normal_status(2, "参数") if params.has_key?(:sort_type) && !SORT_TYPE.include?(params[:sort_type].strip)
|
normal_status(2, "参数") if params.has_key?(:sort_type) && !SORT_TYPE.include?(params[:sort_type].strip)
|
||||||
end
|
end
|
||||||
|
@ -173,6 +200,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 +323,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 +665,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 > 50) ? 50 : 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 +750,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,258 @@
|
||||||
#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) && !url.starts_with?("#{base_url}/repo")
|
||||||
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'
|
if @file.container
|
||||||
if @file.container && current_user.logged?
|
if @file.container.is_a?(Issue)
|
||||||
if @file.container.is_a?(Issue)
|
project = @file.container.project
|
||||||
course = @file.container.project
|
candown = project.is_public || (current_user.logged? && project.member?(current_user))
|
||||||
candown = course.member?(current_user) || course.is_public
|
elsif @file.container.is_a?(Journal)
|
||||||
elsif @file.container.is_a?(Journal)
|
project = @file.container.issue.project
|
||||||
course = @file.container.issue.project
|
candown = project.is_public || (current_user.logged? && project.member?(current_user))
|
||||||
candown = course.member?(current_user)
|
else
|
||||||
else
|
project = nil
|
||||||
course = nil
|
end
|
||||||
end
|
tip_exception(403, "您没有权限进入") if project.present? && !candown
|
||||||
tip_exception(403, "您没有权限进入") if course.present? && !candown
|
end
|
||||||
tip_exception(403, "您没有权限进入") if @file.container.is_a?(ApplyUserAuthentication)
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
def send_file_with_range(path, options = {})
|
||||||
end
|
logger.info("########request.headers: #{request.headers}")
|
||||||
|
logger.info("########request.headers: #{File.exist?(path)}")
|
||||||
def send_file_with_range(path, options = {})
|
|
||||||
logger.info("########request.headers: #{request.headers}")
|
if File.exist?(path)
|
||||||
logger.info("########request.headers: #{File.exist?(path)}")
|
size = File.size(path)
|
||||||
|
logger.info("########request.headers: #{request.headers}")
|
||||||
if File.exist?(path)
|
if !request.headers["Range"]
|
||||||
size = File.size(path)
|
status_code = 200 # 200 OK
|
||||||
logger.info("########request.headers: #{request.headers}")
|
offset = 0
|
||||||
if !request.headers["Range"]
|
length = File.size(path)
|
||||||
status_code = 200 # 200 OK
|
else
|
||||||
offset = 0
|
status_code = 206 # 206 Partial Content
|
||||||
length = File.size(path)
|
bytes = Rack::Utils.byte_ranges(request.headers, size)[0]
|
||||||
else
|
offset = bytes.begin
|
||||||
status_code = 206 # 206 Partial Content
|
length = bytes.end - bytes.begin
|
||||||
bytes = Rack::Utils.byte_ranges(request.headers, size)[0]
|
end
|
||||||
offset = bytes.begin
|
response.header["Accept-Ranges"] = "bytes"
|
||||||
length = bytes.end - bytes.begin
|
response.header["Content-Range"] = "bytes #{bytes.begin}-#{bytes.end}/#{size}" if bytes
|
||||||
end
|
response.header["status"] = status_code
|
||||||
response.header["Accept-Ranges"] = "bytes"
|
|
||||||
response.header["Content-Range"] = "bytes #{bytes.begin}-#{bytes.end}/#{size}" if bytes
|
send_data IO.binread(path, length, offset), options
|
||||||
response.header["status"] = status_code
|
else
|
||||||
|
raise ActionController::MissingFile, "Cannot read file #{path}."
|
||||||
send_data IO.binread(path, length, offset), options
|
end
|
||||||
else
|
end
|
||||||
raise ActionController::MissingFile, "Cannot read file #{path}."
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
|
@ -1,35 +1,19 @@
|
||||||
class BindUsersController < ApplicationController
|
class BindUsersController < ApplicationController
|
||||||
# before_action :require_login
|
|
||||||
|
|
||||||
def create
|
def create
|
||||||
# user = CreateBindUserService.call(create_params)
|
Rails.logger.debug "--------------开始绑定用户------------"
|
||||||
#
|
Rails.logger.debug "--------------params: #{params.to_unsafe_h}"
|
||||||
if params[:type] == "qq"
|
tip_exception '系统错误' if session[:unionid].blank?
|
||||||
begin
|
|
||||||
user = CreateBindUserService.call(current_user, create_params)
|
|
||||||
successful_authentication(user) if user.id != current_user.id
|
|
||||||
|
|
||||||
render_ok
|
bind_user = User.try_to_login(params[:username], params[:password])
|
||||||
rescue ApplicationService::Error => ex
|
tip_exception '用户名或者密码错误' if bind_user.blank?
|
||||||
render_error(ex.message)
|
tip_exception '用户名或者密码错误' unless bind_user.check_password?(params[:password].to_s)
|
||||||
end
|
tip_exception '参数错误' unless ["qq", "wechat", "gitee", "github", "educoder"].include?(params[:type].to_s)
|
||||||
else
|
tip_exception '该账号已被绑定,请更换其他账号进行绑定' if bind_user.bind_open_user?(params[:type].to_s)
|
||||||
begin
|
|
||||||
tip_exception '系统错误' if session[:unionid].blank?
|
|
||||||
|
|
||||||
bind_user = User.try_to_login(params[:username], params[:password])
|
"OpenUsers::#{params[:type].to_s.capitalize}".constantize.create!(user: bind_user, uid: session[:unionid])
|
||||||
tip_exception '用户名或者密码错误' if bind_user.blank?
|
successful_authentication(bind_user)
|
||||||
tip_exception '用户名或者密码错误' unless bind_user.check_password?(params[:password].to_s)
|
@user = bind_user
|
||||||
tip_exception '该账号已被绑定,请更换其他账号进行绑定' if bind_user.bind_open_user?(params[:type].to_s)
|
|
||||||
|
|
||||||
OpenUsers::Wechat.create!(user: bind_user, uid: session[:unionid])
|
|
||||||
successful_authentication(bind_user)
|
|
||||||
|
|
||||||
render_ok
|
|
||||||
rescue Exception => e
|
|
||||||
render_error(e.message)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def new_user
|
def new_user
|
||||||
|
|
|
@ -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
|
|
@ -11,7 +11,7 @@ module LoginHelper
|
||||||
|
|
||||||
def set_autologin_cookie(user)
|
def set_autologin_cookie(user)
|
||||||
token = Token.get_or_create_permanent_login_token(user, "autologin")
|
token = Token.get_or_create_permanent_login_token(user, "autologin")
|
||||||
sync_user_token_to_trustie(user.login, token.value)
|
# sync_user_token_to_trustie(user.login, token.value)
|
||||||
|
|
||||||
Rails.logger.info "###### def set_autologin_cookie and get_or_create_permanent_login_token result: #{token&.value}"
|
Rails.logger.info "###### def set_autologin_cookie and get_or_create_permanent_login_token result: #{token&.value}"
|
||||||
cookie_options = {
|
cookie_options = {
|
||||||
|
|
|
@ -1,21 +1,25 @@
|
||||||
module RegisterHelper
|
module RegisterHelper
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
def autologin_register(username, email, password, platform= 'forge', need_edit_info = false)
|
def autologin_register(username, email, password, platform = 'forge', phone = nil, nickname =nil, need_edit_info = false)
|
||||||
result = {message: nil, user: nil}
|
result = {message: nil, user: nil}
|
||||||
|
email = email.blank? ? "#{username}@example.org" : email
|
||||||
|
|
||||||
user = User.new(admin: false, login: username, mail: email, type: "User")
|
user = User.new(admin: false, login: username, mail: email, type: "User")
|
||||||
user.password = password
|
user.password = password
|
||||||
user.platform = platform
|
user.platform = platform
|
||||||
|
user.phone = phone if phone.present?
|
||||||
|
user.nickname = nickname if nickname.present?
|
||||||
if need_edit_info
|
if need_edit_info
|
||||||
user.need_edit_info
|
user.need_edit_info
|
||||||
else
|
else
|
||||||
user.activate
|
user.activate
|
||||||
end
|
end
|
||||||
|
|
||||||
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 +30,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
|
||||||
|
@ -66,7 +70,7 @@ module RegisterHelper
|
||||||
user.password = params[:password]
|
user.password = params[:password]
|
||||||
user.mail = params[:email]
|
user.mail = params[:email]
|
||||||
|
|
||||||
if user.save!
|
if user.save!
|
||||||
sync_params = {
|
sync_params = {
|
||||||
password: params[:password].to_s,
|
password: params[:password].to_s,
|
||||||
email: params[:email],
|
email: params[:email],
|
||||||
|
@ -74,9 +78,9 @@ module RegisterHelper
|
||||||
new_name: params[:username],
|
new_name: params[:username],
|
||||||
source_id: 0
|
source_id: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
interactor = Gitea::User::UpdateInteractor.call(before_login, sync_params)
|
interactor = Gitea::User::UpdateInteractor.call(before_login, sync_params)
|
||||||
if interactor.success?
|
if interactor.success?
|
||||||
result[:user] = user
|
result[:user] = user
|
||||||
else
|
else
|
||||||
result[:message] = '用户同步Gitea失败!'
|
result[:message] = '用户同步Gitea失败!'
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -7,7 +7,7 @@ class IssueTagsController < ApplicationController
|
||||||
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
issue_tags = @project.issue_tags.reorder("#{order_name} #{order_type}")
|
issue_tags = @project.issue_tags.includes(:issues).reorder("issue_tags.#{order_name} #{order_type}")
|
||||||
@user_admin_or_member = current_user.present? && (current_user.admin || @project.member?(current_user))
|
@user_admin_or_member = current_user.present? && (current_user.admin || @project.member?(current_user))
|
||||||
@page = params[:page] || 1
|
@page = params[:page] || 1
|
||||||
@limit = params[:limit] || 15
|
@limit = params[:limit] || 15
|
||||||
|
|
|
@ -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
|
|
@ -3,6 +3,7 @@ class Oauth::BaseController < ActionController::Base
|
||||||
include LoginHelper
|
include LoginHelper
|
||||||
include ControllerRescueHandler
|
include ControllerRescueHandler
|
||||||
include LoggerHelper
|
include LoggerHelper
|
||||||
|
include RegisterHelper
|
||||||
# include LaboratoryHelper
|
# include LaboratoryHelper
|
||||||
|
|
||||||
skip_before_action :verify_authenticity_token
|
skip_before_action :verify_authenticity_token
|
||||||
|
@ -13,13 +14,13 @@ class Oauth::BaseController < ActionController::Base
|
||||||
|
|
||||||
private
|
private
|
||||||
def tip_exception(status = -1, message)
|
def tip_exception(status = -1, message)
|
||||||
raise Educoder::TipException.new(status, message)
|
raise Gitlink::TipException.new(status, message)
|
||||||
end
|
end
|
||||||
|
|
||||||
def tip_show_exception(status = -2, message)
|
def tip_show_exception(status = -2, message)
|
||||||
raise Educoder::TipException.new(status, message)
|
raise Gitlink::TipException.new(status, message)
|
||||||
end
|
end
|
||||||
|
|
||||||
def tip_show(exception)
|
def tip_show(exception)
|
||||||
uid_logger("Tip show status is #{exception.status}, message is #{exception.message}")
|
uid_logger("Tip show status is #{exception.status}, message is #{exception.message}")
|
||||||
render json: exception.tip_json
|
render json: exception.tip_json
|
||||||
|
@ -35,7 +36,7 @@ class Oauth::BaseController < ActionController::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def auth_hash
|
def auth_hash
|
||||||
Rails.logger.info("[OAuth2] omniauth.auth -> #{request.env['omniauth.auth'].inspect}")
|
# Rails.logger.info("[OAuth2] omniauth.auth -> #{request.env['omniauth.auth'].inspect}")
|
||||||
request.env['omniauth.auth']
|
request.env['omniauth.auth']
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
class Oauth::CallbacksController < Oauth::BaseController
|
||||||
|
def create
|
||||||
|
process_callback_new
|
||||||
|
rescue Exception => e
|
||||||
|
Rails.logger.info "授权失败:#{e}"
|
||||||
|
tip_exception("授权失败")
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def config_providers
|
||||||
|
config = Rails.application.config_for(:configuration)
|
||||||
|
config.dig("oauth").keys
|
||||||
|
end
|
||||||
|
|
||||||
|
# QQ: {"ret":0,"msg":"","is_lost":0,"nickname":"颜值不算太高","gender":"男","gender_type":1,"province":"","city":"","year":"2013","constellation":"","figureurl":"http://qzapp.qlogo.cn/qzapp/101508858/0F860F4B329768F47B22341C5FD9089C/30","figureurl_1":"http://qzapp.qlogo.cn/qzapp/101508858/0F860F4B329768F47B22341C5FD9089C/50","figureurl_2":"http://qzapp.qlogo.cn/qzapp/101508858/0F860F4B329768F47B22341C5FD9089C/100","figureurl_qq_1":"http://thirdqq.qlogo.cn/g?b=oidb\u0026k=My3segFVHFqVmauibJQUltw\u0026s=40\u0026t=1568887757","figureurl_qq_2":"http://thirdqq.qlogo.cn/g?b=oidb\u0026k=My3segFVHFqVmauibJQUltw\u0026s=100\u0026t=1568887757","figureurl_qq":"http://thirdqq.qlogo.cn/g?b=oidb\u0026k=My3segFVHFqVmauibJQUltw\u0026s=140\u0026t=1568887757","figureurl_type":"1","is_yellow_vip":"0","vip":"0","yellow_vip_level":"0","level":"0","is_yellow_year_vip":"0"}
|
||||||
|
def process_callback
|
||||||
|
Rails.logger.info("[OAuth2] omniauth.auth -> #{request.env['omniauth.auth'].inspect}")
|
||||||
|
if auth_hash.blank?
|
||||||
|
redirect_to("/login") && return
|
||||||
|
end
|
||||||
|
|
||||||
|
new_user = false
|
||||||
|
platform = auth_hash[:provider]
|
||||||
|
uid = auth_hash[:uid]
|
||||||
|
mail = auth_hash.info.email || nil
|
||||||
|
nickname = ["gitee", "github"].include?(platform) ? auth_hash.info.name : auth_hash.info.nickname
|
||||||
|
|
||||||
|
open_user = "OpenUsers::#{platform.to_s.capitalize}".constantize.find_by(uid: uid)
|
||||||
|
if open_user.present? && open_user.user.present?
|
||||||
|
successful_authentication(open_user.user)
|
||||||
|
else
|
||||||
|
if current_user.blank? || !current_user.logged?
|
||||||
|
has_user = User.find_by(mail: mail)
|
||||||
|
if has_user.present?
|
||||||
|
"OpenUsers::#{platform.to_s.capitalize}".constantize.create!(user_id: has_user.id, uid: uid, extra: auth_hash.extra)
|
||||||
|
successful_authentication(has_user)
|
||||||
|
else
|
||||||
|
new_user = true
|
||||||
|
login = build_login_name(platform, auth_hash.info.nickname)
|
||||||
|
mail = "#{login}@example.org" if mail.blank?
|
||||||
|
code = %W(0 1 2 3 4 5 6 7 8 9)
|
||||||
|
rand_password = code.sample(10).join
|
||||||
|
reg_result = autologin_register(login, mail, rand_password, platform, nil, nickname)
|
||||||
|
Rails.logger.info("[OAuth2] omniauth.auth [reg_result] #{reg_result} ")
|
||||||
|
if reg_result[:message].blank?
|
||||||
|
open_user = "OpenUsers::#{platform.to_s.capitalize}".constantize.create!(user_id: reg_result[:user][:id], uid: uid, extra: auth_hash.extra)
|
||||||
|
successful_authentication(open_user.user)
|
||||||
|
else
|
||||||
|
tip_exception(reg_result.present? ? reg_result[:message] : "授权失败")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
"OpenUsers::#{platform.to_s.capitalize}".constantize.create!(user: current_user, uid: login, extra: auth_hash.extra)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
redirect_to root_path(new_user: new_user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def process_callback_new
|
||||||
|
Rails.logger.info("[OAuth2] omniauth.auth -> #{request.env['omniauth.auth'].inspect}")
|
||||||
|
if auth_hash.blank?
|
||||||
|
redirect_to("/login") && return
|
||||||
|
end
|
||||||
|
platform = auth_hash[:provider]
|
||||||
|
uid = auth_hash[:uid]
|
||||||
|
uid = auth_hash.info.unionid if platform == "wechat"
|
||||||
|
|
||||||
|
open_user = "OpenUsers::#{platform.to_s.capitalize}".constantize.find_by(uid: uid)
|
||||||
|
if open_user.present? && open_user.user.present?
|
||||||
|
successful_authentication(open_user.user)
|
||||||
|
redirect_to root_path(new_user: false)
|
||||||
|
return
|
||||||
|
else
|
||||||
|
if current_user.blank? || !current_user.logged?
|
||||||
|
session[:unionid] = uid
|
||||||
|
else
|
||||||
|
"OpenUsers::#{platform.to_s.capitalize}".constantize.create!(user: current_user, uid: uid)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Rails.logger.info("[OAuth2] session[:unionid] -> #{session[:unionid]}")
|
||||||
|
redirect_to "/bindlogin/#{platform}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# gitee,github nickname=login,如果系统未占用保留原用户名
|
||||||
|
def build_login_name(provider, nickname)
|
||||||
|
if ["gitee", "github"].include?(provider) && User.find_by(login: nickname).blank?
|
||||||
|
nickname
|
||||||
|
else
|
||||||
|
User.generate_user_login('p')
|
||||||
|
end
|
||||||
|
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)
|
||||||
|
@ -45,9 +46,16 @@ class Organizations::OrganizationsController < Organizations::BaseController
|
||||||
@organization.nickname = organization_params[:nickname] if organization_params[:nickname].present?
|
@organization.nickname = organization_params[:nickname] if organization_params[:nickname].present?
|
||||||
@organization.save!
|
@organization.save!
|
||||||
sync_organization_extension!
|
sync_organization_extension!
|
||||||
|
# 更改组织可见性为私有,则需将该组织下的所有仓库同步更改为私有仓库
|
||||||
|
if organization_extension_params[:visibility] == "privacy"
|
||||||
|
Project.where(user_id: @organization.id).where(is_public: true).each do |project|
|
||||||
|
update_project_private(project)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
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)
|
||||||
|
@ -121,5 +129,20 @@ class Organizations::OrganizationsController < Organizations::BaseController
|
||||||
def sync_organization_extension!
|
def sync_organization_extension!
|
||||||
@organization.organization_extension.update_attributes!(organization_extension_params)
|
@organization.organization_extension.update_attributes!(organization_extension_params)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update_project_private(project)
|
||||||
|
project.update_attributes!(is_public: false)
|
||||||
|
project.forked_projects.update_all(is_public: project.is_public)
|
||||||
|
gitea_params = {
|
||||||
|
private: true,
|
||||||
|
default_branch: project.default_branch,
|
||||||
|
website: project.website,
|
||||||
|
name: project.identifier
|
||||||
|
}
|
||||||
|
gitea_repo = Gitea::Repository::UpdateService.call(@organization, project&.repository&.identifier, gitea_params)
|
||||||
|
project.repository.update_attributes({hidden: gitea_repo["private"], identifier: gitea_repo["name"]})
|
||||||
|
# 更新对应所属分类下的项目数量(私有)
|
||||||
|
project.project_category.decrement!(:private_projects_count, 1) if project.project_category.present?
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ class ProjectCategoriesController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def group_list
|
def group_list
|
||||||
@project_categories = ProjectCategory.where('projects_count > 0').order(projects_count: :desc)
|
@project_categories = ProjectCategory.select("id, name, projects_count, private_projects_count, (projects_count - private_projects_count) as public_projects_count").having('public_projects_count > 0').order(public_projects_count: :desc)
|
||||||
# projects = Project.no_anomory_projects.visible
|
# projects = Project.no_anomory_projects.visible
|
||||||
# @category_group_list = projects.joins(:project_category).group("project_categories.id", "project_categories.name").size
|
# @category_group_list = projects.joins(:project_category).group("project_categories.id", "project_categories.name").size
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
class ProjectRankController < ApplicationController
|
class ProjectRankController < ApplicationController
|
||||||
# 根据时间获取热门项目
|
# 根据时间获取热门项目
|
||||||
def index
|
def index
|
||||||
$redis_cache.zunionstore("recent-days-project-rank", get_timeable_key_names)
|
$redis_cache.zunionstore("recent-days-project-rank-#{time}", get_timeable_key_names)
|
||||||
deleted_data = $redis_cache.smembers("v2-project-rank-deleted")
|
deleted_data = $redis_cache.smembers("v2-project-rank-deleted")
|
||||||
$redis_cache.zrem("recent-days-project-rank", deleted_data) unless deleted_data.blank?
|
$redis_cache.zrem("recent-days-project-rank-#{time}", deleted_data) unless deleted_data.blank?
|
||||||
@project_rank = $redis_cache.zrevrange("recent-days-project-rank", 0, 4, withscores: true)
|
@project_rank = $redis_cache.zrevrange("recent-days-project-rank-#{time}", 0, 9, withscores: true)
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
@project_rank = []
|
@project_rank = []
|
||||||
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!
|
||||||
|
|
|
@ -40,8 +40,9 @@ class ProjectsController < ApplicationController
|
||||||
category_id = params[:category_id]
|
category_id = params[:category_id]
|
||||||
@total_count =
|
@total_count =
|
||||||
if category_id.blank?
|
if category_id.blank?
|
||||||
ps = ProjectStatistic.first
|
# ps = ProjectStatistic.first
|
||||||
ps.common_projects_count + ps.mirror_projects_count unless ps.blank?
|
# ps.common_projects_count + ps.mirror_projects_count unless ps.blank?
|
||||||
|
@projects.total_count
|
||||||
else
|
else
|
||||||
cate = ProjectCategory.find_by(id: category_id)
|
cate = ProjectCategory.find_by(id: category_id)
|
||||||
cate&.projects_count || 0
|
cate&.projects_count || 0
|
||||||
|
@ -52,7 +53,7 @@ class ProjectsController < ApplicationController
|
||||||
ActiveRecord::Base.transaction do
|
ActiveRecord::Base.transaction do
|
||||||
Projects::CreateForm.new(project_params).validate!
|
Projects::CreateForm.new(project_params).validate!
|
||||||
@project = Projects::CreateService.new(current_user, project_params).call
|
@project = Projects::CreateService.new(current_user, project_params).call
|
||||||
|
OpenProjectDevOpsJob.perform_later(@project&.id, current_user.id)
|
||||||
end
|
end
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
uid_logger_error(e.message)
|
uid_logger_error(e.message)
|
||||||
|
@ -154,6 +155,15 @@ class ProjectsController < ApplicationController
|
||||||
}
|
}
|
||||||
gitea_repo = Gitea::Repository::UpdateService.call(@owner, @project&.repository&.identifier, gitea_params)
|
gitea_repo = Gitea::Repository::UpdateService.call(@owner, @project&.repository&.identifier, gitea_params)
|
||||||
@project.repository.update_attributes({hidden: gitea_repo["private"], identifier: gitea_repo["name"]})
|
@project.repository.update_attributes({hidden: gitea_repo["private"], identifier: gitea_repo["name"]})
|
||||||
|
# 更新对应所属分类下的项目数量(私有)
|
||||||
|
before_is_public = @project.previous_changes[:is_public].present? ? @project.previous_changes[:is_public][0] : @project.is_public
|
||||||
|
after_is_public = @project.previous_changes[:is_public].present? ? @project.previous_changes[:is_public][1] : @project.is_public
|
||||||
|
before_pc_id = @project.previous_changes[:project_category_id].present? ? @project.previous_changes[:project_category_id][0] : @project.project_category_id
|
||||||
|
after_pc_id = @project.previous_changes[:project_category_id].present? ? @project.previous_changes[:project_category_id][1] : @project.project_category_id
|
||||||
|
before_pc = ProjectCategory.find_by_id(before_pc_id)
|
||||||
|
after_pc = ProjectCategory.find_by_id(after_pc_id)
|
||||||
|
before_pc.decrement!(:private_projects_count, 1) if before_pc.present? && !before_is_public
|
||||||
|
after_pc.increment!(:private_projects_count, 1) if after_pc.present? && !after_is_public
|
||||||
end
|
end
|
||||||
SendTemplateMessageJob.perform_later('ProjectSettingChanged', current_user.id, @project&.id, @project.previous_changes.slice(:name, :description, :project_category_id, :project_language_id, :is_public, :identifier)) if Site.has_notice_menu?
|
SendTemplateMessageJob.perform_later('ProjectSettingChanged', current_user.id, @project&.id, @project.previous_changes.slice(:name, :description, :project_category_id, :project_language_id, :is_public, :identifier)) if Site.has_notice_menu?
|
||||||
end
|
end
|
||||||
|
@ -171,6 +181,8 @@ class ProjectsController < ApplicationController
|
||||||
Gitea::Repository::DeleteService.new(@project.owner, @project.identifier).call
|
Gitea::Repository::DeleteService.new(@project.owner, @project.identifier).call
|
||||||
@project.destroy!
|
@project.destroy!
|
||||||
@project.forked_projects.update_all(forked_from_project_id: nil)
|
@project.forked_projects.update_all(forked_from_project_id: nil)
|
||||||
|
# 如果该项目有所属的项目分类以及为私有项目,需要更新对应数量
|
||||||
|
@project.project_category.decrement!(:private_projects_count, 1) if @project.project_category.present? && !@project.is_public
|
||||||
render_ok
|
render_ok
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
|
|
@ -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)}"
|
||||||
|
@ -98,19 +100,8 @@ class PullRequestsController < ApplicationController
|
||||||
Issues::UpdateForm.new({subject: params[:title], description: params[:body].blank? ? params[:body] : params[:body].b}).validate!
|
Issues::UpdateForm.new({subject: params[:title], description: params[:body].blank? ? params[:body] : params[:body].b}).validate!
|
||||||
merge_params
|
merge_params
|
||||||
|
|
||||||
@issue&.issue_tags_relates&.destroy_all if params[:issue_tag_ids].blank?
|
reviewers = User.where(id: params[:reviewer_ids])
|
||||||
if params[:issue_tag_ids].present? && !@issue&.issue_tags_relates.where(issue_tag_id: params[:issue_tag_ids]).exists?
|
@pull_request.reviewers = reviewers
|
||||||
if params[:issue_tag_ids].is_a?(Array) && params[:issue_tag_ids].size > 1
|
|
||||||
return normal_status(-1, "最多只能创建一个标记。")
|
|
||||||
elsif params[:issue_tag_ids].is_a?(Array) && params[:issue_tag_ids].size == 1
|
|
||||||
@issue&.issue_tags_relates&.destroy_all
|
|
||||||
params[:issue_tag_ids].each do |tag|
|
|
||||||
IssueTagsRelate.create!(issue_id: @issue.id, issue_tag_id: tag)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
return normal_status(-1, "请输入正确的标记。")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
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)
|
||||||
|
@ -160,6 +151,8 @@ class PullRequestsController < ApplicationController
|
||||||
colsed = PullRequests::CloseService.call(@owner, @repository, @pull_request, current_user)
|
colsed = PullRequests::CloseService.call(@owner, @repository, @pull_request, current_user)
|
||||||
if colsed === true
|
if colsed === true
|
||||||
@pull_request.project_trends.create!(user: current_user, project: @project,action_type: ProjectTrend::CLOSE)
|
@pull_request.project_trends.create!(user: current_user, project: @project,action_type: ProjectTrend::CLOSE)
|
||||||
|
# 合并请求下issue处理为关闭
|
||||||
|
@issue&.update_attributes!({status_id:5})
|
||||||
SendTemplateMessageJob.perform_later('PullRequestClosed', current_user.id, @pull_request.id) if Site.has_notice_menu?
|
SendTemplateMessageJob.perform_later('PullRequestClosed', current_user.id, @pull_request.id) if Site.has_notice_menu?
|
||||||
normal_status(1, "已拒绝")
|
normal_status(1, "已拒绝")
|
||||||
else
|
else
|
||||||
|
@ -181,7 +174,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
|
||||||
|
@ -205,6 +198,8 @@ class PullRequestsController < ApplicationController
|
||||||
# @pull_request.project_trend_status!
|
# @pull_request.project_trend_status!
|
||||||
@pull_request.project_trends.create!(user: current_user, project: @project,action_type: ProjectTrend::MERGE)
|
@pull_request.project_trends.create!(user: current_user, project: @project,action_type: ProjectTrend::MERGE)
|
||||||
@issue&.custom_journal_detail("merge", "", "该合并请求已被合并", current_user&.id)
|
@issue&.custom_journal_detail("merge", "", "该合并请求已被合并", current_user&.id)
|
||||||
|
# 合并请求下issue处理为关闭
|
||||||
|
@issue&.update_attributes!({status_id:5})
|
||||||
SendTemplateMessageJob.perform_later('PullRequestMerged', current_user.id, @pull_request.id) if Site.has_notice_menu?
|
SendTemplateMessageJob.perform_later('PullRequestMerged', current_user.id, @pull_request.id) if Site.has_notice_menu?
|
||||||
normal_status(1, "合并成功")
|
normal_status(1, "合并成功")
|
||||||
else
|
else
|
||||||
|
@ -268,7 +263,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
|
||||||
|
|
|
@ -7,6 +7,7 @@ class SettingsController < ApplicationController
|
||||||
get_sub_competitions
|
get_sub_competitions
|
||||||
get_personal_menu
|
get_personal_menu
|
||||||
get_third_party
|
get_third_party
|
||||||
|
get_third_party_new
|
||||||
get_top_system_notification
|
get_top_system_notification
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -67,6 +68,24 @@ class SettingsController < ApplicationController
|
||||||
url: EducoderOauth.oauth_url
|
url: EducoderOauth.oauth_url
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_third_party_new
|
||||||
|
@third_party_new = []
|
||||||
|
@third_party_new << {
|
||||||
|
name: 'educoder',
|
||||||
|
url: EducoderOauth.oauth_url,
|
||||||
|
method: 'get'
|
||||||
|
}
|
||||||
|
platform_url = Rails.application.config_for(:configuration)['platform_url']
|
||||||
|
config = Rails.application.config_for(:configuration)
|
||||||
|
(config.dig("oauth").keys - ["educoder", "wechat"]).each do |provider|
|
||||||
|
@third_party_new << {
|
||||||
|
name: provider,
|
||||||
|
url: "#{platform_url}/auth/#{provider}",
|
||||||
|
method: 'get'
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def get_top_system_notification
|
def get_top_system_notification
|
||||||
@top_system_notification = SystemNotification.is_top.first
|
@top_system_notification = SystemNotification.is_top.first
|
||||||
|
|
|
@ -2,24 +2,24 @@ class StatisticController < ApplicationController
|
||||||
|
|
||||||
# 平台概况
|
# 平台概况
|
||||||
def platform_profile
|
def platform_profile
|
||||||
@platform_user_query = Statistic::PlatformUserQuery.new(params).call
|
@platform_user_query = Statistic::PlatformUserQuery.new(params).call rescue [0, 0, 0]
|
||||||
@platform_project_query = Statistic::PlatformProjectQuery.new(params).call
|
@platform_project_query = Statistic::PlatformProjectQuery.new(params).call rescue [0, 0, 0]
|
||||||
@platform_course_query = Statistic::PlatformCourseQuery.new(params).call
|
@platform_course_query = Statistic::PlatformCourseQuery.new(params).call rescue [0, 0, 0]
|
||||||
end
|
end
|
||||||
|
|
||||||
# 平台代码提交数据
|
# 平台代码提交数据
|
||||||
def platform_code
|
def platform_code
|
||||||
@platform_pull_request_query = Statistic::PlatformPullRequestQuery.new(params).call
|
@platform_pull_request_query = Statistic::PlatformPullRequestQuery.new(params).call rescue [0, 0]
|
||||||
@platform_commit_query = Statistic::PlatformCommitQuery.new(params,current_user).call
|
@platform_commit_query = Statistic::PlatformCommitQuery.new(params,current_user).call rescue [0, 0]
|
||||||
end
|
end
|
||||||
|
|
||||||
# 项目案例活跃度排行榜
|
# 项目案例活跃度排行榜
|
||||||
def active_project_rank
|
def active_project_rank
|
||||||
@active_project_rank_query = Statistic::ActiveProjectRankQuery.new(params, current_user).call
|
@active_project_rank_query = Statistic::ActiveProjectRankQuery.new(params, current_user).call rescue []
|
||||||
end
|
end
|
||||||
|
|
||||||
# 开发者活跃度排行榜
|
# 开发者活跃度排行榜
|
||||||
def active_developer_rank
|
def active_developer_rank
|
||||||
@active_developer_rank_query = Statistic::ActiveDeveloperRankQuery.new(params, current_user).call
|
@active_developer_rank_query = Statistic::ActiveDeveloperRankQuery.new(params, current_user).call rescue []
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,13 @@ class UsersController < ApplicationController
|
||||||
Cache::V2::OwnerCommonService.new(@user.id).read
|
Cache::V2::OwnerCommonService.new(@user.id).read
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def action
|
||||||
|
if params[:action_id].present? && params[:action_type].present?
|
||||||
|
UserAction.create(:action_id => params[:action_id], :action_type => "#{params[:action_type]}", :user_id => User.current.id, :ip => request.remote_ip)
|
||||||
|
end
|
||||||
|
render_ok
|
||||||
|
end
|
||||||
|
|
||||||
def watch_users
|
def watch_users
|
||||||
watchers = Watcher.watching_users(@user.id).includes(:user).order("watchers.created_at desc")
|
watchers = Watcher.watching_users(@user.id).includes(:user).order("watchers.created_at desc")
|
||||||
if params[:search].present?
|
if params[:search].present?
|
||||||
|
@ -109,6 +116,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 +369,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
|
|
@ -6,7 +6,7 @@ module Admins::ProjectsHelper
|
||||||
if owner.is_a?(User)
|
if owner.is_a?(User)
|
||||||
link_to(project.owner&.real_name, "/#{project&.owner&.login}", target: '_blank')
|
link_to(project.owner&.real_name, "/#{project&.owner&.login}", target: '_blank')
|
||||||
elsif owner.is_a?(Organization)
|
elsif owner.is_a?(Organization)
|
||||||
link_to(project.owner&.real_name, "/organize/#{project&.owner&.login}", target: '_blank')
|
link_to(project.owner&.real_name, "/#{project&.owner&.login}", target: '_blank')
|
||||||
else
|
else
|
||||||
""
|
""
|
||||||
end
|
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
|
||||||
|
|
|
@ -10,7 +10,7 @@ module RepositoriesHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
def download_type(str)
|
def download_type(str)
|
||||||
default_type = %w(xlsx xls ppt pptx pdf zip 7z rar exe pdb obj idb RData rdata doc docx mpp vsdx dot otf eot ttf woff woff2 mp4 mov wmv flv mpeg avi avchd webm mkv apk)
|
default_type = %w(ppt pptx pdf zip 7z rar exe pdb obj idb RData rdata doc docx mpp vsdx dot otf eot ttf woff woff2 mp4 mov wmv flv mpeg avi avchd webm mkv apk xlsx xls)
|
||||||
default_type.include?(str&.downcase) || str.blank?
|
default_type.include?(str&.downcase) || str.blank?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ module RepositoriesHelper
|
||||||
new_r_content = [base_url, "/api/#{owner&.login}/#{repo.identifier}/raw?filepath=#{path_current}/#{path_last}&ref=#{ref}"].join
|
new_r_content = [base_url, "/api/#{owner&.login}/#{repo.identifier}/raw?filepath=#{path_current}/#{path_last}&ref=#{ref}"].join
|
||||||
end
|
end
|
||||||
content = content.gsub(/src=\"#{r_content}\"/, "src=\"#{new_r_content}\"").gsub(/src='#{r_content}'/, "src=\"#{new_r_content}\"")
|
content = content.gsub(/src=\"#{r_content}\"/, "src=\"#{new_r_content}\"").gsub(/src='#{r_content}'/, "src=\"#{new_r_content}\"")
|
||||||
rescue
|
rescue
|
||||||
next
|
next
|
||||||
end
|
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,
|
||||||
|
|
|
@ -62,7 +62,7 @@ module Gitea
|
||||||
file_params = {}
|
file_params = {}
|
||||||
file_params = file_params.merge(branch: @params[:branch]) unless @params[:branch].blank?
|
file_params = file_params.merge(branch: @params[:branch]) unless @params[:branch].blank?
|
||||||
file_params = file_params.merge(new_branch: @params[:new_branch]) unless @params[:new_branch].blank?
|
file_params = file_params.merge(new_branch: @params[:new_branch]) unless @params[:new_branch].blank?
|
||||||
file_params = file_params.merge(content: Base64.encode64(@params[:content] || ""))
|
file_params = file_params.merge(content: @params[:content] || "")
|
||||||
file_params = file_params.merge(message: @params[:message]) unless @params[:message].blank?
|
file_params = file_params.merge(message: @params[:message]) unless @params[:message].blank?
|
||||||
file_params = file_params.merge(committer: @params[:committer])
|
file_params = file_params.merge(committer: @params[:committer])
|
||||||
file_params
|
file_params
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
class MigrateRemoteRepositoryJob < ApplicationJob
|
class MigrateRemoteRepositoryJob < ApplicationJob
|
||||||
queue_as :default
|
queue_as :default
|
||||||
|
|
||||||
def perform(repo_id, token, params)
|
def perform(repo_id, token, user_id, params)
|
||||||
repo = Repository.find_by(id: repo_id)
|
repo = Repository.find_by(id: repo_id)
|
||||||
return if repo.blank?
|
return if repo.blank?
|
||||||
|
|
||||||
|
@ -12,6 +12,10 @@ class MigrateRemoteRepositoryJob < ApplicationJob
|
||||||
if gitea_repository[0]==201
|
if gitea_repository[0]==201
|
||||||
repo&.project&.update_columns(gpid: gitea_repository[2]["id"])
|
repo&.project&.update_columns(gpid: gitea_repository[2]["id"])
|
||||||
repo&.mirror&.succeeded!
|
repo&.mirror&.succeeded!
|
||||||
|
## open jianmu devops
|
||||||
|
project_id = repo&.project&.id
|
||||||
|
puts "############ mirror project_id,user_id: #{project_id},#{user_id} ############"
|
||||||
|
OpenProjectDevOpsJob.perform_later(project_id, user_id) if project_id.present? && user_id.present?
|
||||||
puts "############ mirror status: #{repo.mirror.status} ############"
|
puts "############ mirror status: #{repo.mirror.status} ############"
|
||||||
else
|
else
|
||||||
repo&.mirror&.failed!
|
repo&.mirror&.failed!
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
class OpenProjectDevOpsJob < ApplicationJob
|
||||||
|
include ProjectsHelper
|
||||||
|
|
||||||
|
queue_as :message
|
||||||
|
|
||||||
|
def perform(project_id, user_id)
|
||||||
|
project = Project.find_by(id: project_id)
|
||||||
|
user = User.find_by(id: user_id)
|
||||||
|
code = jianmu_devops_code(project, user)
|
||||||
|
uri = URI.parse("#{jianmu_devops_url}/activate?code=#{URI.encode_www_form_component(code)}")
|
||||||
|
response = Net::HTTP.get_response(uri)
|
||||||
|
puts "jianmu_devops_url response.code ===== #{response.code}"
|
||||||
|
SendTemplateMessageJob.perform_later('ProjectOpenDevOps', user_id, project_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -217,6 +217,14 @@ class SendTemplateMessageJob < ApplicationJob
|
||||||
receivers = project&.all_managers.where.not(id: operator&.id)
|
receivers = project&.all_managers.where.not(id: operator&.id)
|
||||||
receivers_string, content, notification_url = MessageTemplate::ProjectPraised.get_message_content(receivers, operator, project)
|
receivers_string, content, notification_url = MessageTemplate::ProjectPraised.get_message_content(receivers, operator, project)
|
||||||
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, project_id: project.id})
|
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, project_id: project.id})
|
||||||
|
when 'ProjectOpenDevOps'
|
||||||
|
operator_id, project_id = args[0], args[1]
|
||||||
|
operator = User.find_by_id(operator_id)
|
||||||
|
project = Project.find_by_id(project_id)
|
||||||
|
return unless operator.present? && project.present?
|
||||||
|
receivers = User.where(id: operator.id)
|
||||||
|
receivers_string, content, notification_url = MessageTemplate::ProjectOpenDevOps.get_message_content(receivers, operator, project)
|
||||||
|
Notice::Write::CreateService.call(receivers_string, content, notification_url, source, {operator_id: operator.id, project_id: project.id})
|
||||||
when 'ProjectPullRequest'
|
when 'ProjectPullRequest'
|
||||||
operator_id, pull_request_id = args[0], args[1]
|
operator_id, pull_request_id = args[0], args[1]
|
||||||
operator = User.find_by_id(operator_id)
|
operator = User.find_by_id(operator_id)
|
||||||
|
|
|
@ -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/
|
||||||
|
|
|
@ -15,7 +15,7 @@ module EducoderOauth::Service
|
||||||
|
|
||||||
result
|
result
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
raise Educoder::TipException.new(e.message)
|
raise Gitlink::TipException.new(e.message)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ module EducoderOauth::Service
|
||||||
result = client.auth_code.get_token(code, redirect_uri: EducoderOauth.redirect_uri).to_hash
|
result = client.auth_code.get_token(code, redirect_uri: EducoderOauth.redirect_uri).to_hash
|
||||||
return result
|
return result
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
raise Educoder::TipException.new(e.message)
|
raise Gitlink::TipException.new(e.message)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,33 @@
|
||||||
class UserMailer < ApplicationMailer
|
class UserMailer < ApplicationMailer
|
||||||
# 注意:这个地方一定要和你的邮箱服务域名一致
|
# 注意:这个地方一定要和你的邮箱服务域名一致
|
||||||
default from: 'notification@trustie.org'
|
# default from: 'notification@trustie.org'
|
||||||
|
# default from: 'noreply@gitlink.org.cn'
|
||||||
# 用户注册验证码
|
default from: 'GitLink <noreply@gitlink.org.cn>'
|
||||||
def register_email(mail, code)
|
|
||||||
@code = code
|
# 用户注册验证码
|
||||||
mail(to: mail, subject: 'Gitink | 注册验证码')
|
def register_email(mail, code)
|
||||||
end
|
@code = code
|
||||||
|
mail(to: mail, subject: 'Gitink | 注册验证码')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# 用户找回密码
|
||||||
|
def find_password(mail, code)
|
||||||
|
@code = code
|
||||||
|
mail(to: mail, subject: 'Gitink | 找回密码验证码')
|
||||||
|
end
|
||||||
|
|
||||||
|
# 用户绑定邮箱
|
||||||
|
def bind_email(mail, code)
|
||||||
|
@code = code
|
||||||
|
mail(to: mail, subject: 'Gitink | 绑定邮箱验证码')
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_email(mail, code)
|
||||||
|
@code = code
|
||||||
|
mail(to: mail, subject: 'Gitink | 更改邮箱验证码')
|
||||||
|
end
|
||||||
|
|
||||||
|
def feedback_email(mail, title, content)
|
||||||
|
mail(to: mail, subject: title, content_type: "text/html", body: content)
|
||||||
|
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)
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: feedbacks
|
||||||
|
#
|
||||||
|
# id :integer not null, primary key
|
||||||
|
# user_id :integer
|
||||||
|
# content :text(65535)
|
||||||
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
|
#
|
||||||
|
# Indexes
|
||||||
|
#
|
||||||
|
# index_feedbacks_on_user_id (user_id)
|
||||||
|
#
|
||||||
|
|
||||||
|
class Feedback < ApplicationRecord
|
||||||
|
|
||||||
|
belongs_to :user
|
||||||
|
has_many :feedback_message_histories, dependent: :destroy
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,36 @@
|
||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: feedback_message_histories
|
||||||
|
#
|
||||||
|
# id :integer not null, primary key
|
||||||
|
# feedback_id :integer
|
||||||
|
# user_id :integer
|
||||||
|
# title :string(255)
|
||||||
|
# content :text(65535)
|
||||||
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
|
#
|
||||||
|
# Indexes
|
||||||
|
#
|
||||||
|
# index_feedback_message_histories_on_feedback_id (feedback_id)
|
||||||
|
# index_feedback_message_histories_on_user_id (user_id)
|
||||||
|
#
|
||||||
|
|
||||||
|
class FeedbackMessageHistory < ApplicationRecord
|
||||||
|
|
||||||
|
belongs_to :feedback
|
||||||
|
belongs_to :user
|
||||||
|
|
||||||
|
before_validation :send_meessage_email, on: :create
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def send_meessage_email
|
||||||
|
unless UserMailer.feedback_email(feedback&.user&.mail, title, content).deliver_now
|
||||||
|
errors[:title] << '邮件发送失败!'
|
||||||
|
end
|
||||||
|
rescue
|
||||||
|
errors[:title] << '邮件发送失败!'
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -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
|
||||||
|
@ -51,6 +52,7 @@ class MessageTemplate < ApplicationRecord
|
||||||
email_html = File.read("#{email_template_html_dir}/project_milestone_completed.html")
|
email_html = File.read("#{email_template_html_dir}/project_milestone_completed.html")
|
||||||
self.create(type: 'MessageTemplate::ProjectMilestoneCompleted', sys_notice: '在 <b>{nickname}/{repository}</b> 仓库,里程碑 <b>{name}</b> 的完成度已达到100%', notification_url: '{baseurl}/{owner}/{identifier}/milestones/{id}', email: email_html, email_title: "#{PLATFORM}: 仓库 {nickname}/{repository} 有里程碑已完成")
|
self.create(type: 'MessageTemplate::ProjectMilestoneCompleted', sys_notice: '在 <b>{nickname}/{repository}</b> 仓库,里程碑 <b>{name}</b> 的完成度已达到100%', notification_url: '{baseurl}/{owner}/{identifier}/milestones/{id}', email: email_html, email_title: "#{PLATFORM}: 仓库 {nickname}/{repository} 有里程碑已完成")
|
||||||
self.create(type: 'MessageTemplate::ProjectPraised', sys_notice: '<b>{nickname1}</b> 点赞了你管理的仓库 <b>{nickname2}/{repository}</b>', notification_url: '{baseurl}/{login}')
|
self.create(type: 'MessageTemplate::ProjectPraised', sys_notice: '<b>{nickname1}</b> 点赞了你管理的仓库 <b>{nickname2}/{repository}</b>', notification_url: '{baseurl}/{login}')
|
||||||
|
self.create(type: 'MessageTemplate::ProjectOpenDevOps', sys_notice: '您的仓库 <b>{repository}</b> 已成功开通引擎服务,可通过简单的节点编排完成自动化集成与部署。欢迎体验!', notification_url: '{baseurl}/{owner}/{identifier}/devops')
|
||||||
email_html = File.read("#{email_template_html_dir}/project_pull_request.html")
|
email_html = File.read("#{email_template_html_dir}/project_pull_request.html")
|
||||||
self.create(type: 'MessageTemplate::ProjectPullRequest', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 提交了一个合并请求:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}', email: email_html, email_title: "#{PLATFORM}: {nickname1} 在 {nickname2}/{repository} 提交了一个合并请求")
|
self.create(type: 'MessageTemplate::ProjectPullRequest', sys_notice: '{nickname1}在 <b>{nickname2}/{repository}</b> 提交了一个合并请求:<b>{title}</b>', notification_url: '{baseurl}/{owner}/{identifier}/pulls/{id}', email: email_html, email_title: "#{PLATFORM}: {nickname1} 在 {nickname2}/{repository} 提交了一个合并请求")
|
||||||
email_html = File.read("#{email_template_html_dir}/project_role.html")
|
email_html = File.read("#{email_template_html_dir}/project_role.html")
|
||||||
|
@ -113,6 +115,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: message_templates
|
||||||
|
#
|
||||||
|
# id :integer not null, primary key
|
||||||
|
# type :string(255)
|
||||||
|
# sys_notice :text(65535)
|
||||||
|
# email :text(65535)
|
||||||
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
|
# notification_url :string(255)
|
||||||
|
# email_title :string(255)
|
||||||
|
#
|
||||||
|
|
||||||
|
# 我管理的仓库项目设置被更改
|
||||||
|
class MessageTemplate::ProjectOpenDevOps < MessageTemplate
|
||||||
|
|
||||||
|
# MessageTemplate::ProjectOpenDevOps.get_message_content(User.where(login: 'yystopf'))
|
||||||
|
def self.get_message_content(receivers, user, project)
|
||||||
|
return '', '', '' if receivers.blank?
|
||||||
|
content = sys_notice.gsub('{repository}', project&.name)
|
||||||
|
url = notification_url.gsub('{owner}', project&.owner&.login).gsub('{identifier}', project&.identifier)
|
||||||
|
return receivers_string(receivers), content, url
|
||||||
|
rescue => e
|
||||||
|
Rails.logger.info("MessageTemplate::ProjectOpenDevOps.get_message_content [ERROR] #{e}")
|
||||||
|
return '', '', ''
|
||||||
|
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
|
|
@ -0,0 +1,27 @@
|
||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: open_users
|
||||||
|
#
|
||||||
|
# id :integer not null, primary key
|
||||||
|
# user_id :integer
|
||||||
|
# type :string(255)
|
||||||
|
# uid :string(255)
|
||||||
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
|
# extra :text(65535)
|
||||||
|
#
|
||||||
|
# Indexes
|
||||||
|
#
|
||||||
|
# index_open_users_on_type_and_uid (type,uid) UNIQUE
|
||||||
|
# index_open_users_on_user_id (user_id)
|
||||||
|
#
|
||||||
|
|
||||||
|
class OpenUsers::Gitee < OpenUser
|
||||||
|
def nickname
|
||||||
|
extra&.[]('nickname')
|
||||||
|
end
|
||||||
|
|
||||||
|
def en_type
|
||||||
|
'gitee'
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,27 @@
|
||||||
|
# == Schema Information
|
||||||
|
#
|
||||||
|
# Table name: open_users
|
||||||
|
#
|
||||||
|
# id :integer not null, primary key
|
||||||
|
# user_id :integer
|
||||||
|
# type :string(255)
|
||||||
|
# uid :string(255)
|
||||||
|
# created_at :datetime not null
|
||||||
|
# updated_at :datetime not null
|
||||||
|
# extra :text(65535)
|
||||||
|
#
|
||||||
|
# Indexes
|
||||||
|
#
|
||||||
|
# index_open_users_on_type_and_uid (type,uid) UNIQUE
|
||||||
|
# index_open_users_on_user_id (user_id)
|
||||||
|
#
|
||||||
|
|
||||||
|
class OpenUsers::Github < OpenUser
|
||||||
|
def nickname
|
||||||
|
extra&.[]('name')
|
||||||
|
end
|
||||||
|
|
||||||
|
def en_type
|
||||||
|
'github'
|
||||||
|
end
|
||||||
|
end
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue