linkkf 로직수정중

This commit is contained in:
2025-12-25 19:42:32 +09:00
parent 695d26767e
commit af9a38a973
128 changed files with 8711 additions and 1484 deletions

View File

@@ -0,0 +1,277 @@
- name: "기본"
list:
- title: "파일 매니저"
package_name: "flaskfilemanager"
developer: "stevelittlefish"
home: "https://github.com/flaskfarm/flaskfilemanager"
description: "RichFilemanager를 Flask에서 동작하도록 한 FlaskFileManager 포크"
- title: "터미널"
package_name: "terminal"
developer: "joyful"
home: "https://github.com/flaskfarm/terminal"
description: "리눅스 전용 심플 터미널. xterm.js client"
- title: "편집기"
package_name: "flaskcode"
developer: "sujeetkv"
home: "https://github.com/flaskfarm/flaskcode"
description: "flaskcode를 fork한 문서 편집기"
- name: "보조 & 라이브러리"
list:
- title: "번역"
package_name: "trans"
developer: "FlaskFarm"
home: "https://github.com/flaskfarm/trans"
description: "번역 관련 설정 및 API 제공"
- title: "support_site"
package_name: "support_site"
developer: "flaskfarm"
home: "https://github.com/flaskfarm/support_site"
description: "사이트 크롤링 라이브러리"
- title: "Gdrive 라이브러리 for FlaskFarm"
package_name: "libgdrive"
developer: "orial"
home: "https://github.com/byorial/libgdrive"
description: "구글드라이브 API 라이브러리"
- name: "외부 연결"
list:
- title: "Rclone"
package_name: "rclone"
developer: "flaskfarm"
home: "https://github.com/flaskfarm/rclone"
description: "Rclone을 좀 더 쉽게 사용하기 위한 플러그인"
- title: "PLEX MATE"
package_name: "plex_mate"
developer: "flaskfarm"
home: "https://github.com/flaskfarm/plex_mate"
description: "PLEX와 동일 기기에서 동작하는 툴"
- title: "vnStat"
package_name: "vnStat"
developer: "by275"
home: "https://github.com/by275/vnStat"
description: "vnStat 정보를 보여주는 플러그인"
- title: "115 TOOL"
package_name: "tool_115"
developer: "soju6jan"
home: "https://github.com/soju6jan/tool_115"
description: "115 TOOL"
- name: "도구"
list:
- title: "디스코드 봇"
package_name: "discord_bot"
developer: "flaskfarm"
home: "https://github.com/flaskfarm/discord_bot"
description: "디스코드 봇"
- title: "정적 호스트"
package_name: "static_host"
developer: "by275"
description: "정적 웹을 호스팅 하는 플러그인"
home: "https://github.com/by275/static_host"
- title: 'Flaskfarmaider'
package_name: 'flaskfarmaider'
developer: 'halfaider'
description: 'Flaskfarm 보조 플러그인'
home: 'https://github.com/halfaider/flaskfarmaider'
- title: "메타데이터"
package_name: "metadata"
developer: "flaskfarm"
home: "https://github.com/flaskfarm/metadata"
description: "VIDEO 메타데이터 제공"
- title: "lotto"
package_name: "lotto"
developer: "honeypig5"
home: "https://github.com/hudulgi/lotto"
description: "로또 구매"
- title: "핫딜 알람"
package_name: "hotdeal_alarm"
developer: "dbswnschl"
home: "https://github.com/dbswnschl/hotdeal_alarm"
description: "핫딜 알리미"
- name: "파일처리"
list:
- title: "국내TV 파일처리"
package_name: "fp_ktv"
developer: "flaskfarm"
home: "https://github.com/flaskfarm/fp_ktv"
description: "국내TV 영상 파일 전용 파일처리"
- title: "영화 파일처리"
package_name: "fp_movie"
developer: "flaskfarm"
home: "https://github.com/flaskfarm/fp_movie"
description: "영화 파일처리"
- title: "musicProc2"
package_name: "musicProc2"
developer: "dyllislev"
home: "https://github.com/dyllisLev/musicProc2"
description: "음악정리"
- title: "해외TV 파일처리"
package_name: "fp_ftv"
developer: "kihyyo"
home: "https://github.com/kihyyo/fp_ftv"
description: "해외TV 영상 파일 전용 파일처리"
- title: "자막 툴"
package_name: "subtitle_tool"
developer: "flaskfarm"
home: "https://github.com/flaskfarm/subtitle_tool"
description: "자막 관련 툴"
- name: "토렌트 & RSS"
list:
- title: "토렌트 정보"
package_name: "torrent_info"
developer: "by275"
home: "https://github.com/by275/torrent_info"
description: "토렌트 마그넷/파일 정보를 보여주는 플러그인"
- title: "티프리카"
package_name: "tfreeca"
developer: "by275"
home: "https://github.com/by275/tfreeca"
description: "티프리카 게시판 뷰어"
- name: "OTT"
list:
- title: "티빙 검색"
package_name: "tving_search"
developer: "by275"
home: "https://github.com/by275/tving_search"
description: "티빙 검색 플러그인"
- title: "FFMPEG"
package_name: "ffmpeg"
developer: "FlaskFarm"
home: "https://github.com/flaskfarm/ffmpeg"
description: "m3u8 다운로드 & 비디오파일 분석"
- title: "웨이브"
package_name: "wavve"
developer: "halfaider"
home: "https://github.com/halfaider/wavve"
description: "웨이브 VOD 다운로더"
- title: "티빙"
package_name: "tving"
developer: "kihyyo"
home: "https://github.com/kihyyo/tving"
description: "티빙 VOD 다운로더"
- title: "쿠팡플레이"
package_name: "cppl"
developer: "soju6jan"
home: "https://github.com/soju6jan/cppl"
description: "쿠팡플레이 VOD 다운로더"
- title: "DRM 다운로드"
package_name: "wv_tool"
developer: "soju6jan"
home: "https://github.com/soju6jan/wv_tool"
description: "DRM 영상 다운로드"
- title: "make_yaml"
package_name: "make_yaml"
developer: "kihyyo"
home: "https://github.com/kihyyo/make_yaml"
description: "OTT 정보로 직접 yaml로 만드는 플러그인"
- title: "RE_tool"
package_name: "RE_tool"
developer: "kihyyo"
home: "https://github.com/kihyyo/RE_tool"
description: "M3U8_RE 다운로드"
- name: "라이브"
list:
- title: "ALive"
package_name: "alive"
developer: "by275"
home: "https://github.com/by275/alive"
description: "라이브 방송 플러그인"
- title: "EPG"
package_name: "epg"
developer: "flaskfarm"
home: "https://github.com/flaskfarm/epg"
description: "EPG 생성"
- title: "MY EPG"
package_name: "myepg"
developer: "include"
home: "https://github.com/myepg/myepg"
description: "EPG API 플러그인"
- title: "HDHomerun"
package_name: "hdhomerun"
developer: "flaskfarm"
home: "https://github.com/flaskfarm/hdhomerun"
description: "HDHomerun 도구"
- title: "스포TV"
package_name: "ff_spotv"
developer: "ssagajikorea"
home: "https://github.com/ssagajikorea/ff_spotv"
description: "스포TV 방송 FF플러그인"
- title: "삼성TV플러스"
package_name: "ff_sstvplus"
developer: "ssagajikorea"
home: "https://github.com/ssagajikorea/ff_sstvplus"
description: "삼성TV플러스 방송 FF플러그인"
- title: "네이버스포츠"
package_name: "ff_nsports"
developer: "ssagajikorea"
home: "https://github.com/ssagajikorea/ff_nsports"
description: "네이버스포츠 방송 FF플러그인"
- title: "쿠팡플레이"
package_name: "ff_cpp"
developer: "ssagajikorea"
home: "https://github.com/ssagajikorea/ff_cpp"
description: "쿠팡플레이 방송 FF플러그인"
- title: "아프리카TV"
package_name: "ff_afrtv"
developer: "ssagajikorea"
home: "https://github.com/ssagajikorea/ff_afrtv"
description: "아프리카TV 방송 FF플러그인"
- title: "REYSTREAM"
package_name: "ff_reystream"
developer: "ssagajikorea"
description: "REYSTREAM 방송 FF플러그인"
home: "https://github.com/ssagajikorea/ff_reystream"
- title: "팝콘TV"
package_name: "ff_pktv"
developer: "ssagajikorea"
home: "https://github.com/ssagajikorea/ff_pktv"
description: "팝콘TV 방송 FF플러그인"
- title: "팬더TV"
package_name: "ff_pdtv"
developer: "ssagajikorea"
home: "https://github.com/ssagajikorea/ff_pdtv"
description: "팬더TV 방송 FF플러그인"
- title: "NEXTCAST"
package_name: "ff_nextcast"
developer: "ssagajikorea"
home: "https://github.com/ssagajikorea/ff_nextcast"
description: "NEXTCAST 방송 FF플러그인"
- title: "LIFETV365"
package_name: "ff_lifetv365"
developer: "ssagajikorea"
home: "https://github.com/ssagajikorea/ff_lifetv365"
description: "LIFETV365 방송 FF플러그인"
- title: "KLive+"
package_name: "klive_plus"
developer: "soju6jan"
home: "https://github.com/soju6jan/klive_plus"
description: "KLive+"
- name: "SJVA"
list:
- title: "SJVA"
package_name: "sjva"
developer: "soju6jan"
home: "https://github.com/soju6jan/sjva"
description: "SJVA 인증 & 사이트 연동"
- title: "구드공 툴"
package_name: "gds_tool"
developer: "soju6jan"
home: "https://github.com/soju6jan/gds_tool"
description: "복사요청, 제공, GDS 변경사항"
- title: "봇 다운로더"
package_name: "bot_downloader"
developer: "flaskfarm"
home: "https://github.com/soju6jan/bot_downloader"
description: "봇 다운로더"
# name: "기타"
# list:
# - title: "숫자 야구"
# package_name: "number_baseball"
# developer: "FlaskFarm"
# home: "https://github.com/flaskfarm/number_baseball"
# description: "숫자 야구 - 샘플 플러그인"
# - title: "샘플 플러그인"
# package_name: "sample"
# developer: "FlaskFarm"
# home: "https://github.com/flaskfarm/sample"
# description: "샘플 플러그인"

View File

@@ -0,0 +1,9 @@
### 알림
##### 텔레그램
* @BotFather 에게서 Bot 생성
* https://api.telegram.org/bot봇토큰/getUpdates 접속
* 본인의 봇과 대화
* https://api.telegram.org/bot봇토큰/getUpdates 접속
"from":{"id":879500000, 숫자가 본인의 Chat ID

View File

@@ -31,7 +31,7 @@ class ModuleHome(PluginModuleBase):
for key, value in F.app.config.items():
if key not in ['SECRET_KEY']:
data[key] = str(value)
ret = {'json':{'Framework':F.config, 'Flask':data}}
ret = {'json':{'Framework':F.config, 'Flask':data}, 'title':'config'}
return jsonify(ret)
@@ -56,7 +56,7 @@ class ModuleHome(PluginModuleBase):
ret = {}
ret['system'] = self.get_info()
ret['scheduler'] = scheduler.get_job_list_info()
F.socketio.emit("status", ret, namespace=f'/{P.package_name}/{name}', broadcast=True)
F.socketio.emit("status", ret, namespace=f'/{P.package_name}/{name}')
def get_info(self, mode=''):

View File

@@ -22,14 +22,11 @@ class ModuleLog(PluginModuleBase):
log_list.append(x)
arg['log_list'] = '|'.join(log_list)
arg['all_list'] = '|'.join(log_files)
arg['filename'] = 'framework.log'
print(request.form)
print(request.form)
print(request.form)
print(request.form)
arg['filename'] = 'all.log'
if 'filename' in request.form:
arg['filename'] = request.form['filename']
arg['filename'] = req.args.get('filename', arg['filename'])
return render_template(f'{__package__}_{name}.html', arg=arg)
except Exception as e:
P.logger.error(f'Exception:{str(e)}')

View File

@@ -1,14 +1,16 @@
import shutil
from support import SupportFile
from support import SupportFile, SupportYaml
from .setup import *
name = 'plugin'
class ModulePlugin(PluginModuleBase):
def __init__(self, P):
super(ModulePlugin, self).__init__(P, name=name, first_menu='list')
self.all_plugin_list = None
def process_menu(self, page, req):
@@ -36,14 +38,16 @@ class ModulePlugin(PluginModuleBase):
"""
for name, entity in F.PluginManager.all_package_list.items():
try:
if entity.get('version') == '3':
#data.append(entity)
data.append({'package_name':name})
else:
if 'P' in entity:
data.append(entity['P'].plugin_info)
data[-1]['loading'] = entity.get('loading')
data[-1]['status'] = entity.get('status')
data[-1]['log'] = entity.get('log')
else:
data.append({'package_name':name})
data[-1]['loading'] = entity.get('loading')
data[-1]['status'] = entity.get('status')
data[-1]['log'] = entity.get('log')
except Exception as e:
data.append({'package_name':name})
P.logger.error(f'Exception:{str(e)}')
@@ -64,6 +68,36 @@ class ModulePlugin(PluginModuleBase):
else:
ret['msg'] = info['path'] + "<br>폴더가 없습니다."
ret['ret'] = 'danger'
elif command == 'get_plugin_list_all':
if self.all_plugin_list == None:
filepath = os.path.join(os.path.dirname(__file__), 'files', 'all_plugin.yaml')
self.all_plugin_list = SupportYaml.read_yaml(filepath)
def get_plugin(_name):
for _cate in self.all_plugin_list:
for _plugin in _cate['list']:
if _plugin['package_name'] == _name:
P.logger.info(_name)
if _name == 'ff_reystream':
P.logger.info(_name)
return _plugin
for name, entity in F.PluginManager.all_package_list.items():
try:
_plugin = get_plugin(name)
if _plugin != None:
_plugin['loading'] = entity.get('loading')
_plugin['status'] = entity.get('status')
_plugin['log'] = entity.get('log')
_plugin['version'] = entity['P'].plugin_info['version']
except Exception as e:
data.append({'package_name':name})
P.logger.error(f'Exception:{str(e)}')
P.logger.error(traceback.format_exc())
ret['data'] = self.all_plugin_list
return jsonify(ret)

View File

@@ -53,7 +53,7 @@ class ModuleRoute(PluginModuleBase):
@F.socketio.on('connect', namespace=f'/{P.package_name}/restart')
def restart_socket_connect():
F.socketio.emit('connect', {}, namespace='/{P.package_name}/restart', broadcast=True)
F.socketio.emit('connect', {}, namespace='/{P.package_name}/restart')
def process_menu(self, page, req):

View File

@@ -2,8 +2,8 @@ import random
import string
import time
from support import (SupportDiscord, SupportFile, SupportSubprocess,
SupportTelegram)
from support import (SupportDiscord, SupportFile, SupportSlack,
SupportSubprocess, SupportTelegram, SupportYaml)
from tool import ToolModalCommand
from .setup import *
@@ -12,7 +12,7 @@ name = 'setting'
class ModuleSetting(PluginModuleBase):
db_default = {
'db_version' : '1',
'db_version' : '1.1',
'port' : '9999',
'ddns' : 'http://localhost:9999',
'use_login' : 'False',
@@ -34,6 +34,8 @@ class ModuleSetting(PluginModuleBase):
'notify_telegram_disable_notification' : 'False',
'notify_discord_use' : 'False',
'notify_discord_webhook' : '',
'notify_slack_use' : 'False',
'notify_slack_webhook' : '',
'notify_advaned_use' : 'False',
'notify.yaml': '', #직접 사용하지 않으나 저장 편의상.
'command_text': '',
@@ -91,10 +93,15 @@ class ModuleSetting(PluginModuleBase):
ret['msg'] = 'export.sh 파일이 없습니다.'
elif command == 'menu_save':
SupportFile.write_file(F.config['menu_yaml_filepath'], arg1 )
ret['msg'] = '저장하였습니다.'
from framework.init_menu import MenuManager
MenuManager.init_menu()
F.socketio.emit("refresh", {}, namespace='/framework', broadcast=True)
try:
SupportYaml.read_yaml(F.config['menu_yaml_filepath'])
ret['msg'] = '저장하였습니다.'
from framework.init_menu import MenuManager
MenuManager.init_menu()
F.socketio.emit("refresh", {}, namespace='/framework')
except:
ret['ret'] = "danger"
ret['msg'] = "yaml 형식에 맞지 않습니다"
elif command == 'notify_test':
if arg1 == 'telegram':
token, chatid, sound, text = arg2.split('||')
@@ -104,6 +111,9 @@ class ModuleSetting(PluginModuleBase):
elif arg1 == 'discord':
SupportDiscord.send_discord_message(arg3, webhook_url=arg2)
ret['msg'] = '메시지를 전송했습니다.'
elif arg1 == 'slack':
SupportSlack.send_slack_message(arg3, webhook_url=arg2)
ret['msg'] = '메시지를 전송했습니다.'
elif arg1 == 'advanced':
from tool import ToolNotify
ToolNotify.send_advanced_message(arg3, message_id=arg2)
@@ -122,7 +132,31 @@ class ModuleSetting(PluginModuleBase):
ret['type'] = 'warning'
elif command == 'command_run':
ret['msg'] = arg1
pass
SystemModelSetting.set('command_text', arg1)
# db이름 set/get key value
try:
tmp = arg1.strip().split(' ')
if tmp[0].startswith('setting'):
plugin = F.PluginManager.get_plugin_instance(tmp[1])
if len(tmp) == 2 or tmp[2] == 'all':
ret['json'] = plugin.ModelSetting.to_dict()
ret['ret'] = 'success'
elif tmp[2] == 'get':
ret['msg'] = plugin.ModelSetting.get(tmp[3])
ret['ret'] = 'success'
elif tmp[2] == 'set':
value = ""
if len(tmp) == 5:
value = tmp[4]
plugin.ModelSetting.set(tmp[3], value)
ret['msg'] = f"{tmp[1]} DB에 {tmp[3]}={value} 저장"
except Exception as e:
P.logger.error(f'Exception:{str(e)}')
P.logger.error(traceback.format_exc())
ret['msg'] = f"실행 실패: {str(e)}"
ret['type'] = 'danger'
elif command == 'celery_execute':
self.celery_execute(arg1, mode='foreground')
elif command == 'celery_execute_back':
@@ -138,8 +172,7 @@ class ModuleSetting(PluginModuleBase):
try:
if F.config['run_flask'] == False:
return
if SystemModelSetting.get_bool('celery_start_by_web'):
self.celery_execute()
if F.config['arg_repeat'] == 0 or SystemModelSetting.get('system_start_time') == '':
SystemModelSetting.set('system_start_time', datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
SystemModelSetting.set('repeat', str(F.config['arg_repeat']))
@@ -162,7 +195,11 @@ class ModuleSetting(PluginModuleBase):
from tool import ToolNotify
msg = f"시스템이 시작되었습니다.\n재시작: {F.config['arg_repeat']}"
ToolNotify.send_message(msg, message_id='system_start')
if SystemModelSetting.get_bool('celery_start_by_web'):
# 2022-11-14 DB는 flask가 만드는데 만들기전 celery를 실행해버림
from threading import Timer
Timer(10, self.celery_execute).start()
#self.celery_execute()
except Exception as e:
P.logger.error(f'Exception:{str(e)}')
@@ -173,9 +210,14 @@ class ModuleSetting(PluginModuleBase):
def setting_save_after(self, change_list):
if 'theme' in change_list or 'web_title' in change_list:
F.socketio.emit("refresh", {}, namespace='/framework', broadcast=True)
F.socketio.emit("refresh", {}, namespace='/framework')
elif 'notify.yaml' in change_list:
SupportFile.write_file(F.config['notify_yaml_filepath'], SystemModelSetting.get('notify.yaml'))
try:
SupportFile.write_file(F.config['notify_yaml_filepath'], SystemModelSetting.get('notify.yaml'))
SupportYaml.read_yaml(F.config['notify_yaml_filepath'])
except:
data = {'type':'danger', 'msg' : "알림 정책이 yaml 형식에 맞지 않습니다."}
F.socketio.emit("notify", data, namespace='/framework')
elif 'web_pw' in change_list:
import hashlib
enc = hashlib.md5()
@@ -185,6 +227,9 @@ class ModuleSetting(PluginModuleBase):
if SystemModelSetting.get('restart_interval') == '':
SystemModelSetting.set('restart_interval', '0')
self.__set_restart_scheduler()
elif 'log_level' in change_list:
F.set_level(SystemModelSetting.get_int('log_level'))
def __set_restart_scheduler(self):
@@ -258,6 +303,7 @@ class ModuleSetting(PluginModuleBase):
try:
time.sleep(1)
data = '정상입니다. 이 메시지는 celery 에서 반환됩니다. '
P.logger.info(data)
return data
except Exception as e:
P.logger.error(f'Exception:{str(e)}')

View File

@@ -1,4 +1,5 @@
import queue
import shlex
from support import SupportSubprocess
from tool import ToolModalCommand
@@ -25,7 +26,7 @@ class PageCommand(PluginPageBase):
ret = {'ret':'success'}
if command == 'foreground_command':
P.ModelSetting.set(f'{self.parent.name}_{self.name}_recent', arg1)
self.__foreground_execute(arg1, arg1.split(' '))
self.__foreground_execute(arg1, shlex.split(arg1))
return jsonify('')
elif command == 'job_new':
@@ -54,7 +55,7 @@ class PageCommand(PluginPageBase):
elif command == 'job_fore_execute':
db_item = ModelCommand.get_by_id(arg1)
cmd = (db_item.command + ' ' + db_item.args).strip()
self.__foreground_execute(f"Command ID: {db_item.id}", cmd.split(' '), db_item.id)
self.__foreground_execute(f"Command ID: {db_item.id}", shlex.split(cmd), db_item.id)
elif command == 'job_back_execute':
self.execute_thread_start(arg1)
ret['msg'] = "실행 요청을 하였습니다.<br>로그를 확인하세요."
@@ -64,8 +65,8 @@ class PageCommand(PluginPageBase):
ret['ret'] = 'danger'
ret['msg'] = "로그 파일이 없습니다."
elif command == 'task_sched':
job_id = req.form['arg1']
flag = (req.form['arg2'] == 'true')
job_id = arg1
flag = (arg2 == 'true')
scheduler_id = f'command_{job_id}'
if flag and F.scheduler.is_include(scheduler_id):
ret['msg'] = '이미 스케쥴러에 등록되어 있습니다.'
@@ -92,7 +93,7 @@ class PageCommand(PluginPageBase):
if command[0] != 'LOAD':
ToolModalCommand.start(title, [command])
else:
F.socketio.emit("command_modal_show", title, namespace='/framework', broadcast=True)
F.socketio.emit("command_modal_show", title, namespace='/framework')
def start_communicate_load(load_log_list):
def func():
while True:
@@ -100,7 +101,7 @@ class PageCommand(PluginPageBase):
load_log_list.truncate(0)
if logs:
P.logger.error(logs)
F.socketio.emit("command_modal_add_text", logs.strip() + '\n', namespace='/framework', broadcast=True)
F.socketio.emit("command_modal_add_text", logs.strip() + '\n', namespace='/framework')
if logs == '<<END>>':
break
time.sleep(0.3)
@@ -154,11 +155,12 @@ class PageCommand(PluginPageBase):
th = threading.Thread(target=self.execute_thread_function_by_job_id, args=(job_id,))
th.setDaemon(True)
th.start()
return th
def execute_thread_function_by_job_id(self, *args, **kwargs):
P.logger.error(d(args))
P.logger.error(d(kwargs))
#P.logger.error(d(args))
#P.logger.error(d(kwargs))
db_item = ModelCommand.get_by_id(args[0])
kwargs['id'] = args[0]
self.execute_thread_function((db_item.command + ' ' + db_item.args).strip(), **kwargs)
@@ -166,7 +168,7 @@ class PageCommand(PluginPageBase):
def execute_thread_function(self, command, **kwargs):
try:
cmd = command.split(' ')
cmd = shlex.split(command)
if cmd[0] == 'LOAD':
command_logger = F.get_logger(f"command_{kwargs['id']}")
@@ -177,8 +179,8 @@ class PageCommand(PluginPageBase):
def __init__(self, logger):
self.logger = logger
def stdout_callback(self, mode, text):
if mode == 'log':
def stdout_callback(self, call_id, mode, text):
if mode == 'LOG':
self.logger.debug(text)
else:
self.logger.debug(mode)
@@ -194,14 +196,17 @@ class PageCommand(PluginPageBase):
def plugin_load(self):
def plugin_load_thread():
try:
while F.config['loading_completed'] == False:
time.sleep(1)
db_items = ModelCommand.get_list()
for db_item in db_items:
if db_item.schedule_mode == 'startup':
self.execute_thread_start(db_item.id)
elif db_item.schedule_mode == 'scheduler' and db_item.schedule_auto_start:
self.__sched_add(db_item.id, db_item=db_item)
except Exception as exception:
logger.error('Exception:%s', exception)
except Exception as e:
logger.error(f"Exception:{str(e)}")
logger.error(traceback.format_exc())
try:
th = threading.Thread(target=plugin_load_thread)
@@ -219,7 +224,7 @@ class PageCommand(PluginPageBase):
job_id = f"command_{db_item.id}"
if scheduler.is_include(job_id):
return
job = Job(self.P.package_name, job_id, db_item.schedule_interval, self.execute_thread_function_by_job_id, db_item.description, args=db_item.id)
job = Job(self.P.package_name, job_id, db_item.schedule_interval, self.execute_thread_function_by_job_id, db_item.description, args=(db_item.id,))
scheduler.add_job_instance(job)
return True
except Exception as e:
@@ -286,6 +291,6 @@ class ModelCommand(ModelBase):
item['process'] = (SupportSubprocess.get_instance_by_call_id(f"command_{item['id']}") != None)
return data
except Exception as exception:
logger.error('Exception:%s', exception)
except Exception as e:
logger.error(f"Exception:{str(e)}")
logger.error(traceback.format_exc())

View File

@@ -14,6 +14,7 @@ __menu = {
{'uri': 'export', 'name': 'export.sh 파일'},
{'uri': 'celery', 'name': '비동기 작업(celery)'},
{'uri': 'notify', 'name': '알림'},
{'uri': 'manual/files/매뉴얼_설정.md', 'name': '매뉴얼'},
],
},
{
@@ -22,7 +23,7 @@ __menu = {
'list': [
#{'uri': 'setting', 'name': '설정'},
{'uri': 'list', 'name': '로딩 플러그인'},
#{'uri': 'all', 'name': '플러그인 목록'},
{'uri': 'all', 'name': '전체 플러그인 목록'},
],
},
{

View File

@@ -1,33 +1,9 @@
{% extends "base.html" %}
{% block content %}
</style>
<div>
{{ macros.setting_select_empty('log_select1', '로그 파일 선택 (.log)') }}
<!--{{ macros.setting_select_empty('log_select2', '로그 파일 선택 (.logX)') }}-->
<nav>
{{ macros.m_tab_head_start() }}
{{ macros.m_tab_head('old', '이전', true) }}
{{ macros.m_tab_head('new', '실시간', false) }}
{{ macros.m_tab_head_end() }}
</nav>
<div class="tab-content" id="nav-tabContent">
{{ macros.m_tab_content_start('old', true) }}
<div>
<textarea id="log" class="col-md-12" rows="30" charswidth="23" disabled style="background-color:#ffffff;visibility:hidden"></textarea>
</div>
{{ macros.m_tab_content_end() }}
{{ macros.m_tab_content_start('new', false) }}
<div>
<textarea id="add" class="col-md-12" rows="30" charswidth="23" disabled style="background-color:#ffffff;visibility:visible"></textarea>
</div>
<div class="form-inline">
<label class="form-check-label" for="auto_scroll">자동 스크롤</label>
<input id="auto_scroll" name="auto_scroll" class="form-control form-control-sm" type="checkbox" data-toggle="toggle" checked>
<span class='text-left' style="padding-left:25px; padding-top:0px">
<button id="clear" class="btn btn-sm btn-outline-success">리셋</button>
</span>
</div>
{{ macros.m_tab_content_end() }}
<div id="log_div" class="bg-dark" style="overflow:auto; border-color: blue; border: solid 1px;">
</div>
</div>
@@ -56,14 +32,6 @@ function make_form() {
str += '<option value="' + data[i] + '">' + data[i] + '</option>';
}
$("#log_select1_div").html(str);
/*
str = '<select id="log_select" name="log_select" class="form-control form-control-sm">';
data = all_list.split('|')
for(var i in data) {
str += '<option value="' + data[i] + '">' + data[i] + '</option>';
}
$("#log_select2_div").html(str);
*/
}
$("body").on('change', '#log_select', function(e){
@@ -75,11 +43,9 @@ $("body").on('change', '#log_select', function(e){
socket.emit("start", {'filename':filename} );
});
function ResizeTextAreaAllLog() {
ClientHeight = window.innerHeight
$("#log").height(ClientHeight-300);
$("#add").height(ClientHeight-320);
$("#log_div").height(ClientHeight-180);
}
$(window).resize(function() {
@@ -88,17 +54,20 @@ $(window).resize(function() {
socket.on('on_start', function(data){
document.getElementById("log").innerHTML += data.data;
document.getElementById("log").scrollTop = document.getElementById("log").scrollHeight;
document.getElementById("log").style.visibility = 'visible';
lines = splitLines(data.data);
var html = '';
for (i in lines) {
html += logline(lines[i]);
}
$('#log_div').html(html)
document.getElementById("log_div").scrollTop = document.getElementById("log_div").scrollHeight;
$('#loading').hide();
});
socket.on('add', function(data){
if (data.filename == current_filename) {
var chk = $('#auto_scroll').is(":checked");
document.getElementById("add").innerHTML += data.data;
if (chk) document.getElementById("add").scrollTop = document.getElementById("add").scrollHeight;
$('#log_div').append(logline(data.data.trim()));
document.getElementById("log_div").scrollTop = document.getElementById("log_div").scrollHeight;
}
});

View File

@@ -8,7 +8,7 @@
<div>
<div class="row">
<div class="col-sm-12">
<canvas id="mycanvas" height="100vh"></canvas>
<h3>시스템</h3>
<hr>
{{ macros.info_text_and_buttons('python_version', 'Python', [['globalLinkBtn', '패키지 관리', [('url','/system/tool/python')]]], info['python_version']) }}
@@ -45,21 +45,102 @@
<h3>스케쥴</h3>
<div id="scheduler_list_div"></div>
</div> <!--전체-->
</div>
<!--전체-->
<script src="{{ url_for('static', filename='js/chartjs-utils.js') }}"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.9.1/dist/chart.min.js"></script>
<script>
const Utils = ChartUtils.init()
</script>
<script src="https://cdn.jsdelivr.net/npm/luxon@3.0.4"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-luxon@1.2.0"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-streaming@2.0.0"></script>
<script type="text/javascript">
$(document).ready(function(){
var socket = io.connect(window.location.href);
Chart.defaults.set("plugins.streaming", {
duration: 20000,
})
socket.on('start', function(data){
});
// used for example purposes
function getRandomIntInclusive(min, max) {
min = Math.ceil(min)
max = Math.floor(max)
return Math.floor(Math.random() * (max - min + 1)) + min
}
socket.on('status', function(data) {
make_system(data.system);
make_scheduler_list(data.scheduler);
});
});
$(document).ready(function () {
var socket = io.connect(window.location.href)
var postId = 1
socket.on("start", function (data) {})
socket.on("status", function (data) {
console.log(data.system.cpu_percent)
const now = Date.now()
//myChart.data.labels.push("T " + postId++)
/* */
myChart.data.datasets[0].data.push({ x: now, y: data.system.cpu_percent.replace(/.%/g, "") })
/* */
myChart.update()
make_system(data.system)
make_scheduler_list(data.scheduler)
})
/* const onRefresh = (chart) => {
const now = Date.now()
chart.data.datasets.forEach((dataset) => {
dataset.data.push({
x: now,
y: Utils.rand(0, 100),
})
})
}
*/
var ctx_live = document.getElementById("mycanvas")
var myChart = new Chart(ctx_live, {
type: "line",
data: {
labels: [],
datasets: [
{
label: "CPU",
backgroundColor: Utils.transparentize(Utils.CHART_COLORS.blue, 0.5),
borderColor: Utils.CHART_COLORS.blue,
cubicInterpolationMode: "monotone",
data: [],
},
],
},
options: {
plugins: {
// Change options for ALL axes of THIS CHART
streaming: {
duration: 20000,
},
},
scales: {
x: {
type: "realtime",
realtime: {
duration: 60000,
refresh: 1000,
delay: 1000,
//onRefresh: onRefresh,
},
},
y: {
title: {
display: true,
//text: "Value",
},
},
},
interaction: {
intersect: false,
},
},
})
})
$("body").on('click', '#recent_version_btn', function(e){
e.preventDefault();
@@ -70,7 +151,7 @@ $("body").on('click', '#recent_version_btn', function(e){
$("body").on('click', '#config_show_btn', function(e){
e.preventDefault();
globalSendCommand('get_config', null, null, null, 'Config');
globalSendCommand('get_config');
});
@@ -184,4 +265,4 @@ function make_scheduler_list(data) {
</script>
{% endblock %}
{% endblock %}

View File

@@ -45,7 +45,6 @@ $("body").on('click', '#login_btn', function(e){
$('#username').val(),
$('#password').val(),
$("#remember").is(":checked"),
'',
function(data) {
if (data == 'redirect') {
next = document.getElementById("next").value;
@@ -53,7 +52,6 @@ $("body").on('click', '#login_btn', function(e){
if (next == '' || next == 'None' || next == '/system/restart' || '/system/shutdown') {
next = '/'
}
//console.log(next)
window.location.href = next;
} else if (data == 'no_id') {
$.notify('<strong>ID가 없습니다.</strong>', {

View File

@@ -0,0 +1,153 @@
{% extends "base.html" %}
{% block content %}
<div>
<div id="plugin_list_div"></div>
</div>
<script type="text/javascript">
$(document).ready(function(){
globalSendCommand('get_plugin_list_all', null, null, null, function(data){
make_plugin_list(data.data);
});
});
$("body").on('click', '#plugin_install_btn', function(e){
e.preventDefault();
globalSendCommand('plugin_install', $('#_plugin_git').val());
});
function make_plugin_list(data) {
current_data = data;
str = ''
count = 0;
for (i in data) {
console.log(data[i])
str += j_row_start();
str += j_col(12, '<b><span style="font-size:150%; font-style:italic; margin=0px;">' + data[i].name + '</span></b>', 'left');
//str += '<hr style="width: 100%; margin:0px; margin-bottom:10px; margin-top:2px; margin-left:15px; margin-right:15px; background-color:black; height:2px" />'
//str += '<div class="d-inline-block"></div><hr style="width: 100%; margin:0px; margin-left:15px; margin-right:15px;background-color:#808080;">';
str += j_row_end();
//str += j_hr_black(0);
str += head();
for (j in data[i].list) {
console.log(data[i].list[j]);
str += j_row_start();
count += 1
str += j_col_wide(1, (parseInt(count)), 'center')
tmp = text_color_bootstrap(data[i].list[j].title, 'text-info');
str += j_col_wide(2, tmp);
tmp = data[i].list[j].package_name;
str += j_col_wide(2, tmp);
str += j_col_wide(1, data[i].list[j].developer);
if (data[i].list[j].version == null) {
str += j_col_wide(1, "미설치");
} else {
str += j_col_wide(1, text_color_bootstrap(data[i].list[j].version, 'text-danger'));
}
if (data[i].list[j].loading == false) {
tmp = data[i].list[j].description + '<br>' + text_color('[로딩 실패] ') + data[i].list[j].status;
str += j_col_wide(3, tmp);
} else {
str += j_col_wide(3, data[i].list[j].description);
}
tmp = ''
tmp += j_button_small('globalOpenBtn', '홈페이지', {'url':data[i].list[j].home}, 'primary', false, true);
if (data[i].list[j].version == null) {
tmp += j_button_small('install_btn', '설치', {'package_name':data[i].list[j].package_name, 'title':data[i].list[j].title, 'home':data[i].list[j].home}, 'info', false, true);
} else {
tmp += j_button_small('uninstall_btn', '삭제', {'package_name':data[i].list[j].package_name, 'title':data[i].list[j].title}, 'danger', false, true);
}
tmp = j_button_group(tmp)
str += j_col_wide(2, tmp, 'right')
str += j_row_end();
if (i != current_data.length -1) str += j_hr(0);
}
str += j_row_start();
str += j_row_end();
}
$("#plugin_list_div").html(str);
}
$("body").on('click', '#json_btn', function(e){
e.preventDefault();
item_id = $(this).data('idx');
showModal(current_data[item_id]);
});
$("body").on('click', '#install_btn', function(e){
e.preventDefault();
$("#confirm_title").html("설치 확인");
$("#confirm_body").html($(this).data('title') + " 플러그인을 설치 하시겠습니까?");
home = $(this).data('home');
$('#confirm_button').attr('onclick', "javascript:install(home);");
$("#confirm_modal").modal();
});
function install(git) {
globalSendCommand('plugin_install', git);
}
$("body").on('click', '#uninstall_btn', function(e){
e.preventDefault();
$("#confirm_title").html("삭제 확인");
$("#confirm_body").html($(this).data('title') + " 플러그인을 삭제 하시겠습니까?");
package_name = $(this).data('package_name');
$('#confirm_button').attr('onclick', "javascript:uninstall(package_name);");
$("#confirm_modal").modal();
});
function uninstall(package_name) {
globalSendCommand('uninstall', package_name, null, null, function(ret) {
});
}
$("body").on('click', '#plugin_uninstall_btn', function(e){
e.preventDefault();
plugin_name = $(this).data('plugin_name')
$.ajax({
url: '/' + package_name + '/ajax/plugin_uninstall',
type: "POST",
cache: false,
data:{plugin_name:plugin_name},
success: function (data) {
if (data == 'success') {
$.notify('<strong>재시작시 적용됩니다.</strong>', {
type: 'success'
});
} else {
$.notify('<strong>실패하였습니다.</strong>', {
type: 'warning'
});
}
}
});
});
function head(str) {
tmp = '<hr style="width: 100%; margin:0px; background-color:#808080;"> \
<div class="row chover" style="padding:0px; align-items:center;"> \
<div class="col-sm-1" style="padding:0px; margin:0px; text-align:center; word-break:break-all;"><strong>Idx</strong></div> \
<div class="col-sm-2" style="padding:0px; margin:0px; text-align:left; word-break:break-all;"><strong>Title</strong></div> \
<div class="col-sm-2" style="padding:0px; margin:0px; text-align:left; word-break:break-all;"><strong>Package Name</strong></div> \
<div class="col-sm-1" style="padding:0px; margin:0px; text-align:left; word-break:break-all;"><strong>Dev.</strong></div> \
<div class="col-sm-1" style="padding:0px; margin:0px; text-align:left; word-break:break-all;"><strong>Version</strong></div> \
<div class="col-sm-5" style="padding:0px; margin:0px; text-align:left; word-break:break-all;"><strong>Description</strong></div> \
</div> \
<hr style="width: 100%; margin:0px; margin-bottom:10px; margin-top:2px; background-color:#808080; height:2px" />';
return tmp;
}
</script>
{% endblock %}

View File

@@ -19,7 +19,7 @@
<script type="text/javascript">
$(document).ready(function(){
globalSendCommand('get_plugin_list', null, null, null, null, function(data){
globalSendCommand('get_plugin_list', null, null, null, function(data){
make_plugin_list(data.data);
});
});
@@ -31,7 +31,6 @@ $("body").on('click', '#plugin_install_btn', function(e){
function make_plugin_list(data) {
current_data = data;
console.log(data);
str = ''
console.log(data)
for (i in data) {
@@ -41,7 +40,7 @@ function make_plugin_list(data) {
if (data[i].title == null) {
str += j_col_wide(2, '');
str += j_col_wide(2, data[i].package_name);
str += j_col_wide(5, '');
str += j_col_wide(5, data[i].status, 'center');
tmp = j_button('uninstall_btn', '삭제', {'package_name':data[i].package_name}, 'danger', false, true);
} else {
str += j_col_wide(2, data[i].title);
@@ -74,7 +73,7 @@ function make_plugin_list(data) {
$("body").on('click', '#json_btn', function(e){
e.preventDefault();
item_id = $(this).data('idx');
m_modal(current_data[item_id]);
showModal(current_data[item_id]);
});
@@ -89,7 +88,7 @@ $("body").on('click', '#uninstall_btn', function(e){
function uninstall(package_name) {
globalSendCommand('uninstall', package_name, null, null, null, function(ret) {
globalSendCommand('uninstall', package_name, null, null, function(ret) {
});
}

View File

@@ -28,7 +28,6 @@ $(document).ready(function() {
var restartSocket = io.connect(window.location.href);
restartSocket.on('connect', function(data){
console.log('접속 받음')
window.location.href = referer;
});
}, 3000);

View File

@@ -33,7 +33,7 @@ $('#use_login').change(function() {
$("body").on('click', '#apikey_generate_btn', function(e) {
e.preventDefault();
globalSendCommand('apikey_generate', null, null, null, null, function(ret){
globalSendCommand('apikey_generate', null, null, null, function(ret){
$("#apikey").val(ret);
});
});

View File

@@ -1,22 +1,20 @@
{% extends "base.html" %}
{% block content %}
<div>
{{ macros.m_button_group([['globalSettingSaveBtn', '설정 저장']])}}
{{ macros.m_row_start('5') }}
{{ macros.m_row_end() }}
{{ macros.m_hr() }}
{{ macros.m_button_group([['globalSettingSaveBtn', '설정 저장']])}}
{{ macros.m_row_start('5') }}
{{ macros.m_row_end() }}
{{ macros.m_hr() }}
<form id='setting' name='setting'>
{{ macros.setting_input_int('port', 'Port', value=arg['port'], min='1', placeholder='Port', desc=['포트 번호입니다.', '네이티브 설치 혹은 도커 네트워크 타입이 호스트일 경우 반영됩니다.', '도커 브릿지 모드인 경우는 docker run -p 옵션에서 변경하시기 바랍니다.', '경고 : -p 브릿지 모드로 사용중 일 경우 9999번을 변경하지 마세요.']) }}
{{ macros.setting_input_text_and_buttons('ddns', 'DDNS', [['ddns_test_btn', '테스트']], value=arg['ddns'], desc=['외부에서 접근시 사용할 DDNS. http:// 나 https:// 로 시작해야합니다.', 'URL생성시 사용합니다.', '테스트 버튼 클릭 후 버전을 확인 할 수 있어야 합니다.']) }}
{{ macros.setting_input_text('restart_interval', '자동 재시작 시간', value=arg['restart_interval'], col='3', desc=['자동 재시작 간격(시간단위)이나 Cron 설정을 입력합니다.', '0이면 재시작 안함.']) }}
{{ macros.setting_checkbox('restart_notify', '시작시 알림', value=arg['restart_notify'], desc=['메시지 ID: system_start']) }}
{{ macros.setting_select('log_level', '로그 레벨', [['10', 'DEBUG'],['20', 'INFO'],['30', 'WARNING'],['40', 'ERROR'], ['50', 'CRITICAL'] ], value=arg['log_level'], col='3') }}
{{ macros.m_hr() }}
{{ macros.setting_input_text_and_buttons('command_text', 'Command', [['command_run_btn', 'Run']], value='', desc='') }}
</form>
</div><!--전체-->
<form id='setting' name='setting'>
{{ macros.setting_input_int('port', 'Port', value=arg['port'], min='1', placeholder='Port', desc=['포트 번호입니다.', '네이티브 설치 혹은 도커 네트워크 타입이 호스트일 경우 반영됩니다.', '도커 브릿지 모드인 경우는 docker run -p 옵션에서 변경하시기 바랍니다.', '경고 : -p 브릿지 모드로 사용중 일 경우 9999번을 변경하지 마세요.']) }}
{{ macros.setting_input_text_and_buttons('ddns', 'DDNS', [['ddns_test_btn', '테스트']], value=arg['ddns'], desc=['외부에서 접근시 사용할 DDNS. http:// 나 https:// 로 시작해야합니다.', 'URL생성시 사용합니다.', '테스트 버튼 클릭 후 버전을 확인 할 수 있어야 합니다.']) }}
{{ macros.setting_input_text('restart_interval', '자동 재시작 시간', value=arg['restart_interval'], col='3', desc=['자동 재시작 간격(시간단위)이나 Cron 설정을 입력합니다.', '0이면 재시작 안함.']) }}
{{ macros.setting_checkbox('restart_notify', '시작시 알림', value=arg['restart_notify'], desc=['메시지 ID: system_start']) }}
{{ macros.setting_select('log_level', '로그 레벨', [['10', 'DEBUG'],['20', 'INFO'],['30', 'WARNING'],['40', 'ERROR'], ['50', 'CRITICAL'] ], value=arg['log_level'], col='3') }}
{{ macros.m_hr() }}
{{ macros.setting_input_text_and_buttons('command_text', 'Command', [['command_run_btn', 'Run']], value=arg['command_text'], desc='') }}
</form>
<script type="text/javascript">
$("body").on('click', '#ddns_test_btn', function(e){

View File

@@ -9,7 +9,7 @@
<div class="tab-content" id="nav-tabContent">
{{ macros.info_text('use_celery', 'use_celery 값', arg['use_celery']) }}
{{ macros.info_text('running_type', 'running_type 값', arg['running_type']) }}
{{ macros.info_text('_tmp', '설명', "Docker는 celery가 서비스로 동작하기 때문에 설정이 불필요하며 '테스트' 버튼으로 작동 여부 확인만 가능합니다.", desc=['','native로 동작하는 경우 celery 실행을 따로 하지 않고 한번에 실행하기 위한 설정', 'Redis는 설정된 Port로 동작중인 상태여야 함.']) }}
{{ macros.info_text('_tmp', '설명', "보통 시작시 celery 실행 On 상태로 동작하며 개발시에만 Off로 설정.", desc=None) }}
{{ macros.m_hr() }}
<form id='setting' name='setting'>
{{ macros.setting_checkbox('celery_start_by_web', '시작시 celery 실행', value=arg['celery_start_by_web']) }}

View File

@@ -29,6 +29,14 @@
{{ macros.setting_input_text('notify_discord_webhook', '웹훅', value=arg['notify_discord_webhook']) }}
{{ macros.setting_input_text_and_buttons('tmp_text_discord', 'Test', [['tmp_discord_test_btn', '전송']], value='테스트 메시지입니다.', col='9') }}
</div>
{{ macros.m_hr() }}
{{ macros.setting_checkbox('notify_slack_use', '슬랙 사용', value=arg['notify_slack_use']) }}
<div id="notify_slack_use_div" class="collapse">
{{ macros.setting_input_text('notify_slack_webhook', '웹훅', value=arg['notify_slack_webhook']) }}
{{ macros.setting_input_text_and_buttons('tmp_text_slack', 'Test', [['tmp_slack_test_btn', '전송']], value='테스트 메시지입니다.', col='9') }}
</div>
{{ macros.m_tab_content_end() }}
{{ macros.m_tab_content_start('advanced', false) }}
@@ -53,6 +61,7 @@
$(document).ready(function(){
use_collapse("notify_telegram_use");
use_collapse("notify_discord_use");
use_collapse("notify_slack_use");
use_collapse("notify_advaned_use");
});
@@ -64,6 +73,10 @@ $('#notify_discord_use').change(function() {
use_collapse('notify_discord_use');
});
$('#notify_slack_use').change(function() {
use_collapse('notify_slack_use');
});
$('#notify_advaned_use').change(function() {
use_collapse('notify_advaned_use');
});
@@ -80,6 +93,11 @@ $("body").on('click', '#tmp_discord_test_btn', function(e){
globalSendCommand('notify_test', 'discord', $('#notify_discord_webhook').val(), $('#tmp_text_discord').val());
});
$("body").on('click', '#tmp_slack_test_btn', function(e){
e.preventDefault();
globalSendCommand('notify_test', 'slack', $('#notify_slack_webhook').val(), $('#tmp_text_slack').val());
});
$("body").on('click', '#tmp_advanced_test_btn', function(e){
e.preventDefault();
globalSendCommand('notify_test', 'advanced', $('#tmp_message_id').val(), $('#tmp_text_advanced').val());

View File

@@ -63,7 +63,7 @@ $("body").on('click', '#foreground_command_btn', function(e){
$("body").on('click', '#job_new_btn', function(e){
e.preventDefault();
globalSendCommandPage('job_new', $('#command').val(), null, null, null, function(ret){
globalSendCommandPage('job_new', $('#command').val(), null, null, function(ret){
request_list();
});
});
@@ -79,7 +79,7 @@ $("body").on('click', '#select_file_btn', function(e){
function request_list() {
globalSendCommandPage('job_list', null, null, null, null, function(ret){
globalSendCommandPage('job_list', null, null, null, function(ret){
make_list(ret.data);
});
}
@@ -92,18 +92,16 @@ function make_list(data) {
<th style="width:60%; text-align:center;">Command & arg & Desc</th> \
<th style="width:5%; text-align:center;">자동</th> \
<th colspan="2" style="width:20%; text-align:center;">스케쥴 상태</th> \
<th style="width:10%; text-align:center;">스케쥴</th> \
<th style="width:10%; text-align:center;">스케쥴주기</th> \
</tr></thead><tbody id="list">';
if (data.length == 0) str += '<tr><td colspan="6"><h4>작업이 없습니다.</h4></td></tr>';
for(i in data) {
console.log(data[i]);
//console.log(data[i]);
str += '<tr class="chover" style="cursor: pointer;" data-toggle="collapse" data-target="#collapse_' + i + '" aria-expanded="true" >';
str += '<td rowspan="2" scope="col" style="width:5%; text-align:center;">'+ (data[i].id) + '</td>';
// command
tmp = '';
tmp += text_color(data[i].command, 'blue') + '<br>';
@@ -123,7 +121,7 @@ function make_list(data) {
tmp1 = "시작시 한번 실행";
} else if (data[i].schedule_mode == 'scheduler') {
tmp1 = "스케쥴링";
tmp2 = '<input id="use_checkbox|'+data[i].id+'" type="checkbox" data-id='+data[i].id+' data-toggle="toggle" data-on="On" data-off="Off" data-onstyle="info" data-offstyle="danger" data-size="small" ' + ((data[i].scheduler_is_include) ? 'checked' : '') + '>';
tmp2 = '<input id="use_checkbox|'+data[i].id+'" type="checkbox" data-id='+data[i].id+' data-toggle="toggle" data-on="On" data-off="Off" data-onstyle="danger" data-offstyle="info" data-size="small" ' + ((data[i].scheduler_is_include) ? 'checked' : '') + '>';
if (data[i].scheduler_is_include) {
tmp2 += (data[i].scheduler_is_running) ? "<br>실행중" : "<br>대기중";
}
@@ -197,7 +195,7 @@ $("body").on('click', '#job_save_btn', function(e){
}
var formData = getFormdata('#item_setting');
globalSendCommandPage('job_save', formData, null, null, null, function(ret){
globalSendCommandPage('job_save', formData, null, null, function(ret){
if (ret.ret == 'success') {
$('#job_modal').modal('hide');
request_list();
@@ -216,7 +214,7 @@ $("body").on('click', '#job_remove_btn', function(e){
});
function remove_job(job_id) {
globalSendCommandPage('job_remove', job_id, null, null, null, function(ret){
globalSendCommandPage('job_remove', job_id, null, null, function(ret){
if (ret.ret == 'success') {
$('#job_modal').modal('hide');
request_list();
@@ -267,14 +265,14 @@ $("body").on('click', '#job_fore_execute_btn', function(e){
$("body").on('click', '#job_back_execute_btn', function(e){
e.preventDefault();
globalSendCommandPage('job_back_execute', $(this).data('id'), null, null, null, function(e) {
globalSendCommandPage('job_back_execute', $(this).data('id'), null, null, function(e) {
request_list();
});
});
$("body").on('click', '#job_log_btn', function(e){
e.preventDefault();
globalSendCommandPage('job_log', $(this).data('id'), null, null, null, function(data){
globalSendCommandPage('job_log', $(this).data('id'), null, null, function(data){
if (data.ret == 'success') {
redirect = '/system/all_log/list';
$.redirectPost(redirect, {filename: data.filename});
@@ -293,14 +291,14 @@ $("body").on('click', '#job_cmd_input_btn', function(e){
$("body").on('change', 'input[id^="use_checkbox|"]', function(e){
e.preventDefault();
globalSendCommandPage('task_sched', $(this).data('id'), $(this).prop('checked'), null, null, function(e) {
globalSendCommandPage('task_sched', $(this).data('id'), $(this).prop('checked'), null, function(e) {
request_list();
});
});
$("body").on('click', '#job_process_stop_btn', function(e){
e.preventDefault();
globalSendCommandPage('job_process_stop', $(this).data('id'), null, null, null, function(e) {
globalSendCommandPage('job_process_stop', $(this).data('id'), null, null, function(e) {
request_list();
});
});

View File

@@ -16,7 +16,7 @@ $(document).ready(function(){
});
function refresh() {
globalSendCommandPage('get_freeze', null, null, null, null, function(ret){
globalSendCommandPage('get_freeze', null, null, null, function(ret){
make_list(ret.data);
});
}