diff --git a/.gitignore b/.gitignore
index a4a6e37..85a5640 100644
--- a/.gitignore
+++ b/.gitignore
@@ -143,6 +143,7 @@ false
*copy.py
*.sh
data/
+tmp/
lib/support/site/tving.py
lib/support/site/wavve.py
diff --git a/lib/framework/init_main.py b/lib/framework/init_main.py
index c1c8dc8..67a9551 100644
--- a/lib/framework/init_main.py
+++ b/lib/framework/init_main.py
@@ -104,8 +104,8 @@ class Framework:
# https://flask-sqlalchemy.palletsprojects.com/en/3.0.x/config/#flask_sqlalchemy.config.SQLALCHEMY_BINDS
# 어떤 편법도 불가. db를 사용하지 않아도 파일이 생김.
db_path = os.path.join(self.config['path_data'], 'db', 'system.db')
- self.app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{db_path}' # 3.0에서 필수
- self.app.config['SQLALCHEMY_BINDS'] = {'system':f'sqlite:///{db_path}'}
+ self.app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{db_path}?check_same_thread=False' # 3.0에서 필수
+ self.app.config['SQLALCHEMY_BINDS'] = {'system':f'sqlite:///{db_path}?check_same_thread=False'}
self.app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
_ = os.path.join(self.config['path_data'], 'plugins')
@@ -124,7 +124,7 @@ class Framework:
for package_name in plugins:
db_path = os.path.join(self.config['path_data'], 'db', f'{package_name}.db')
- self.app.config['SQLALCHEMY_BINDS'][package_name] = f'sqlite:///{db_path}'
+ self.app.config['SQLALCHEMY_BINDS'][package_name] = f'sqlite:///{db_path}?check_same_thread=False'
self.db = SQLAlchemy(self.app, session_options={"autoflush": False, "expire_on_commit": False})
#with self.app.app_context():
# self.db.session.expunge_all()
diff --git a/lib/framework/static/js/ff_global1.js b/lib/framework/static/js/ff_global1.js
index ae3cca9..aee97ec 100644
--- a/lib/framework/static/js/ff_global1.js
+++ b/lib/framework/static/js/ff_global1.js
@@ -130,6 +130,175 @@ $("body").on('click', '#globalCliboardBtn', function(e) {
});
+// 사용 on / off
+$("body").on('change', '#globalSchedulerSwitchBtn', function(e) {
+ e.preventDefault();
+ var ret = $(this).prop('checked');
+ $.ajax({
+ url: '/'+PACKAGE_NAME+'/ajax/' + MODULE_NAME + '/scheduler',
+ type: "POST",
+ cache: false,
+ data: {scheduler : ret},
+ dataType: "json",
+ success: function () {}
+ });
+});
+
+$("body").on('change', '#globalSchedulerSwitchPageBtn', function(e) {
+ var ret = $(this).prop('checked');
+ $.ajax({
+ url: '/'+PACKAGE_NAME+'/ajax/' + MODULE_NAME + '/' + PAGE_NAME + '/scheduler',
+ type: "POST",
+ cache: false,
+ data: {scheduler : ret},
+ dataType: "json",
+ success: function () {}
+ });
+});
+
+$("body").on('click', '#globalOneExecuteBtn', function(e) {
+ e.preventDefault();
+ $.ajax({
+ url: '/'+PACKAGE_NAME+'/ajax/' + MODULE_NAME + '/one_execute',
+ type: "POST",
+ cache: false,
+ data: {},
+ dataType: "json",
+ success: function (ret) {
+ if (ret=='scheduler' || ret=='thread') {
+ $.notify('작업을 시작하였습니다. ('+ret+')', {
+ type: 'success'
+ });
+ } else if (ret == 'is_running') {
+ $.notify('작업중입니다.', {
+ type: 'warning'
+ });
+ } else {
+ $.notify('작업 시작에 실패하였습니다.', {
+ type: 'warning'
+ });
+ }
+ }
+ });
+});
+
+$("body").on('click', '#globalOneExecutePageBtn', function(e) {
+ e.preventDefault();
+ $.ajax({
+ url: '/'+PACKAGE_NAME+'/ajax/' + MODULE_NAME + '/' + PAGE_NAME + '/one_execute',
+ type: "POST",
+ cache: false,
+ data: {sub:sub},
+ dataType: "json",
+ success: function (ret) {
+ if (ret=='scheduler' || ret=='thread') {
+ $.notify('작업을 시작하였습니다. ('+ret+')', {
+ type: 'success'
+ });
+ } else if (ret == 'is_running') {
+ $.notify('작업중입니다.', {
+ type: 'warning'
+ });
+ } else {
+ $.notify('작업 시작에 실패하였습니다.', {
+ type: 'warning'
+ });
+ }
+ }
+ });
+});
+
+$("body").on('click', '#globalImmediatelyExecuteBtn', function(e){
+ e.preventDefault();
+ $.ajax({
+ url: '/'+PACKAGE_NAME+'/ajax/' + MODULE_NAME + '/immediately_execute',
+ type: "POST",
+ cache: false,
+ data: {},
+ dataType: "json",
+ success: function (ret) {
+ if (ret.msg != null) notify(ret.msg, ret.ret);
+ }
+ });
+});
+
+$("body").on('click', '#globalImmediatelyExecutePageBtn', function(e){
+ e.preventDefault();
+ $.ajax({
+ url: '/'+PACKAGE_NAME+'/ajax/' + MODULE_NAME + '/' + PAGE_NAME + '/immediately_execute',
+ type: "POST",
+ cache: false,
+ data: {},
+ dataType: "json",
+ success: function (ret) {
+ if (ret.msg != null) notify(ret.msg, ret.ret);
+ }
+ });
+});
+
+
+$("body").on('click', '#globalDbDeleteBtn', function(e){
+ e.preventDefault();
+ document.getElementById("confirm_title").innerHTML = "DB 삭제";
+ document.getElementById("confirm_body").innerHTML = "전체 목록을 삭제 하시겠습니까?";
+ $('#confirm_button').attr('onclick', "globalDbDelete();");
+ $("#confirm_modal").modal();
+ return;
+});
+
+function globalDbDelete() {
+ $.ajax({
+ url: '/'+PACKAGE_NAME+'/ajax/' + MODULE_NAME + '/reset_db',
+ type: "POST",
+ cache: false,
+ data: {},
+ dataType: "json",
+ success: function (data) {
+ if (data) {
+ $.notify('삭제하였습니다.', {
+ type: 'success'
+ });
+ } else {
+ $.notify('삭제에 실패하였습니다.',{
+ type: 'warning'
+ });
+ }
+ }
+ });
+}
+
+$("body").on('click', '#globalDbDeletePageBtn', function(e){
+ e.preventDefault();
+ document.getElementById("confirm_title").innerHTML = "DB 삭제";
+ document.getElementById("confirm_body").innerHTML = "전체 목록을 삭제 하시겠습니까?";
+ $('#confirm_button').attr('onclick', "globalDbDeletePage();");
+ $("#confirm_modal").modal();
+ return;
+});
+
+function globalDbDeletePage() {
+ $.ajax({
+ url: '/'+PACKAGE_NAME+'/ajax/' + MODULE_NAME + '/' + PAGE_NAME + '/reset_db',
+ type: "POST",
+ cache: false,
+ data: {sub:sub},
+ dataType: "json",
+ success: function (data) {
+ if (data) {
+ $.notify('삭제하였습니다.', {
+ type: 'success'
+ });
+ } else {
+ $.notify('삭제에 실패하였습니다.',{
+ type: 'warning'
+ });
+ }
+ }
+ });
+}
+
+
+
///////////////////////////////////////
// Global - 함수
///////////////////////////////////////
@@ -180,6 +349,88 @@ function shutdown_confirm() {
}
+
+
+///////////////////////////////////////
+// 리스트 화면 기본
+///////////////////////////////////////
+
+
+function globalRequestSearch(page, move_top=true) {
+ var formData = getFormdata('#form_search')
+ formData += '&page=' + page;
+ $.ajax({
+ url: '/' + PACKAGE_NAME + '/ajax/' + MODULE_NAME + '/web_list',
+ type: "POST",
+ cache: false,
+ data: formData,
+ dataType: "json",
+ success: function (data) {
+ current_data = data;
+ if (move_top)
+ window.scrollTo(0,0);
+ make_list(data.list)
+ make_page_html(data.paging)
+ }
+ });
+}
+
+
+
+function make_page_html(data) {
+ str = ' \
+
\
+ \
+ '
+ document.getElementById("page1").innerHTML = str;
+ document.getElementById("page2").innerHTML = str;
+}
+
+
+
+$("body").on('click', '#gloablSearchPageBtn', function(e){
+ e.preventDefault();
+ globalRequestSearch($(this).data('page'), false);
+});
+
+$("body").on('click', '#globalSearchSearchBtn', function(e){
+ e.preventDefault();
+ globalRequestSearch(1, false);
+});
+
+$("body").on('click', '#globalSearchResetBtn', function(e){
+ e.preventDefault();
+ $("#order").val('desc');
+ $("#option1").val('all');
+ $("#option2").val('all');
+ $("#keyword").val('');
+ globalRequestSearch(1, false);
+});
+
+
+
///////////////////////////////////////
// 파일 선택 모달
///////////////////////////////////////
diff --git a/lib/framework/static/js/ff_ui1.js b/lib/framework/static/js/ff_ui1.js
index eb2006d..3ef2cb4 100644
--- a/lib/framework/static/js/ff_ui1.js
+++ b/lib/framework/static/js/ff_ui1.js
@@ -84,6 +84,14 @@ function j_row_info(left, right, l=2, r=8) {
return str;
}
+function j_progress(id, width, label) {
+ var str = '';
+ str += ''
+ str += '
';
+ str += '
'+label+'
';
+ str += '
'
+ return str;
+}
@@ -110,6 +118,19 @@ function j_row_info(left, right, l=2, r=8) {
+
+
+
+
+
+
+
+
+function make_log(key, value, left=2, right=10) {
+ row = m_col(left, key, aligh='right');
+ row += m_col(right, value, aligh='left');
+ return row;
+}
@@ -118,16 +139,106 @@ function text_color(text, color='red') {
return '' + text + '';
}
-function m_table(id, heads) {
- str += ' \
- | NO | \
- 물어본 숫자 | \
- 스트라이크 | \
- 볼 | \
- 가능한 숫자 수 | \
- Action | \
-
';
-}
+
+
+
+///////////////////////////////////////
+// UI - 확장설정 - dropdown
+///////////////////////////////////////
+
+document.addEventListener("DOMContentLoaded", function(){
+ /////// Prevent closing from click inside dropdown
+ document.querySelectorAll('.dropdown-menu').forEach(function(element){
+ element.addEventListener('click', function (e) {
+ e.stopPropagation();
+ });
+ })
+
+ // make it as accordion for smaller screens
+ if (window.innerWidth < 992) {
+ // close all inner dropdowns when parent is closed
+ document.querySelectorAll('.navbar .dropdown').forEach(function(everydropdown){
+ everydropdown.addEventListener('hidden.bs.dropdown', function () {
+ // after dropdown is hidden, then find all submenus
+ this.querySelectorAll('.submenu').forEach(function(everysubmenu){
+ // hide every submenu as well
+ everysubmenu.style.display = 'none';
+ });
+ })
+ });
+
+ document.querySelectorAll('.dropdown-menu a').forEach(function(element){
+ element.addEventListener('click', function (e) {
+
+ let nextEl = this.nextElementSibling;
+ if(nextEl && nextEl.classList.contains('submenu')) {
+ // prevent opening link if link needs to open dropdown
+ e.preventDefault();
+ console.log(nextEl);
+ if(nextEl.style.display == 'block'){
+ nextEl.style.display = 'none';
+ } else {
+ nextEl.style.display = 'block';
+ }
+
+ }
+ });
+ })
+ }
+// end if innerWidth
+});
+// DOMContentLoaded end
+///////////////////////////////////////
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -218,14 +329,7 @@ function m_tab_content(name, content, active) {
return str;
}
-function m_progress(id, width, label) {
- var str = '';
- str += ''
- str += '
';
- str += '
'+label+'
';
- str += '
'
- return str;
-}
+
function m_progress2(id, width, label) {
@@ -239,94 +343,12 @@ function m_progress2(id, width, label) {
-function make_page_html(data) {
- str = ' \
- \
- \
- '
- document.getElementById("page1").innerHTML = str;
- document.getElementById("page2").innerHTML = str;
-}
-function make_log(key, value, left=2, right=10) {
- row = m_col(left, key, aligh='right');
- row += m_col(right, value, aligh='left');
- return row;
-}
+
-
-///////////////////////////////////////
-// UI - 확장설정 - dropdown
-///////////////////////////////////////
-
-document.addEventListener("DOMContentLoaded", function(){
- /////// Prevent closing from click inside dropdown
- document.querySelectorAll('.dropdown-menu').forEach(function(element){
- element.addEventListener('click', function (e) {
- e.stopPropagation();
- });
- })
-
- // make it as accordion for smaller screens
- if (window.innerWidth < 992) {
- // close all inner dropdowns when parent is closed
- document.querySelectorAll('.navbar .dropdown').forEach(function(everydropdown){
- everydropdown.addEventListener('hidden.bs.dropdown', function () {
- // after dropdown is hidden, then find all submenus
- this.querySelectorAll('.submenu').forEach(function(everysubmenu){
- // hide every submenu as well
- everysubmenu.style.display = 'none';
- });
- })
- });
-
- document.querySelectorAll('.dropdown-menu a').forEach(function(element){
- element.addEventListener('click', function (e) {
-
- let nextEl = this.nextElementSibling;
- if(nextEl && nextEl.classList.contains('submenu')) {
- // prevent opening link if link needs to open dropdown
- e.preventDefault();
- console.log(nextEl);
- if(nextEl.style.display == 'block'){
- nextEl.style.display = 'none';
- } else {
- nextEl.style.display = 'block';
- }
-
- }
- });
- })
- }
-// end if innerWidth
-});
-// DOMContentLoaded end
-///////////////////////////////////////
\ No newline at end of file
diff --git a/lib/framework/static/js/sjva_global1.js b/lib/framework/static/js/sjva_global1.js
index 3e042db..a42bcc8 100644
--- a/lib/framework/static/js/sjva_global1.js
+++ b/lib/framework/static/js/sjva_global1.js
@@ -193,202 +193,14 @@ function streaming_kill(command, data={}) {
// Global.. JS 파일로 뺄것
///////////////////////////////////////////////////////////////////////////////
-// 사용 on / off
-$('#global_scheduler').change(function() {
- var ret = $(this).prop('checked');
- $.ajax({
- url: '/'+package_name+'/ajax/scheduler',
- type: "POST",
- cache: false,
- data: {scheduler : ret},
- dataType: "json",
- success: function (list) {
- }
- });
-});
-
-$('#global_scheduler_sub').change(function() {
- var ret = $(this).prop('checked');
- $.ajax({
- url: '/'+package_name+'/ajax/scheduler',
- type: "POST",
- cache: false,
- data: {scheduler : ret, sub:sub},
- dataType: "json",
- success: function (list) {
- }
- });
-});
-function global_setting_save_function() {
- var formData = getFormdata('#setting');
- $.ajax({
- url: '/'+package_name+'/ajax/setting_save',
- type: "POST",
- cache: false,
- data: formData,
- dataType: "json",
- success: function (ret) {
- if (ret) {
- $.notify('설정을 저장하였습니다.', {
- type: 'success'
- });
- } else {
- $.notify('설정 저장에 실패하였습니다.', {
- type: 'warning'
- });
- }
- }
- });
-}
-$("#global_one_execute_btn").click(function(e) {
-//$("body").on('click', '#one_execute_btn', function(e){
- e.preventDefault();
- $.ajax({
- url: '/' + package_name + '/ajax/one_execute',
- type: "POST",
- cache: false,
- data: {},
- dataType: "json",
- success: function (ret) {
- if (ret=='scheduler' || ret=='thread') {
- $.notify('작업을 시작하였습니다. ('+ret+')', {
- type: 'success'
- });
- } else if (ret == 'is_running') {
- $.notify('작업중입니다.', {
- type: 'warning'
- });
- } else {
- $.notify('작업 시작에 실패하였습니다.', {
- type: 'warning'
- });
- }
- }
- });
-});
-
-$("#global_one_execute_sub_btn").click(function(e) {
-//$("body").on('click', '#one_execute_btn', function(e){
- e.preventDefault();
- $.ajax({
- url: '/' + package_name + '/ajax/one_execute',
- type: "POST",
- cache: false,
- data: {sub:sub},
- dataType: "json",
- success: function (ret) {
- if (ret=='scheduler' || ret=='thread') {
- $.notify('작업을 시작하였습니다. ('+ret+')', {
- type: 'success'
- });
- } else if (ret == 'is_running') {
- $.notify('작업중입니다.', {
- type: 'warning'
- });
- } else {
- $.notify('작업 시작에 실패하였습니다.', {
- type: 'warning'
- });
- }
- }
- });
-});
-$("body").on('click', '#global_immediately_execute_sub_btn', function(e){
- e.preventDefault();
- $.ajax({
- url: '/' + package_name + '/ajax/immediately_execute',
- type: "POST",
- cache: false,
- data: {sub:sub},
- dataType: "json",
- success: function (ret) {
- if (ret.msg != null) notify(ret.msg, ret.ret);
- }
- });
-});
-$("body").on('click', '#global_reset_db_btn', function(e){
- e.preventDefault();
- document.getElementById("confirm_title").innerHTML = "DB 삭제";
- document.getElementById("confirm_body").innerHTML = "전체 목록을 삭제 하시겠습니까?";
- $('#confirm_button').attr('onclick', "global_db_delete();");
- $("#confirm_modal").modal();
- return;
-});
-
-function global_db_delete() {
- $.ajax({
- url: '/' + package_name + '/ajax/reset_db',
- type: "POST",
- cache: false,
- data: {},
- dataType: "json",
- success: function (data) {
- if (data) {
- $.notify('삭제하였습니다.', {
- type: 'success'
- });
- } else {
- $.notify('삭제에 실패하였습니다.',{
- type: 'warning'
- });
- }
- }
- });
-}
-$("body").on('click', '#global_reset_db_sub_btn', function(e){
- e.preventDefault();
- document.getElementById("confirm_title").innerHTML = "DB 삭제";
- document.getElementById("confirm_body").innerHTML = "전체 목록을 삭제 하시겠습니까?";
- $('#confirm_button').attr('onclick', "global_db_delete_sub();");
- $("#confirm_modal").modal();
- return;
-});
-
-function global_db_delete_sub() {
- $.ajax({
- url: '/' + package_name + '/ajax/reset_db',
- type: "POST",
- cache: false,
- data: {sub:sub},
- dataType: "json",
- success: function (data) {
- if (data) {
- $.notify('삭제하였습니다.', {
- type: 'success'
- });
- } else {
- $.notify('삭제에 실패하였습니다.',{
- type: 'warning'
- });
- }
- }
- });
-}
-function global_sub_request_search(page, move_top=true) {
- var formData = getFormdata('#form_search')
- formData += '&page=' + page;
- $.ajax({
- url: '/' + package_name + '/ajax/' + sub + '/web_list',
- type: "POST",
- cache: false,
- data: formData,
- dataType: "json",
- success: function (data) {
- current_data = data;
- if (move_top)
- window.scrollTo(0,0);
- make_list(data.list)
- make_page_html(data.paging)
- }
- });
-}
+
$("body").on('click', '#global_json_btn', function(e){
@@ -438,79 +250,11 @@ $("body").on('click', '#global_remove_btn', function(e) {
-//#######################################################
-//플러그인 - 모듈 - 서브 구조하에서 서브 관련 함수
-function global_send_command_sub(command, arg1, arg2, arg3, modal_title, callback) {
- $.ajax({
- url: '/' + package_name + '/ajax/' + sub + '/' + sub2 + '/command',
- type: "POST",
- cache: false,
- data:{command:command, arg1:arg1, arg2:arg2, arg3},
- dataType: "json",
- success: function (ret) {
- console.log(ret);
- if (ret.msg != null) notify(ret.msg, ret.ret);
- if (ret.modal != null) m_modal(ret.modal, modal_title, false);
- if (ret.json != null) m_modal(ret.json, modal_title, true);
- if (callback != null) callback(ret);
- }
- });
-}
-$("body").on('click', '#global_one_execute_sublogic_btn', function(e){
- e.preventDefault();
- $.ajax({
- url: '/' + package_name + '/ajax/' + sub + '/' + sub2 + '/one_execute',
- type: "POST",
- cache: false,
- data: {},
- dataType: "json",
- success: function (ret) {
- if (ret=='scheduler' || ret=='thread') {
- $.notify('작업을 시작하였습니다. ('+ret+')', {
- type: 'success'
- });
- } else if (ret == 'is_running') {
- $.notify('작업중입니다.', {
- type: 'warning'
- });
- } else {
- $.notify('작업 시작에 실패하였습니다.', {
- type: 'warning'
- });
- }
- }
- });
-});
-$("body").on('click', '#global_immediately_execute_sublogic_btn', function(e){
- e.preventDefault();
- $.ajax({
- url: '/' + package_name + '/ajax/' + sub + '/' + sub2 + '/immediately_execute',
- type: "POST",
- cache: false,
- data: {},
- dataType: "json",
- success: function (ret) {
- if (ret.msg != null) notify(ret.msg, ret.ret);
- }
- });
-});
-$('#global_scheduler_sublogic').change(function() {
- var ret = $(this).prop('checked');
- $.ajax({
- url: '/'+package_name+'/ajax/' + sub + '/' + sub2 + '/scheduler',
- type: "POST",
- cache: false,
- data: {scheduler : ret},
- dataType: "json",
- success: function (list) {
- }
- });
-});
@@ -615,50 +359,3 @@ $('#global_scheduler_sublogic').change(function() {
-
-
-
-
-
-
-
-
-
-
-
-
-
-// 이동한 함수
-
-
-
-
-function global_send_command(command, data={}) {
- data['command'] = command;
- $.ajax({
- url: '/' + package_name + '/ajax/' + sub + '/command',
- type: "POST",
- cache: false,
- data:data,
- dataType: "json",
- success: function (data) {
- notify(data['msg'], data['ret']);
- }
- });
-}
-
-function global_send_command2(command, arg1, arg2, arg3, modal_title, callback) {
- $.ajax({
- url: '/' + package_name + '/ajax/' + sub + '/command',
- type: "POST",
- cache: false,
- data:{command:command, arg1:arg1, arg2:arg2, arg3},
- dataType: "json",
- success: function (ret) {
- if (ret.msg != null) notify(ret.msg, ret.ret);
- if (ret.modal != null) m_modal(ret.modal, modal_title, false);
- if (ret.json != null) m_modal(ret.json, modal_title, true);
- if (callback != null) callback(ret);
- }
- });
-}
diff --git a/lib/framework/static/js/sjva_ui14.js b/lib/framework/static/js/sjva_ui14.js
index 1298f7a..5312110 100644
--- a/lib/framework/static/js/sjva_ui14.js
+++ b/lib/framework/static/js/sjva_ui14.js
@@ -97,57 +97,7 @@ function m_tab_content(name, content, active) {
return str;
}
-function m_progress(id, width, label) {
- var str = '';
- str += ''
- str += '
';
- str += '
'+label+'
';
- str += '
'
- return str;
-}
-
-
-function m_progress2(id, width, label) {
- var str = '';
- str += ''
- str += '
';
- str += '
'+label+'
';
- str += '
'
- return str;
-}
-
-
-function make_page_html(data) {
- str = ' \
- \
- \
- '
- document.getElementById("page1").innerHTML = str;
- document.getElementById("page2").innerHTML = str;
-}
diff --git a/lib/framework/templates/macro.html b/lib/framework/templates/macro.html
index 97388d4..4cc1bd3 100644
--- a/lib/framework/templates/macro.html
+++ b/lib/framework/templates/macro.html
@@ -246,7 +246,25 @@
{% endmacro %}
-
+
+{% macro setting_global_scheduler_button(is_include, is_running, id='scheduler', left='스케쥴링 작동', desc=['On : 스케쥴링 시작','Off : 스케쥴링 중지']) %}
+{{ setting_top(left) }}
+
+ {% if is_include == 'True' %}
+
+ {% else %}
+
+ {% endif %}
+ {% if is_running == 'True' %}
+ 동작중
+ {% else %}
+ {% if is_include == 'True' %}
+ 대기중
+ {% endif %}
+ {% endif %}
+
+{{ setting_bottom(desc) }}
+{% endmacro %}
@@ -728,25 +746,7 @@ macros.setting_button_with_info([['toggle_btn', 'Toggle', [{'key':'category', 'v
{% endmacro %}
-
-{% macro setting_global_scheduler_button(is_include, is_running, id='scheduler', left='스케쥴링 작동', desc=['On : 스케쥴링 시작','Off : 스케쥴링 중지']) %}
-{{ setting_top(left) }}
-
- {% if is_include == 'True' %}
-
- {% else %}
-
- {% endif %}
- {% if is_running == 'True' %}
- 동작중
- {% else %}
- {% if is_include == 'True' %}
- 대기중
- {% endif %}
- {% endif %}
-
-{{ setting_bottom(desc) }}
-{% endmacro %}
+
{% macro setting_global_scheduler_sub_button(is_include, is_running, id='scheduler', left='스케쥴링 작동', desc=['On : 스케쥴링 시작','Off : 스케쥴링 중지']) %}
{{ setting_top(left) }}
diff --git a/lib/framework/version.py b/lib/framework/version.py
index ac80dea..334bc04 100644
--- a/lib/framework/version.py
+++ b/lib/framework/version.py
@@ -1 +1 @@
-VERSION="4.0.30"
\ No newline at end of file
+VERSION="4.0.32"
\ No newline at end of file
diff --git a/lib/plugin/create_plugin.py b/lib/plugin/create_plugin.py
index 0b840e6..2f89297 100644
--- a/lib/plugin/create_plugin.py
+++ b/lib/plugin/create_plugin.py
@@ -44,7 +44,7 @@ class PluginBase(object):
self.ModelSetting = None
if setting.get('use_db', True):
db_path = os.path.join(F.config['path_data'], 'db', f'{self.package_name}.db')
- F.app.config['SQLALCHEMY_BINDS'][self.package_name] = f"sqlite:///{db_path}"
+ F.app.config['SQLALCHEMY_BINDS'][self.package_name] = f"sqlite:///{db_path}?check_same_thread=False"
if setting.get('use_default_setting', True):
self.ModelSetting = get_model_setting(self.package_name, self.logger)
diff --git a/lib/plugin/logic.py b/lib/plugin/logic.py
index a1186da..36d3bc8 100644
--- a/lib/plugin/logic.py
+++ b/lib/plugin/logic.py
@@ -84,47 +84,47 @@ class Logic(object):
self.P.logger.error(traceback.format_exc())
- def scheduler_start(self, sub):
+ def scheduler_start(self, module_name):
try:
- job_id = '%s_%s' % (self.P.package_name, sub)
- module = self.get_module(sub)
- job = Job(self.P.package_name, job_id, module.get_scheduler_interval(), self.scheduler_function, module.get_scheduler_desc(), args=sub)
+ job_id = '%s_%s' % (self.P.package_name, module_name)
+ module = self.get_module(module_name)
+ job = Job(self.P.package_name, job_id, module.get_scheduler_interval(), self.scheduler_function, module.get_scheduler_desc(), args=module_name)
F.scheduler.add_job_instance(job)
except Exception as e:
self.P.logger.error(f'Exception:{str(e)}')
self.P.logger.error(traceback.format_exc())
- def scheduler_stop(self, sub):
+ def scheduler_stop(self, module_name):
try:
- job_id = '%s_%s' % (self.P.package_name, sub)
+ job_id = '%s_%s' % (self.P.package_name, module_name)
F.scheduler.remove_job(job_id)
except Exception as e:
self.P.logger.error(f'Exception:{str(e)}')
self.P.logger.error(traceback.format_exc())
- def scheduler_function(self, sub):
+ def scheduler_function(self, module_name):
try:
- module = self.get_module(sub)
+ module = self.get_module(module_name)
module.scheduler_function()
except Exception as e:
self.P.logger.error(f'Exception:{str(e)}')
self.P.logger.error(traceback.format_exc())
- def reset_db(self,sub):
+ def reset_db(self, module_name):
try:
- module = self.get_module(sub)
+ module = self.get_module(module_name)
return module.reset_db()
except Exception as e:
self.P.logger.error(f'Exception:{str(e)}')
self.P.logger.error(traceback.format_exc())
- def one_execute(self, sub):
- self.P.logger.debug('one_execute :%s', sub)
+ def one_execute(self, module_name):
+ self.P.logger.debug('one_execute :%s', module_name)
try:
- job_id = '%s_%s' % (self.P.package_name, sub)
+ job_id = '%s_%s' % (self.P.package_name, module_name)
if F.scheduler.is_include(job_id):
if F.scheduler.is_running(job_id):
ret = 'is_running'
@@ -134,7 +134,7 @@ class Logic(object):
else:
def func():
time.sleep(2)
- self.scheduler_function(sub)
+ self.scheduler_function(module_name)
threading.Thread(target=func, args=()).start()
ret = 'thread'
except Exception as e:
@@ -143,12 +143,12 @@ class Logic(object):
ret = 'fail'
return ret
- def immediately_execute(self, sub):
- self.P.logger.debug('immediately_execute :%s', sub)
+ def immediately_execute(self, module_name):
+ self.P.logger.debug('immediately_execute :%s', module_name)
try:
def func():
time.sleep(1)
- self.scheduler_function(sub)
+ self.scheduler_function(module_name)
threading.Thread(target=func, args=()).start()
ret = {'ret':'success', 'msg':'실행합니다.'}
except Exception as e:
@@ -175,6 +175,65 @@ class Logic(object):
self.P.logger.error(f'Exception:{str(e)}')
self.P.logger.error(traceback.format_exc())
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
#######################################################
# 플러그인 - 모듈 - 페이지 구조하에서 서브 관련 함수
diff --git a/lib/plugin/logic_module_base.py b/lib/plugin/logic_module_base.py
index b7117d7..ec56521 100644
--- a/lib/plugin/logic_module_base.py
+++ b/lib/plugin/logic_module_base.py
@@ -14,6 +14,16 @@ class PluginModuleBase(object):
self.socketio_list = None
self.page_list = None
+ def get_module(self, module_name):
+ try:
+ for module in self.P.module_list:
+ if module.name == module_name:
+ return module
+ except Exception as e:
+ self.P.logger.error(f'Exception:{str(e)}')
+ self.P.logger.error(traceback.format_exc())
+
+
# set_module_list 대응
def set_page_list(self, page_list):
try:
@@ -87,7 +97,7 @@ class PluginModuleBase(object):
def get_first_menu(self):
return self.first_menu
- def get_scheduler_name(self):
+ def get_scheduler_id(self):
return '%s_%s' % (self.P.package_name, self.name)
def dump(self, data):
diff --git a/lib/plugin/model_base.py b/lib/plugin/model_base.py
index fadc531..ca3c4b3 100644
--- a/lib/plugin/model_base.py
+++ b/lib/plugin/model_base.py
@@ -1,5 +1,5 @@
import traceback
-from datetime import datetime
+from datetime import datetime, timedelta
from framework import F
@@ -8,7 +8,7 @@ class ModelBase(F.db.Model):
__abstract__ = True
__table_args__ = {'mysql_collate': 'utf8_general_ci'}
model_setting = None
- logger = None
+ P = None
def __repr__(self):
return repr(self.as_dict())
@@ -24,8 +24,8 @@ class ModelBase(F.db.Model):
F.db.session.commit()
return self
except Exception as e:
- self.logger.error(f'Exception:{str(e)}')
- self.logger.error(traceback.format_exc())
+ self.P.logger.error(f'Exception:{str(e)}')
+ self.P.logger.error(traceback.format_exc())
@classmethod
def get_paging_info(cls, count, current_page, page_size):
@@ -48,8 +48,8 @@ class ModelBase(F.db.Model):
F.logger.debug('paging : c:%s %s %s %s %s %s', count, paging['total_page'], paging['prev_page'], paging['next_page'] , paging['start_page'], paging['last_page'])
return paging
except Exception as e:
- F.logger.error(f'Exception:{str(e)}')
- F.logger.error(traceback.format_exc())
+ cls.P.logger.error(f'Exception:{str(e)}')
+ cls.P.logger.error(traceback.format_exc())
@classmethod
@@ -58,8 +58,8 @@ class ModelBase(F.db.Model):
with F.app.app_context():
return F.db.session.query(cls).filter_by(id=int(id)).first()
except Exception as e:
- F.logger.error(f'Exception:{str(e)}')
- F.logger.error(traceback.format_exc())
+ cls.P.logger.error(f'Exception:{str(e)}')
+ cls.P.logger.error(traceback.format_exc())
@classmethod
@@ -71,8 +71,8 @@ class ModelBase(F.db.Model):
tmp = [x.as_dict() for x in tmp]
return tmp
except Exception as e:
- F.logger.error(f'Exception:{str(e)}')
- F.logger.error(traceback.format_exc())
+ cls.P.logger.error(f'Exception:{str(e)}')
+ cls.P.logger.error(traceback.format_exc())
@@ -84,20 +84,32 @@ class ModelBase(F.db.Model):
F.db.session.commit()
return True
except Exception as e:
- F.logger.error(f'Exception:{str(e)}')
- F.logger.error(traceback.format_exc())
+ cls.P.logger.error(f'Exception:{str(e)}')
+ cls.P.logger.error(traceback.format_exc())
return False
@classmethod
- def delete_all(cls):
+ def delete_all(cls, days=None):
try:
with F.app.app_context():
- F.db.session.query(cls).delete()
- F.db.session.commit()
+ if days == None:
+ F.db.session.query(cls).delete()
+ F.db.session.commit()
+ else:
+ now = datetime.datetime.now()
+ ago = now - datetime.timedelta(days=days)
+
+ ret = F.db.session.query(cls).filter(cls.created_time > ago).delete()
+ cls.P.debug(ret)
+
+
+
+
+
return True
except Exception as e:
- F.logger.error(f'Exception:{str(e)}')
- F.logger.error(traceback.format_exc())
+ cls.P.logger.error(f'Exception:{str(e)}')
+ cls.P.logger.error(traceback.format_exc())
return False
@@ -111,12 +123,12 @@ class ModelBase(F.db.Model):
if 'page' in req.form:
page = int(req.form['page'])
if 'keyword' in req.form:
- search = req.form['keyword']
+ search = req.form['keyword'].strip()
option1 = req.form.get('option1', 'all')
option2 = req.form.get('option2', 'all')
order = req.form['order'] if 'order' in req.form else 'desc'
- query = cls.make_query(order=order, search=search, option1=option1, option2=option2)
+ query = cls.make_query(req, order=order, search=search, option1=option1, option2=option2)
count = query.count()
query = query.limit(page_size).offset((page-1)*page_size)
F.logger.debug('cls count:%s', count)
@@ -124,21 +136,21 @@ class ModelBase(F.db.Model):
ret['list'] = [item.as_dict() for item in lists]
ret['paging'] = cls.get_paging_info(count, page, page_size)
try:
- if cls.model_setting is not None and cls.__tablename__ is not None:
- cls.model_setting.set(f'{cls.__tablename__}_last_list_option', f'{order}|{page}|{search}|{option1}|{option2}')
+ if cls.P.ModelSetting is not None and cls.__tablename__ is not None:
+ cls.P.ModelSetting.set(f'{cls.__tablename__}_last_list_option', f'{order}|{page}|{search}|{option1}|{option2}')
except Exception as e:
F.logger.error('Exception:%s', e)
F.logger.error(traceback.format_exc())
F.logger.error(f'{cls.__tablename__}_last_list_option ERROR!' )
return ret
except Exception as e:
- F.logger.error('Exception:%s', e)
- F.logger.error(traceback.format_exc())
+ cls.P.logger.error('Exception:%s', e)
+ cls.P.logger.error(traceback.format_exc())
# 오버라이딩
@classmethod
- def make_query(cls, order='desc', search='', option1='all', option2='all'):
+ def make_query(cls, req, order='desc', search='', option1='all', option2='all'):
with F.app.app_context():
query = F.db.session.query(cls)
return query
diff --git a/lib/plugin/model_setting.py b/lib/plugin/model_setting.py
index 853d65f..3a93a88 100644
--- a/lib/plugin/model_setting.py
+++ b/lib/plugin/model_setting.py
@@ -101,7 +101,7 @@ def get_model_setting(package_name, logger, table_name=None):
for key, value in req.form.items():
if key in ['scheduler', 'is_running']:
continue
- if key.startswith('global_') or key.startswith('tmp_') or key.startswith('_'):
+ if key.startswith('global') or key.startswith('tmp_') or key.startswith('_'):
continue
#logger.debug('Key:%s Value:%s', key, value)
if ModelSetting.get(key) != value:
diff --git a/lib/plugin/route.py b/lib/plugin/route.py
index f0d5253..a1aca47 100644
--- a/lib/plugin/route.py
+++ b/lib/plugin/route.py
@@ -92,42 +92,37 @@ def default_route(P):
for module in P.module_list:
module.setting_save_after(change_list)
return jsonify(ret)
- elif sub == 'scheduler':
- sub = request.form['sub']
- go = request.form['scheduler']
- P.logger.debug('scheduler :%s', go)
- if go == 'true':
- P.logic.scheduler_start(sub)
- else:
- P.logic.scheduler_stop(sub)
- return jsonify(go)
- elif sub == 'reset_db':
- sub = request.form['sub']
- ret = P.logic.reset_db(sub)
- return jsonify(ret)
- elif sub == 'one_execute':
- sub = request.form['sub']
- ret = P.logic.one_execute(sub)
- return jsonify(ret)
- elif sub == 'immediately_execute':
- sub = request.form['sub']
- ret = P.logic.immediately_execute(sub)
- return jsonify(ret)
+
except Exception as exception:
P.logger.error('Exception:%s', exception)
P.logger.error(traceback.format_exc())
- @P.blueprint.route('/ajax//', methods=['GET', 'POST'])
+ @P.blueprint.route('/ajax//', methods=['GET', 'POST'])
@login_required
- def second_ajax(mod, cmd):
+ def second_ajax(module_name, cmd):
try:
for module in P.module_list:
- if mod == module.name:
+ if module_name == module.name:
if cmd == 'command':
return module.process_command(request.form['command'], request.form.get('arg1'), request.form.get('arg2'), request.form.get('arg3'), request)
else:
return module.process_ajax(cmd, request)
-
+ elif cmd == 'scheduler':
+ go = request.form['scheduler']
+ if go == 'true':
+ P.logic.scheduler_start(module_name)
+ else:
+ P.logic.scheduler_stop(module_name)
+ return jsonify(go)
+ elif cmd == 'reset_db':
+ ret = P.logic.reset_db(module_name)
+ return jsonify(ret)
+ elif cmd == 'one_execute':
+ ret = P.logic.one_execute(module_name)
+ return jsonify(ret)
+ elif cmd == 'immediately_execute':
+ ret = P.logic.immediately_execute(module_name)
+ return jsonify(ret)
except Exception as exception:
P.logger.error('Exception:%s', exception)
P.logger.error(traceback.format_exc())