test
This commit is contained in:
275
lib/system/___logic.py
Normal file
275
lib/system/___logic.py
Normal file
@@ -0,0 +1,275 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#########################################################
|
||||
# python
|
||||
import os
|
||||
import traceback
|
||||
import logging
|
||||
from datetime import datetime
|
||||
import string
|
||||
import random
|
||||
import json
|
||||
|
||||
# third-party
|
||||
import requests
|
||||
from flask import Blueprint, request, Response, send_file, render_template, redirect, jsonify
|
||||
from flask_login import login_user, logout_user, current_user, login_required
|
||||
|
||||
|
||||
from framework import F, frame, app, db, scheduler, VERSION, path_app_root, logger, Job, User
|
||||
from framework.util import Util
|
||||
|
||||
# 패키지
|
||||
from .model import ModelSetting
|
||||
import system
|
||||
|
||||
#########################################################
|
||||
|
||||
class SystemLogic(object):
|
||||
point = 0
|
||||
db_default = {
|
||||
'db_version' : '1',
|
||||
'port' : '9999',
|
||||
'ddns' : 'http://localhost:9999',
|
||||
#'url_filebrowser' : 'http://localhost:9998',
|
||||
#'url_celery_monitoring' : 'http://localhost:9997',
|
||||
'id' : 'admin',
|
||||
'pw' : '//nCv0/YkVI3U2AAgYwOuJ2hPlQ7cDYIbuaCt4YJupY=',
|
||||
'system_start_time' : '',
|
||||
'repeat' : '',
|
||||
'auto_restart_hour' : '12',
|
||||
#'unique' : '',
|
||||
'theme' : 'Cerulean',
|
||||
'log_level' : '10',
|
||||
'use_login' : 'False',
|
||||
'link_json' : '[{"type":"link","title":"위키","url":"https://sjva.me/wiki/public/start"}]',
|
||||
'plugin_dev_path': '',
|
||||
'plugin_tving_level2' : 'False',
|
||||
'web_title' : 'Home',
|
||||
'my_ip' : '',
|
||||
'wavve_guid' : '',
|
||||
|
||||
#인증
|
||||
'auth_use_apikey' : 'False',
|
||||
'auth_apikey' : '',
|
||||
#'hide_menu' : 'True',
|
||||
|
||||
#Selenium
|
||||
'selenium_remote_url' : '',
|
||||
'selenium_remote_default_option' : '--no-sandbox\n--disable-gpu',
|
||||
'selenium_binary_default_option' : '',
|
||||
|
||||
# notify
|
||||
'notify_telegram_use' : 'False',
|
||||
'notify_telegram_token' : '',
|
||||
'notify_telegram_chat_id' : '',
|
||||
'notify_telegram_disable_notification' : 'False',
|
||||
'notify_discord_use' : 'False',
|
||||
'notify_discord_webhook' : '',
|
||||
|
||||
'notify_advaned_use' : 'False',
|
||||
'notify_advaned_policy' : u"# 각 플러그인 설정 설명에 명시되어 있는 ID = 형식\n# DEFAULT 부터 주석(#) 제거 후 작성\n\n# DEFAULT = ",
|
||||
|
||||
# telegram
|
||||
'telegram_bot_token' : '',
|
||||
'telegram_bot_auto_start' : 'False',
|
||||
'telegram_resend' : 'False',
|
||||
'telegram_resend_chat_id' : '',
|
||||
|
||||
# 홈페이지 연동 2020-06-07
|
||||
'sjva_me_user_id' : '',
|
||||
'auth_status' : '',
|
||||
'sjva_id' : '',
|
||||
|
||||
# memo
|
||||
'memo' : '',
|
||||
|
||||
# tool - decrypt
|
||||
'tool_crypt_use_user_key' : 'False',
|
||||
'tool_crypt_user_key' : '',
|
||||
'tool_crypt_encrypt_word' : '',
|
||||
'tool_crypt_decrypt_word' : '',
|
||||
|
||||
'use_beta' : 'False',
|
||||
}
|
||||
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_info():
|
||||
info = {}
|
||||
import platform
|
||||
info['platform'] = platform.platform()
|
||||
info['processor'] = platform.processor()
|
||||
|
||||
import sys
|
||||
info['python_version'] = sys.version
|
||||
info['version'] = VERSION
|
||||
info['recent_version'] = SystemLogic.recent_version
|
||||
info['path_app_root'] = path_app_root
|
||||
info['running_type'] = u'%s. 비동기 작업 : %s' % (frame.config['running_type'], u"사용" if frame.config['use_celery'] else "미사용")
|
||||
import system
|
||||
|
||||
info['auth'] = frame.config['member']['auth_desc']
|
||||
info['cpu_percent'] = 'not supported'
|
||||
info['memory'] = 'not supported'
|
||||
info['disk'] = 'not supported'
|
||||
if frame.config['running_type'] != 'termux':
|
||||
try:
|
||||
import psutil
|
||||
from framework.util import Util
|
||||
info['cpu_percent'] = '%s %%' % psutil.cpu_percent()
|
||||
tmp = psutil.virtual_memory()
|
||||
#info['memory'] = [Util.sizeof_fmt(tmp[0], suffix='B'), Util.sizeof_fmt(tmp[3]), Util.sizeof_fmt(tmp[1]), tmp[2]]
|
||||
info['memory'] = u'전체 : %s 사용량 : %s 남은량 : %s (%s%%)' % (Util.sizeof_fmt(tmp[0], suffix='B'), Util.sizeof_fmt(tmp[3], suffix='B'), Util.sizeof_fmt(tmp[1], suffix='B'), tmp[2])
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
import platform
|
||||
if platform.system() == 'Windows':
|
||||
s = os.path.splitdrive(path_app_root)
|
||||
root = s[0]
|
||||
else:
|
||||
root = '/'
|
||||
tmp = psutil.disk_usage(root)
|
||||
info['disk'] = u'전체 : %s 사용량 : %s 남은량 : %s (%s%%) - 드라이브 (%s)' % (Util.sizeof_fmt(tmp[0], suffix='B'), Util.sizeof_fmt(tmp[1], suffix='B'), Util.sizeof_fmt(tmp[2], suffix='B'), tmp[3], root)
|
||||
except Exception as exception:
|
||||
pass
|
||||
try:
|
||||
tmp = SystemLogic.get_setting_value('system_start_time')
|
||||
#logger.debug('SYSTEM_START_TIME:%s', tmp)
|
||||
tmp_datetime = datetime.strptime(tmp, '%Y-%m-%d %H:%M:%S')
|
||||
timedelta = datetime.now() - tmp_datetime
|
||||
info['time'] = u'시작 : %s 경과 : %s 재시작 : %s' % (tmp, str(timedelta).split('.')[0], frame.config['arg_repeat'])
|
||||
except Exception as exception:
|
||||
info['time'] = str(exception)
|
||||
return info
|
||||
|
||||
|
||||
@staticmethod
|
||||
def setting_save_system(req):
|
||||
try:
|
||||
for key, value in req.form.items():
|
||||
logger.debug('Key:%s Value:%s', key, value)
|
||||
entity = db.session.query(ModelSetting).filter_by(key=key).with_for_update().first()
|
||||
entity.value = value
|
||||
#if key == 'theme':
|
||||
# SystemLogic.change_theme(value)
|
||||
db.session.commit()
|
||||
lists = ModelSetting.query.all()
|
||||
SystemLogic.setting_list = Util.db_list_to_dict(lists)
|
||||
frame.users[db.session.query(ModelSetting).filter_by(key='id').first().value] = User(db.session.query(ModelSetting).filter_by(key='id').first().value, passwd_hash=db.session.query(ModelSetting).filter_by(key='pw').first().value)
|
||||
SystemLogic.set_restart_scheduler()
|
||||
frame.set_level(int(db.session.query(ModelSetting).filter_by(key='log_level').first().value))
|
||||
|
||||
return True
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def setting_save_after():
|
||||
try:
|
||||
frame.users[ModelSetting.get('id')] = User(ModelSetting.get('id'), passwd_hash=ModelSetting.get('pw'))
|
||||
SystemLogic.set_restart_scheduler()
|
||||
frame.set_level(int(db.session.query(ModelSetting).filter_by(key='log_level').first().value))
|
||||
from .logic_site import SystemLogicSite
|
||||
SystemLogicSite.get_daum_cookies(force=True)
|
||||
SystemLogicSite.create_tving_instance()
|
||||
return True
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def change_theme(theme):
|
||||
try:
|
||||
source = os.path.join(path_app_root, 'static', 'css', 'theme', '%s_bootstrap.min.css' % theme)
|
||||
target = os.path.join(path_app_root, 'static', 'css', 'bootstrap.min.css')
|
||||
os.remove(target)
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def get_setting_value(key):
|
||||
try:
|
||||
#logger.debug('get_setting_value:%s', key)
|
||||
entity = db.session.query(ModelSetting).filter_by(key=key).first()
|
||||
if entity is None:
|
||||
return None
|
||||
else:
|
||||
return entity.value
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
logger.error('error key : %s', key)
|
||||
return False
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@staticmethod
|
||||
def command_run(command_text):
|
||||
try:
|
||||
ret = {}
|
||||
tmp = command_text.strip().split(' ')
|
||||
if not tmp:
|
||||
ret['ret'] = 'success'
|
||||
ret['log'] = 'Empty..'
|
||||
return ret
|
||||
if tmp[0] == 'set':
|
||||
if len(tmp) == 3:
|
||||
if tmp[1] == 'token':
|
||||
tmp[1] = 'unique'
|
||||
entity = db.session.query(ModelSetting).filter_by(key=tmp[1]).with_for_update().first()
|
||||
if entity is None:
|
||||
ret['ret'] = 'fail'
|
||||
ret['log'] = '%s not exist' % tmp[1]
|
||||
return ret
|
||||
entity.value = tmp[2] if tmp[2] != 'EMPTY' else ""
|
||||
db.session.commit()
|
||||
ret['ret'] = 'success'
|
||||
ret['log'] = '%s - %s' % (tmp[1], tmp[2])
|
||||
return ret
|
||||
|
||||
if tmp[0] == 'set2':
|
||||
if tmp[1] == 'klive':
|
||||
from klive import ModelSetting as KLiveModelSetting
|
||||
if KLiveModelSetting.get(tmp[2]) is not None:
|
||||
KLiveModelSetting.set(tmp[2], tmp[3])
|
||||
ret['ret'] = 'success'
|
||||
ret['log'] = f'KLive 설정 값 변경 : {tmp[2]} - {tmp[3]}'
|
||||
return ret
|
||||
|
||||
|
||||
ret['ret'] = 'fail'
|
||||
ret['log'] = 'wrong command'
|
||||
return ret
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
ret['ret'] = 'fail'
|
||||
ret['log'] = str(exception)
|
||||
return ret
|
||||
|
||||
@staticmethod
|
||||
def link_save(link_data_str):
|
||||
try:
|
||||
data = json.loads(link_data_str)
|
||||
entity = db.session.query(ModelSetting).filter_by(key='link_json').with_for_update().first()
|
||||
entity.value = link_data_str
|
||||
db.session.commit()
|
||||
SystemLogic.apply_menu_link()
|
||||
return True
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
return False
|
||||
|
||||
14
lib/system/__init__.py
Normal file
14
lib/system/__init__.py
Normal file
@@ -0,0 +1,14 @@
|
||||
"""
|
||||
from .plugin import blueprint, menu, plugin_load, plugin_unload, restart, shutdown
|
||||
from .logic import SystemLogic
|
||||
from .model import ModelSetting
|
||||
from .model import ModelSetting as SystemModelSetting
|
||||
|
||||
|
||||
from .logic_plugin import LogicPlugin
|
||||
from .logic_selenium import SystemLogicSelenium
|
||||
from .logic_command import SystemLogicCommand
|
||||
|
||||
from .logic_site import SystemLogicSite
|
||||
|
||||
"""
|
||||
160
lib/system/logic_auth.py
Normal file
160
lib/system/logic_auth.py
Normal file
@@ -0,0 +1,160 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#########################################################
|
||||
# python
|
||||
import os
|
||||
import traceback
|
||||
import random
|
||||
import json
|
||||
import string
|
||||
import codecs
|
||||
|
||||
# third-party
|
||||
import requests
|
||||
from flask import Blueprint, request, Response, send_file, render_template, redirect, jsonify
|
||||
|
||||
# sjva 공용
|
||||
|
||||
from framework import frame, path_app_root, app
|
||||
from framework.util import Util
|
||||
|
||||
# 패키지
|
||||
from .plugin import package_name, logger
|
||||
from .model import ModelSetting
|
||||
|
||||
class SystemLogicAuth(object):
|
||||
@staticmethod
|
||||
def process_ajax(sub, req):
|
||||
logger.debug(sub)
|
||||
try:
|
||||
if sub == 'apikey_generate':
|
||||
ret = SystemLogicAuth.apikey_generate()
|
||||
return jsonify(ret)
|
||||
elif sub == 'do_auth':
|
||||
ret = SystemLogicAuth.do_auth()
|
||||
return jsonify(ret)
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
##########################################################################
|
||||
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_auth_status(retry=True):
|
||||
try:
|
||||
value = ModelSetting.get('auth_status')
|
||||
ret = {'ret' : False, 'desc' : '', 'level' : 0, 'point': 0}
|
||||
if value == '':
|
||||
ret['desc'] = '미인증'
|
||||
elif value == 'wrong_id':
|
||||
ret['desc'] = '미인증 - 홈페이지 아이디가 없습니다.'
|
||||
elif value == 'too_many_sjva':
|
||||
ret['desc'] = '미인증 - 너무 많은 SJVA를 사용중입니다.'
|
||||
elif value == 'wrong_apikey':
|
||||
ret['desc'] = '미인증 - 홈페이지에 등록된 APIKEY와 다릅니다.'
|
||||
elif value == 'auth_status':
|
||||
ret['desc'] = '인증 실패'
|
||||
else:
|
||||
status = SystemLogicAuth.check_auth_status(value)
|
||||
if status is not None and status['ret']:
|
||||
ret['ret'] = status['ret']
|
||||
ret['desc'] = '인증되었습니다. (회원등급:%s, 포인트:%s)' % (status['level'], status['point'])
|
||||
ret['level'] = status['level']
|
||||
ret['point'] = status['point']
|
||||
else:
|
||||
if retry:
|
||||
SystemLogicAuth.do_auth()
|
||||
#ModelSetting.set('auth_status', SystemLogicAuth.make_auth_status())
|
||||
return SystemLogicAuth.get_auth_status(retry=False)
|
||||
else:
|
||||
ret['desc'] = '잘못된 값입니다. 다시 인증하세요.'
|
||||
return ret
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
@staticmethod
|
||||
def check_auth_status(value=None):
|
||||
try:
|
||||
from support.base.aes import SupportAES
|
||||
mykey=(codecs.encode(SystemLogicAuth.get_ip().encode(), 'hex').decode() + codecs.encode(ModelSetting.get('auth_apikey').encode(), 'hex').decode()).zfill(32)[:32].encode()
|
||||
logger.debug(mykey)
|
||||
tmp = SupportAES.decrypt(value, mykey=mykey)
|
||||
tmp = tmp.split('_')
|
||||
ret = {}
|
||||
ret['ret'] = (ModelSetting.get('sjva_id') == tmp[0])
|
||||
ret['level'] = int(tmp[1])
|
||||
ret['point'] = int(tmp[2])
|
||||
return ret
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
@staticmethod
|
||||
def make_auth_status(level, point):
|
||||
try:
|
||||
from support.base import SupportAES
|
||||
mykey=(codecs.encode(SystemLogicAuth.get_ip().encode(), 'hex').decode() + codecs.encode(ModelSetting.get('auth_apikey').encode(), 'hex').decode()).zfill(32)[:32].encode()
|
||||
ret = SupportAES.encrypt(str('%s_%s_%s' % (ModelSetting.get('sjva_id'), level, point)), mykey=mykey)
|
||||
logger.debug(ret)
|
||||
return ret
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_ip():
|
||||
import socket
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
try:
|
||||
# doesn't even have to be reachable
|
||||
s.connect(('10.255.255.255', 1))
|
||||
IP = s.getsockname()[0]
|
||||
except Exception:
|
||||
IP = '127.0.0.1'
|
||||
finally:
|
||||
s.close()
|
||||
logger.debug('IP:%s', IP)
|
||||
return IP
|
||||
|
||||
@staticmethod
|
||||
def do_auth():
|
||||
try:
|
||||
ret = {'ret':False, 'msg':'', 'level':0, 'point':0}
|
||||
apikey = ModelSetting.get('auth_apikey')
|
||||
user_id = ModelSetting.get('sjva_me_user_id')
|
||||
if len(apikey) != 10:
|
||||
ret['msg'] = 'APIKEY 문자 길이는 10자리여야합니다.'
|
||||
return ret
|
||||
if user_id == '':
|
||||
ret['msg'] = '홈페이지 ID가 없습니다.'
|
||||
return ret
|
||||
|
||||
data = requests.post(f"{frame.config['DEFINE']['WEB_DIRECT_URL']}/sjva/auth.php", data={'apikey':apikey,'user_id':user_id, 'sjva_id':ModelSetting.get('sjva_id')}).json()
|
||||
if data['result'] == 'success':
|
||||
ret['ret'] = True
|
||||
ret['msg'] = u'총 %s개 등록<br>회원등급:%s, 포인트:%s' % (data['count'], data['level'], data['point'])
|
||||
ret['level'] = int(data['level'])
|
||||
ret['point'] = int(data['point'])
|
||||
ModelSetting.set('auth_status', SystemLogicAuth.make_auth_status(ret['level'], ret['point']))
|
||||
else:
|
||||
ModelSetting.set('auth_status', data['result'])
|
||||
tmp = SystemLogicAuth.get_auth_status(retry=False)
|
||||
ret['ret'] = tmp['ret']
|
||||
ret['msg'] = tmp['desc']
|
||||
return ret
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
ret['msg'] = '인증 실패'
|
||||
ret['level'] = -1
|
||||
ret['point'] = -1
|
||||
ModelSetting.set('auth_status', 'auth_fail')
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
|
||||
246
lib/system/logic_command.py
Normal file
246
lib/system/logic_command.py
Normal file
@@ -0,0 +1,246 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#########################################################
|
||||
# python
|
||||
import os
|
||||
import traceback
|
||||
import logging
|
||||
import platform
|
||||
import subprocess
|
||||
import threading
|
||||
import sys
|
||||
import io
|
||||
import time
|
||||
import json
|
||||
import queue
|
||||
# third-party
|
||||
|
||||
# sjva 공용
|
||||
|
||||
from framework import path_app_root, socketio, app, logger
|
||||
|
||||
# 패키지
|
||||
|
||||
|
||||
|
||||
class SystemLogicCommand(object):
|
||||
|
||||
commands = None
|
||||
process = None
|
||||
stdout_queue = None
|
||||
thread = None
|
||||
send_to_ui_thread = None
|
||||
return_log = None
|
||||
@staticmethod
|
||||
def start(title, commands, clear=True, wait=False, show_modal=True):
|
||||
try:
|
||||
if show_modal:
|
||||
if clear:
|
||||
socketio.emit("command_modal_clear", None, namespace='/framework', broadcast=True)
|
||||
SystemLogicCommand.return_log = []
|
||||
SystemLogicCommand.title = title
|
||||
SystemLogicCommand.commands = commands
|
||||
SystemLogicCommand.thread = threading.Thread(target=SystemLogicCommand.execute_thread_function, args=(show_modal,))
|
||||
SystemLogicCommand.thread.setDaemon(True)
|
||||
SystemLogicCommand.thread.start()
|
||||
if wait:
|
||||
time.sleep(1)
|
||||
SystemLogicCommand.thread.join()
|
||||
return SystemLogicCommand.return_log
|
||||
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
@staticmethod
|
||||
def execute_thread_function(show_modal):
|
||||
try:
|
||||
#if wait:
|
||||
if show_modal:
|
||||
socketio.emit("loading_hide", None, namespace='/framework', broadcast=True)
|
||||
for command in SystemLogicCommand.commands:
|
||||
#logger.debug('Command :%s', command)
|
||||
if command[0] == 'msg':
|
||||
if show_modal:
|
||||
socketio.emit("command_modal_add_text", '%s\n\n' % command[1], namespace='/framework', broadcast=True)
|
||||
elif command[0] == 'system':
|
||||
if show_modal:
|
||||
socketio.emit("command_modal_add_text", '$ %s\n\n' % command[1], namespace='/framework', broadcast=True)
|
||||
os.system(command[1])
|
||||
else:
|
||||
show_command = True
|
||||
if command[0] == 'hide':
|
||||
show_command = False
|
||||
command = command[1:]
|
||||
#SystemLogicCommand.process = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, bufsize=1)
|
||||
SystemLogicCommand.process = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, encoding='utf8')
|
||||
SystemLogicCommand.start_communicate(command, show_command=show_command)
|
||||
SystemLogicCommand.send_queue_start(show_modal)
|
||||
if SystemLogicCommand.process is not None:
|
||||
SystemLogicCommand.process.wait()
|
||||
time.sleep(1)
|
||||
|
||||
except Exception as exception:
|
||||
#logger.error('Exception:%s', exception)
|
||||
#logger.error(traceback.format_exc())
|
||||
if show_modal:
|
||||
socketio.emit("command_modal_show", SystemLogicCommand.title, namespace='/framework', broadcast=True)
|
||||
socketio.emit("command_modal_add_text", str(exception), namespace='/framework', broadcast=True)
|
||||
socketio.emit("command_modal_add_text", str(traceback.format_exc()), namespace='/framework', broadcast=True)
|
||||
|
||||
|
||||
|
||||
@staticmethod
|
||||
def start_communicate(current_command, show_command=True):
|
||||
SystemLogicCommand.stdout_queue = queue.Queue()
|
||||
if show_command:
|
||||
SystemLogicCommand.stdout_queue.put('$ %s\n' % ' '.join(current_command))
|
||||
sout = io.open(SystemLogicCommand.process.stdout.fileno(), 'rb', closefd=False)
|
||||
#serr = io.open(process.stderr.fileno(), 'rb', closefd=False)
|
||||
|
||||
def Pump(stream):
|
||||
queue = queue.Queue()
|
||||
|
||||
def rdr():
|
||||
logger.debug('START RDR')
|
||||
while True:
|
||||
buf = SystemLogicCommand.process.stdout.read(1)
|
||||
if buf:
|
||||
queue.put( buf )
|
||||
else:
|
||||
queue.put( None )
|
||||
break
|
||||
logger.debug('END RDR')
|
||||
queue.put( None )
|
||||
time.sleep(1)
|
||||
|
||||
#Logic.command_close()
|
||||
def clct():
|
||||
active = True
|
||||
logger.debug('START clct')
|
||||
while active:
|
||||
r = queue.get()
|
||||
if r is None:
|
||||
break
|
||||
try:
|
||||
while True:
|
||||
r1 = queue.get(timeout=0.005)
|
||||
if r1 is None:
|
||||
active = False
|
||||
break
|
||||
else:
|
||||
r += r1
|
||||
except:
|
||||
pass
|
||||
if r is not None:
|
||||
try:
|
||||
r = r.decode('utf-8')
|
||||
except Exception as exception:
|
||||
#logger.error('Exception:%s', e)
|
||||
#logger.error(traceback.format_exc())
|
||||
try:
|
||||
r = r.decode('cp949')
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
try:
|
||||
r = r.decode('euc-kr')
|
||||
except:
|
||||
pass
|
||||
|
||||
SystemLogicCommand.stdout_queue.put(r)
|
||||
#SystemLogicCommand.return_log.append(r)
|
||||
SystemLogicCommand.return_log += r.split('\n')
|
||||
logger.debug('IN:%s', r)
|
||||
SystemLogicCommand.stdout_queue.put('<END>')
|
||||
logger.debug('END clct')
|
||||
#Logic.command_close()
|
||||
for tgt in [rdr, clct]:
|
||||
th = threading.Thread(target=tgt)
|
||||
th.setDaemon(True)
|
||||
th.start()
|
||||
Pump(sout)
|
||||
#Pump(serr, 'stderr')
|
||||
|
||||
@staticmethod
|
||||
def send_queue_start(show_modal):
|
||||
def send_to_ui_thread_function():
|
||||
logger.debug('send_queue_thread_function START')
|
||||
if show_modal:
|
||||
socketio.emit("command_modal_show", SystemLogicCommand.title, namespace='/framework', broadcast=True)
|
||||
while SystemLogicCommand.stdout_queue:
|
||||
line = SystemLogicCommand.stdout_queue.get()
|
||||
logger.debug('Send to UI :%s', line)
|
||||
if line == '<END>':
|
||||
if show_modal:
|
||||
socketio.emit("command_modal_add_text", "\n", namespace='/framework', broadcast=True)
|
||||
break
|
||||
else:
|
||||
if show_modal:
|
||||
socketio.emit("command_modal_add_text", line, namespace='/framework', broadcast=True)
|
||||
SystemLogicCommand.send_to_ui_thread = None
|
||||
SystemLogicCommand.stdout_queue = None
|
||||
SystemLogicCommand.process = None
|
||||
logger.debug('send_to_ui_thread_function END')
|
||||
|
||||
if SystemLogicCommand.send_to_ui_thread is None:
|
||||
SystemLogicCommand.send_to_ui_thread = threading.Thread(target=send_to_ui_thread_function, args=())
|
||||
SystemLogicCommand.send_to_ui_thread.start()
|
||||
|
||||
@staticmethod
|
||||
def plugin_unload():
|
||||
try:
|
||||
if SystemLogicCommand.process is not None and SystemLogicCommand.process.poll() is None:
|
||||
import psutil
|
||||
process = psutil.Process(SystemLogicCommand.process.pid)
|
||||
for proc in SystemLogicCommand.process.children(recursive=True):
|
||||
proc.kill()
|
||||
SystemLogicCommand.process.kill()
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
##################################
|
||||
# 외부 호출
|
||||
@staticmethod
|
||||
def execute_command_return(command, format=None, force_log=False):
|
||||
from tool_base import ToolSubprocess
|
||||
return ToolSubprocess.execute_command_return(command, format=format, force_log=force_log)
|
||||
"""
|
||||
try:
|
||||
logger.debug('execute_command_return : %s', ' '.join(command))
|
||||
|
||||
if app.config['config']['running_type'] == 'windows':
|
||||
command = ' '.join(command)
|
||||
|
||||
process = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, encoding='utf8')
|
||||
ret = []
|
||||
with process.stdout:
|
||||
for line in iter(process.stdout.readline, ''):
|
||||
ret.append(line.strip())
|
||||
if force_log:
|
||||
logger.debug(ret[-1])
|
||||
process.wait() # wait for the subprocess to exit
|
||||
|
||||
|
||||
if format is None:
|
||||
ret2 = '\n'.join(ret)
|
||||
elif format == 'json':
|
||||
try:
|
||||
index = 0
|
||||
for idx, tmp in enumerate(ret):
|
||||
#logger.debug(tmp)
|
||||
if tmp.startswith('{') or tmp.startswith('['):
|
||||
index = idx
|
||||
break
|
||||
ret2 = json.loads(''.join(ret[index:]))
|
||||
except:
|
||||
ret2 = None
|
||||
|
||||
return ret2
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
logger.error('command : %s', command)
|
||||
"""
|
||||
|
||||
209
lib/system/logic_command2.py
Normal file
209
lib/system/logic_command2.py
Normal file
@@ -0,0 +1,209 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#########################################################
|
||||
# python
|
||||
import os
|
||||
import traceback
|
||||
import logging
|
||||
import platform
|
||||
import subprocess
|
||||
import threading
|
||||
import sys
|
||||
import io
|
||||
import time
|
||||
import json
|
||||
import queue
|
||||
# third-party
|
||||
|
||||
# sjva 공용
|
||||
|
||||
from framework import path_app_root, socketio, logger, app
|
||||
|
||||
# 패키지
|
||||
|
||||
# 로그
|
||||
package_name = __name__.split('.')[0]
|
||||
#logger = get_logger(package_name)
|
||||
#########################################################
|
||||
|
||||
class SystemLogicCommand2(object):
|
||||
instance_list = []
|
||||
|
||||
def __init__(self, title, commands, clear=True, wait=False, show_modal=True):
|
||||
self.title = title
|
||||
self.commands = commands
|
||||
self.clear = clear
|
||||
self.wait = wait
|
||||
self.show_modal = show_modal
|
||||
|
||||
self.process = None
|
||||
self.stdout_queue = None
|
||||
self.thread = None
|
||||
self.send_to_ui_thread = None
|
||||
self.return_log = []
|
||||
SystemLogicCommand2.instance_list.append(self)
|
||||
|
||||
|
||||
def start(self):
|
||||
try:
|
||||
if self.show_modal:
|
||||
if self.clear:
|
||||
socketio.emit("command_modal_clear", None, namespace='/framework', broadcast=True)
|
||||
|
||||
self.thread = threading.Thread(target=self.execute_thread_function, args=())
|
||||
self.thread.setDaemon(True)
|
||||
self.thread.start()
|
||||
if self.wait:
|
||||
time.sleep(1)
|
||||
self.thread.join()
|
||||
return self.return_log
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
def execute_thread_function(self):
|
||||
try:
|
||||
#if wait:
|
||||
if self.show_modal:
|
||||
socketio.emit("command_modal_show", self.title, namespace='/framework', broadcast=True)
|
||||
socketio.emit("loading_hide", None, namespace='/framework', broadcast=True)
|
||||
|
||||
for command in self.commands:
|
||||
if command[0] == 'msg':
|
||||
if self.show_modal:
|
||||
socketio.emit("command_modal_add_text", '%s\n\n' % command[1], namespace='/framework', broadcast=True)
|
||||
elif command[0] == 'system':
|
||||
if self.show_modal:
|
||||
socketio.emit("command_modal_add_text", '$ %s\n\n' % command[1], namespace='/framework', broadcast=True)
|
||||
os.system(command[1])
|
||||
else:
|
||||
show_command = True
|
||||
if command[0] == 'hide':
|
||||
show_command = False
|
||||
command = command[1:]
|
||||
#self.process = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, bufsize=1)
|
||||
self.process = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, encoding='utf8')
|
||||
self.start_communicate(command, show_command=show_command)
|
||||
self.send_queue_start()
|
||||
if self.process is not None:
|
||||
self.process.wait()
|
||||
time.sleep(1)
|
||||
except Exception as exception:
|
||||
if self.show_modal:
|
||||
socketio.emit("command_modal_show", self.title, namespace='/framework', broadcast=True)
|
||||
socketio.emit("command_modal_add_text", str(exception), namespace='/framework', broadcast=True)
|
||||
socketio.emit("command_modal_add_text", str(traceback.format_exc()), namespace='/framework', broadcast=True)
|
||||
|
||||
|
||||
def start_communicate(self, current_command, show_command=True):
|
||||
self.stdout_queue = queue.Queue()
|
||||
if show_command:
|
||||
self.stdout_queue.put('$ %s\n' % ' '.join(current_command))
|
||||
sout = io.open(self.process.stdout.fileno(), 'rb', closefd=False)
|
||||
#serr = io.open(process.stderr.fileno(), 'rb', closefd=False)
|
||||
|
||||
def Pump(stream):
|
||||
queue = queue.Queue()
|
||||
|
||||
def rdr():
|
||||
#logger.debug('START RDR')
|
||||
while True:
|
||||
buf = self.process.stdout.read(1)
|
||||
if buf:
|
||||
queue.put( buf )
|
||||
else:
|
||||
queue.put( None )
|
||||
break
|
||||
#logger.debug('END RDR')
|
||||
queue.put( None )
|
||||
time.sleep(1)
|
||||
|
||||
#Logic.command_close()
|
||||
def clct():
|
||||
active = True
|
||||
#logger.debug('START clct')
|
||||
while active:
|
||||
r = queue.get()
|
||||
if r is None:
|
||||
break
|
||||
try:
|
||||
while True:
|
||||
r1 = queue.get(timeout=0.005)
|
||||
if r1 is None:
|
||||
active = False
|
||||
break
|
||||
else:
|
||||
r += r1
|
||||
except:
|
||||
pass
|
||||
if r is not None:
|
||||
if app.config['config']['is_py2']:
|
||||
try:
|
||||
r = r.decode('utf-8')
|
||||
except Exception as exception:
|
||||
#logger.error('Exception:%s', e)
|
||||
#logger.error(traceback.format_exc())
|
||||
try:
|
||||
r = r.decode('cp949')
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
try:
|
||||
r = r.decode('euc-kr')
|
||||
except:
|
||||
pass
|
||||
|
||||
self.stdout_queue.put(r)
|
||||
self.return_log += r.split('\n')
|
||||
#logger.debug('IN:%s', r)
|
||||
self.stdout_queue.put('<END>')
|
||||
#logger.debug('END clct')
|
||||
#Logic.command_close()
|
||||
for tgt in [rdr, clct]:
|
||||
th = threading.Thread(target=tgt)
|
||||
th.setDaemon(True)
|
||||
th.start()
|
||||
Pump(sout)
|
||||
#Pump(serr, 'stderr')
|
||||
|
||||
def send_queue_start(self):
|
||||
def send_to_ui_thread_function():
|
||||
#logger.debug('send_queue_thread_function START')
|
||||
if self.show_modal:
|
||||
socketio.emit("command_modal_show", self.title, namespace='/framework', broadcast=True)
|
||||
while self.stdout_queue:
|
||||
line = self.stdout_queue.get()
|
||||
#logger.debug('Send to UI :%s', line)
|
||||
if line == '<END>':
|
||||
if self.show_modal:
|
||||
socketio.emit("command_modal_add_text", "\n", namespace='/framework', broadcast=True)
|
||||
break
|
||||
else:
|
||||
if self.show_modal:
|
||||
socketio.emit("command_modal_add_text", line, namespace='/framework', broadcast=True)
|
||||
self.send_to_ui_thread = None
|
||||
self.stdout_queue = None
|
||||
self.process = None
|
||||
#logger.debug('send_to_ui_thread_function END')
|
||||
|
||||
if self.send_to_ui_thread is None:
|
||||
self.send_to_ui_thread = threading.Thread(target=send_to_ui_thread_function, args=())
|
||||
self.send_to_ui_thread.start()
|
||||
|
||||
|
||||
@classmethod
|
||||
def plugin_unload(cls):
|
||||
for instance in cls.instance_list:
|
||||
try:
|
||||
if instance.process is not None and instance.process.poll() is None:
|
||||
import psutil
|
||||
process = psutil.Process(instance.process.pid)
|
||||
for proc in instance.process.children(recursive=True):
|
||||
proc.kill()
|
||||
instance.process.kill()
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
finally:
|
||||
try: instance.process.kill()
|
||||
except: pass
|
||||
129
lib/system/logic_env.py
Normal file
129
lib/system/logic_env.py
Normal file
@@ -0,0 +1,129 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#########################################################
|
||||
# python
|
||||
import os
|
||||
import traceback
|
||||
import logging
|
||||
import platform
|
||||
import time
|
||||
import threading
|
||||
|
||||
# third-party
|
||||
from flask import Blueprint, request, Response, send_file, render_template, redirect, jsonify
|
||||
|
||||
|
||||
# sjva 공용
|
||||
|
||||
from framework import F, path_app_root, path_data, celery, app
|
||||
|
||||
# 패키지
|
||||
from .plugin import logger, package_name
|
||||
from .model import ModelSetting
|
||||
|
||||
class SystemLogicEnv(object):
|
||||
@staticmethod
|
||||
def load_export():
|
||||
try:
|
||||
from support.base.file import SupportFile
|
||||
f = os.path.join(path_app_root, 'export.sh')
|
||||
if os.path.exists(f):
|
||||
return SupportFile.read_file(f)
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
@staticmethod
|
||||
def process_ajax(sub, req):
|
||||
ret = False
|
||||
try:
|
||||
if sub == 'setting_save':
|
||||
data = req.form['export']
|
||||
#logger.debug(data)
|
||||
data = data.replace("\r\n", "\n" ).replace( "\r", "\n" )
|
||||
ret = False
|
||||
if platform.system() != 'Windows':
|
||||
f = os.path.join(path_app_root, 'export.sh')
|
||||
with open(f, 'w') as f:
|
||||
f.write(data)
|
||||
#os.system("dos2unix export.sh")
|
||||
ret = True
|
||||
elif sub == 'ps':
|
||||
def func():
|
||||
import system
|
||||
commands = [
|
||||
['msg', u'잠시만 기다려주세요.'],
|
||||
['ps', '-ef'],
|
||||
['top', '-n1']
|
||||
]
|
||||
#commands.append(['msg', u'설치가 완료되었습니다.'])
|
||||
system.SystemLogicCommand.start('ps', commands)
|
||||
t = threading.Thread(target=func, args=())
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
elif sub == 'celery_test':
|
||||
ret = SystemLogicEnv.celery_test()
|
||||
elif sub == 'worker_start':
|
||||
os.system('sh worker_start.sh &')
|
||||
"""
|
||||
def func():
|
||||
import system
|
||||
commands = [
|
||||
['msg', u'잠시만 기다려주세요.'],
|
||||
['sh', 'worker_start.sh'],
|
||||
]
|
||||
#commands.append(['msg', u'설치가 완료되었습니다.'])
|
||||
system.SystemLogicCommand.start('ps', commands)
|
||||
t = threading.Thread(target=func, args=())
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
"""
|
||||
ret = True
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
return jsonify(ret)
|
||||
|
||||
|
||||
|
||||
@staticmethod
|
||||
def celery_test():
|
||||
if F.config['use_celery']:
|
||||
from celery import Celery
|
||||
from celery.exceptions import TimeoutError, NotRegistered
|
||||
|
||||
data = {}
|
||||
try:
|
||||
result = SystemLogicEnv.celery_test2.apply_async()
|
||||
logger.debug(result)
|
||||
try:
|
||||
tmp = result.get(timeout=5, propagate=True)
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
#result = SystemLogicEnv.celery_test2.delay()
|
||||
data['ret'] = 'success'
|
||||
data['data'] = tmp
|
||||
except TimeoutError:
|
||||
data['ret'] = 'timeout'
|
||||
data['data'] = u'celery가 동작중이 아니거나 모든 프로세스가 작업중입니다.'
|
||||
except NotRegistered:
|
||||
data['ret'] = 'not_registered'
|
||||
data['data'] = u'Not Registered'
|
||||
#logger.debug(data)
|
||||
else:
|
||||
data['ret'] = 'no_celery'
|
||||
data['data'] = u'celery 실행환경이 아닙니다.'
|
||||
return data
|
||||
|
||||
@staticmethod
|
||||
@celery.task
|
||||
def celery_test2():
|
||||
try:
|
||||
logger.debug('!!!! celery_test2222')
|
||||
import time
|
||||
time.sleep(1)
|
||||
data = u'정상입니다. 이 메시지는 celery 에서 반환됩니다. '
|
||||
return data
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
40
lib/system/logic_notify.py
Normal file
40
lib/system/logic_notify.py
Normal file
@@ -0,0 +1,40 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#########################################################
|
||||
# python
|
||||
import os
|
||||
import traceback
|
||||
import logging
|
||||
import platform
|
||||
import time
|
||||
|
||||
# third-party
|
||||
from flask import Blueprint, request, Response, send_file, render_template, redirect, jsonify
|
||||
|
||||
|
||||
# sjva 공용
|
||||
|
||||
from framework import path_app_root, path_data
|
||||
from tool_base import ToolBaseNotify
|
||||
# 패키지
|
||||
from .plugin import logger, package_name
|
||||
from .model import ModelSetting
|
||||
|
||||
|
||||
class SystemLogicNotify(object):
|
||||
@staticmethod
|
||||
def process_ajax(sub, req):
|
||||
try:
|
||||
if sub == 'telegram_test':
|
||||
ret = ToolBaseNotify.send_telegram_message(req.form['text'], bot_token=req.form['bot_token'], chat_id=req.form['chat_id'])
|
||||
return jsonify(ret)
|
||||
elif sub == 'discord_test':
|
||||
ret = ToolBaseNotify.send_discord_message(req.form['text'], webhook_url=req.form['url'])
|
||||
return jsonify(ret)
|
||||
elif sub == 'advanced_test':
|
||||
ret = ToolBaseNotify.send_advanced_message(req.form['text'], policy=req.form['policy'], message_id=req.form['message_id'])
|
||||
return jsonify(ret)
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
return jsonify('exception')
|
||||
|
||||
290
lib/system/logic_plugin.py
Normal file
290
lib/system/logic_plugin.py
Normal file
@@ -0,0 +1,290 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#########################################################
|
||||
# python
|
||||
import os
|
||||
import traceback
|
||||
import logging
|
||||
import json
|
||||
import zipfile
|
||||
import time
|
||||
import platform
|
||||
# third-party
|
||||
import requests
|
||||
|
||||
|
||||
# sjva 공용
|
||||
from framework import frame, app, path_data, logger
|
||||
from framework.util import Util
|
||||
from support.base.process import SupportProcess
|
||||
|
||||
# 패키지
|
||||
from .model import ModelSetting
|
||||
import system
|
||||
|
||||
|
||||
|
||||
class LogicPlugin(object):
|
||||
plugin_loading = False
|
||||
|
||||
|
||||
|
||||
current_loading_plugin_list = {}
|
||||
|
||||
"""
|
||||
custom_plugin_list = []
|
||||
@staticmethod
|
||||
def loading():
|
||||
try:
|
||||
custom_path = os.path.join(path_data, 'custom')
|
||||
plugin_list = os.listdir(custom_path)
|
||||
logger.debug(plugin_list)
|
||||
for name in plugin_list:
|
||||
try:
|
||||
p = {}
|
||||
p['name'] = name
|
||||
p['plugin_name'] = name
|
||||
mod = __import__('%s' % (p['plugin_name']), fromlist=[])
|
||||
p['local_info'] = getattr(mod, 'plugin_info')
|
||||
p['status'] = 'latest'
|
||||
LogicPlugin.custom_plugin_list.append(p)
|
||||
except Exception as exception:
|
||||
logger.error('NO Exception:%s', exception)
|
||||
logger.debug('plunin not import : %s', p['plugin_name'])
|
||||
p['local_info'] = None
|
||||
p['status'] = 'no'
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def get_plugin_list():
|
||||
return LogicPlugin.current_loading_plugin_list
|
||||
"""
|
||||
try:
|
||||
if not LogicPlugin.plugin_loading:
|
||||
LogicPlugin.loading()
|
||||
LogicPlugin.plugin_loading = True
|
||||
return LogicPlugin.custom_plugin_list
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
"""
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_plugin_info(plugin_name):
|
||||
try:
|
||||
lists = LogicPlugin.get_plugin_list()
|
||||
for key, value in lists.items():
|
||||
if key == plugin_name:
|
||||
return value['info']
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
"""
|
||||
@staticmethod
|
||||
def plugin_install(plugin_name):
|
||||
logger.debug('plugin_name : %s', plugin_name)
|
||||
try:
|
||||
plugin_info = LogicPlugin.get_plugin_info(plugin_name)
|
||||
|
||||
custom_path = os.path.join(path_data, 'custom')
|
||||
|
||||
if 'platform' in plugin_info:
|
||||
if platform.system() not in plugin_info['platform']:
|
||||
return 'not_support_os'
|
||||
if 'running_type' in plugin_info:
|
||||
if app.config['config']['running_type'] not in plugin_info['running_type']:
|
||||
return 'not_support_running_type'
|
||||
git_clone_flag = True
|
||||
if git_clone_flag:
|
||||
# git clone
|
||||
command = ['git', '-C', custom_path, 'clone', plugin_info['git'], '--depth', '1']
|
||||
ret = Util.execute_command(command)
|
||||
return 'success'
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def plugin_uninstall(plugin_name):
|
||||
logger.debug('plugin_name : %s', plugin_name)
|
||||
try:
|
||||
mod = __import__('%s' % (plugin_name), fromlist=[])
|
||||
mod_plugin_unload = getattr(mod, 'plugin_unload')
|
||||
mod_plugin_unload()
|
||||
time.sleep(1)
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
try:
|
||||
custom_path = os.path.join(path_data, 'custom')
|
||||
plugin_path = os.path.join(custom_path, plugin_name)
|
||||
if os.path.exists(plugin_path):
|
||||
try:
|
||||
import framework.common.celery as celery_task
|
||||
celery_task.rmtree(plugin_path)
|
||||
except Exception as exception:
|
||||
try:
|
||||
logger.debug('plugin_uninstall')
|
||||
os.system('rmdir /S /Q "%s"' % plugin_path)
|
||||
except:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
if os.path.exists(plugin_path):
|
||||
return 'fail'
|
||||
else:
|
||||
return 'success'
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
@staticmethod
|
||||
def custom_plugin_update():
|
||||
try:
|
||||
if os.environ.get('UPDATE_STOP') == 'true':
|
||||
return
|
||||
if os.environ.get('PLUGIN_UPDATE_FROM_PYTHON') == 'false':
|
||||
return
|
||||
if frame.config['debug'] == True:
|
||||
return
|
||||
if frame.config['plugin_update'] != True:
|
||||
return
|
||||
|
||||
custom_path = os.path.join(path_data, 'plugins')
|
||||
tmps = os.listdir(custom_path)
|
||||
for t in tmps:
|
||||
plugin_path = os.path.join(custom_path, t)
|
||||
try:
|
||||
if t == 'torrent_info':
|
||||
os.remove(os.path.join(plugin_path, 'info.json'))
|
||||
except:
|
||||
pass
|
||||
if t.startswith('_'):
|
||||
continue
|
||||
if os.path.exists(os.path.join(plugin_path, '.git')):
|
||||
command = ['git', '-C', plugin_path, 'reset', '--hard', 'HEAD']
|
||||
ret = SupportProcess.execute(command)
|
||||
command = ['git', '-C', plugin_path, 'pull']
|
||||
ret = SupportProcess.execute(command)
|
||||
logger.debug("%s\n%s", plugin_path, ret)
|
||||
else:
|
||||
logger.debug(f"plugin_path is not git repo")
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
@staticmethod
|
||||
def plugin_install_by_api(plugin_git, zip_url, zip_filename):
|
||||
logger.debug('plugin_git : %s', plugin_git)
|
||||
logger.debug('zip_url : %s', zip_url)
|
||||
logger.debug('zip_filename : %s', zip_filename)
|
||||
|
||||
is_git = True if plugin_git != None and plugin_git != '' else False
|
||||
ret = {}
|
||||
try:
|
||||
if is_git:
|
||||
name = plugin_git.split('/')[-1]
|
||||
else:
|
||||
name = zip_filename.split('.')[0]
|
||||
|
||||
custom_path = os.path.join(path_data, 'custom')
|
||||
plugin_path = os.path.join(custom_path, name)
|
||||
logger.debug(plugin_path)
|
||||
plugin_info = None
|
||||
if os.path.exists(plugin_path):
|
||||
ret['ret'] = 'already_exist'
|
||||
ret['log'] = '이미 설치되어 있습니다.'
|
||||
else:
|
||||
if plugin_git and plugin_git.startswith('http'):
|
||||
for tag in ['main', 'master']:
|
||||
try:
|
||||
info_url = plugin_git.replace('github.com', 'raw.githubusercontent.com') + '/%s/info.json' % tag
|
||||
plugin_info = requests.get(info_url).json()
|
||||
if plugin_info is not None:
|
||||
break
|
||||
except:
|
||||
pass
|
||||
if zip_filename and zip_filename != '':
|
||||
import zipfile
|
||||
from tool_base import ToolBaseFile
|
||||
zip_filepath = os.path.join(path_data, 'tmp', zip_filename)
|
||||
extract_filepath = os.path.join(path_data, 'tmp', name)
|
||||
logger.error(zip_url)
|
||||
logger.warning(zip_filepath)
|
||||
if ToolBaseFile.download(zip_url, zip_filepath):
|
||||
#logger.warning(os.path.exists(zip_filepath))
|
||||
with zipfile.ZipFile(zip_filepath, 'r') as zip_ref:
|
||||
zip_ref.extractall(extract_filepath)
|
||||
plugin_info_filepath = os.path.join(extract_filepath, 'info.json')
|
||||
if os.path.exists(plugin_info_filepath):
|
||||
plugin_info = ToolBaseFile.read_json(plugin_info_filepath)
|
||||
if plugin_info == None:
|
||||
plugin_info = {}
|
||||
flag = True
|
||||
if 'platform' in plugin_info:
|
||||
if platform.system() not in plugin_info['platform']:
|
||||
ret['ret'] = 'not_support_os'
|
||||
ret['log'] = '설치 가능한 OS가 아닙니다.'
|
||||
flag = False
|
||||
if flag and 'running_type' in plugin_info:
|
||||
if app.config['config']['running_type'] not in plugin_info['running_type']:
|
||||
ret['ret'] = 'not_support_running_type'
|
||||
ret['log'] = '설치 가능한 실행타입이 아닙니다.'
|
||||
flag = False
|
||||
if flag and 'policy_level' in plugin_info:
|
||||
if plugin_info['policy_level'] > app.config['config']['level']:
|
||||
ret['ret'] = 'policy_level'
|
||||
ret['log'] = '설치 가능 회원등급보다 낮습니다.'
|
||||
flag = False
|
||||
if flag and 'policy_point' in plugin_info:
|
||||
if plugin_info['policy_level'] > app.config['config']['point']:
|
||||
ret['ret'] = 'policy_level'
|
||||
ret['log'] = '설치 가능 포인트보다 낮습니다.'
|
||||
flag = False
|
||||
|
||||
if flag:
|
||||
if plugin_git and plugin_git.startswith('http'):
|
||||
command = ['git', '-C', custom_path, 'clone', plugin_git + '.git', '--depth', '1']
|
||||
log = Util.execute_command(command)
|
||||
if zip_filename and zip_filename != '':
|
||||
import shutil
|
||||
if os.path.exists(plugin_path) == False:
|
||||
shutil.move(extract_filepath, plugin_path)
|
||||
else:
|
||||
for tmp in os.listdir(extract_filepath):
|
||||
shutil.move(os.path.join(extract_filepath, tmp), plugin_path)
|
||||
log = ''
|
||||
logger.debug(plugin_info)
|
||||
# 2021-12-31
|
||||
if 'dependency' in plugin_info:
|
||||
for dep in plugin_info['dependency']:
|
||||
for key, value in LogicPlugin.get_plugin_list().items():
|
||||
if key == dep['name']:
|
||||
logger.debug(f"Dependency 설치 - 이미 설치됨 : {dep['name']}")
|
||||
break
|
||||
else:
|
||||
logger.debug(f"Dependency 설치 : {dep['home']}")
|
||||
LogicPlugin.plugin_install_by_api(dep['home'], dep.get('zip_url'), dep.get('zip_filename'))
|
||||
#command = ['git', '-C', custom_path, 'clone', dep['home'], '--depth', '1']
|
||||
#ret = Util.execute_command(command)
|
||||
ret['ret'] = 'success'
|
||||
ret['log'] = [u'정상적으로 설치하였습니다. 재시작시 적용됩니다.', log]
|
||||
ret['log'] = '<br>'.join(ret['log'])
|
||||
|
||||
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
ret['ret'] = 'exception'
|
||||
ret['log'] = str(exception)
|
||||
|
||||
|
||||
return ret
|
||||
|
||||
397
lib/system/logic_selenium.py
Normal file
397
lib/system/logic_selenium.py
Normal file
@@ -0,0 +1,397 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#########################################################
|
||||
# python
|
||||
import os
|
||||
import traceback
|
||||
import logging
|
||||
import platform
|
||||
import time
|
||||
import base64
|
||||
|
||||
# third-party
|
||||
from flask import Blueprint, request, Response, send_file, render_template, redirect, jsonify
|
||||
|
||||
try:
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from PIL import Image
|
||||
Image.MAX_IMAGE_PIXELS = None
|
||||
except:
|
||||
pass
|
||||
from io import BytesIO
|
||||
|
||||
# sjva 공용
|
||||
|
||||
from framework import path_app_root, path_data
|
||||
|
||||
# 패키지
|
||||
from .plugin import logger, package_name
|
||||
from .model import ModelSetting
|
||||
|
||||
#########################################################
|
||||
#apk --no-cache add --repository http://dl-cdn.alpinelinux.org/alpine/edge/testing firefox
|
||||
#https://github.com/mozilla/geckodriver/releases/download/v0.26.0/geckodriver-v0.26.0-linux64.tar.gz
|
||||
#curl -s -L "$url" | tar -xz
|
||||
|
||||
class SystemLogicSelenium(object):
|
||||
chrome_driver = None
|
||||
chrome_driver_list = []
|
||||
|
||||
@staticmethod
|
||||
def process_ajax(sub, req):
|
||||
try:
|
||||
if sub == 'selenium_test_go':
|
||||
driver = SystemLogicSelenium.get_driver()
|
||||
driver.get(req.form['url'])
|
||||
return jsonify('success')
|
||||
elif sub == 'capture':
|
||||
driver = SystemLogicSelenium.get_driver()
|
||||
img = Image.open(BytesIO((driver.get_screenshot_as_png())))
|
||||
|
||||
timestamp = time.time()
|
||||
timestamp = str(timestamp).split('.')[0]
|
||||
tmp = os.path.join(path_data, 'tmp', '%s.png' % timestamp)
|
||||
img.save(tmp)
|
||||
from system.model import ModelSetting as SystemModelSetting
|
||||
ddns = SystemModelSetting.get('ddns')
|
||||
url = '%s/open_file%s' % (ddns, tmp)
|
||||
logger.debug(url)
|
||||
ret = {}
|
||||
ret['ret'] = 'success'
|
||||
ret['data'] = url
|
||||
return jsonify(ret)
|
||||
elif sub == 'full_capture':
|
||||
driver = SystemLogicSelenium.get_driver()
|
||||
img = SystemLogicSelenium.full_screenshot(driver)
|
||||
|
||||
timestamp = time.time()
|
||||
timestamp = str(timestamp).split('.')[0]
|
||||
tmp = os.path.join(path_data, 'tmp', '%s.png' % timestamp)
|
||||
img.save(tmp)
|
||||
return send_file(tmp, mimetype='image/png')
|
||||
elif sub == 'cookie':
|
||||
driver = SystemLogicSelenium.get_driver()
|
||||
data = driver.get_cookies()
|
||||
return jsonify(data)
|
||||
elif sub == 'daum_capcha':
|
||||
daum_capcha = req.form['daum_capcha']
|
||||
driver = SystemLogicSelenium.get_driver()
|
||||
#driver.find_element_by_xpath('//div[@class="secret_viewer"]/p/img').screenshot("captcha.png")
|
||||
driver.find_element_by_xpath('//input[@id="answer"]').send_keys(daum_capcha)
|
||||
driver.find_element_by_xpath('//input[@value="%s"]' % u'확인').click()
|
||||
return jsonify({'ret':'success'})
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
return jsonify('exception')
|
||||
|
||||
@staticmethod
|
||||
def get_pagesoruce_by_selenium(url, wait_xpath, retry=True):
|
||||
try:
|
||||
logger.debug('get_pagesoruce_by_selenium:%s %s', url, wait_xpath)
|
||||
driver = SystemLogicSelenium.get_driver()
|
||||
#logger.debug('driver : %s', driver)
|
||||
driver.get(url)
|
||||
|
||||
WebDriverWait(driver, 10).until(lambda driver: driver.find_element_by_xpath(wait_xpath))
|
||||
#import time
|
||||
#driver.save_screenshot('%s.png' % time.time())
|
||||
#logger.debug('return page_source')
|
||||
return driver.page_source
|
||||
except Exception as exception:
|
||||
#logger.debug(driver.page_source)
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
SystemLogicSelenium.close_driver()
|
||||
#SystemLogicSelenium.chrome_driver = None
|
||||
if retry:
|
||||
return SystemLogicSelenium.get_pagesoruce_by_selenium(url, wait_xpath, retry=False)
|
||||
|
||||
# 1회성
|
||||
@staticmethod
|
||||
def get_driver(chrome_options=None):
|
||||
try:
|
||||
if SystemLogicSelenium.chrome_driver is None:
|
||||
SystemLogicSelenium.chrome_driver = SystemLogicSelenium.inner_create_driver(chrome_options)
|
||||
return SystemLogicSelenium.chrome_driver
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
# 플러그인이 점유
|
||||
@staticmethod
|
||||
def create_driver(chrome_options=None):
|
||||
try:
|
||||
driver = SystemLogicSelenium.inner_create_driver(chrome_options)
|
||||
if driver is not None:
|
||||
SystemLogicSelenium.chrome_driver_list.append(driver)
|
||||
return driver
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
@staticmethod
|
||||
def close_driver():
|
||||
try:
|
||||
#if SystemLogicSelenium.chrome_driver is not None:
|
||||
# SystemLogicSelenium.chrome_driver.quit()
|
||||
# SystemLogicSelenium.chrome_driver = None
|
||||
if SystemLogicSelenium.chrome_driver is not None:
|
||||
try: SystemLogicSelenium.chrome_driver.close()
|
||||
except: pass
|
||||
time.sleep(2)
|
||||
try: SystemLogicSelenium.chrome_driver.quit()
|
||||
except: pass
|
||||
SystemLogicSelenium.chrome_driver = None
|
||||
|
||||
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
@staticmethod
|
||||
def inner_create_driver(chrome_options):
|
||||
try:
|
||||
driver = None
|
||||
remote_url = ModelSetting.get('selenium_remote_url')
|
||||
if remote_url.endswith('/wd/hub/'):
|
||||
remote_url = remote_url[:-1]
|
||||
if remote_url != '':
|
||||
if chrome_options is None:
|
||||
chrome_options = webdriver.ChromeOptions()
|
||||
tmp = ModelSetting.get_list('selenium_remote_default_option')
|
||||
for t in tmp:
|
||||
chrome_options.add_argument(t)
|
||||
driver = webdriver.Remote(command_executor=remote_url, desired_capabilities=chrome_options.to_capabilities())
|
||||
driver.set_window_size(1920, 1080)
|
||||
logger.debug('Using Remote :%s', driver)
|
||||
else:
|
||||
path_chrome = os.path.join(path_app_root, 'bin', platform.system(), 'chromedriver')
|
||||
if platform.system() == 'Windows':
|
||||
path_chrome += '.exe'
|
||||
if chrome_options is None:
|
||||
chrome_options = webdriver.ChromeOptions()
|
||||
tmp = ModelSetting.get_list('selenium_binary_default_option')
|
||||
for t in tmp:
|
||||
chrome_options.add_argument(t)
|
||||
driver = webdriver.Chrome(path_chrome, chrome_options=chrome_options)
|
||||
logger.debug('Using local bin :%s', driver)
|
||||
if driver is not None:
|
||||
return driver
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
@staticmethod
|
||||
def plugin_unload():
|
||||
try:
|
||||
SystemLogicSelenium.close_driver()
|
||||
#logger.debug(SystemLogicSelenium.chrome_driver)
|
||||
#if SystemLogicSelenium.chrome_driver is not None:
|
||||
# SystemLogicSelenium.chrome_driver.quit()
|
||||
# logger.debug(SystemLogicSelenium.chrome_driver)
|
||||
|
||||
for tmp in SystemLogicSelenium.chrome_driver_list:
|
||||
if tmp is not None:
|
||||
tmp.quit()
|
||||
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
@staticmethod
|
||||
def get_text_excluding_children(driver, element):
|
||||
return driver.execute_script("""
|
||||
return jQuery(arguments[0]).contents().filter(function() {
|
||||
return this.nodeType == Node.TEXT_NODE;
|
||||
}).text();
|
||||
""", element)
|
||||
|
||||
@staticmethod
|
||||
def full_screenshot(driver, low_offset = 0):
|
||||
try:
|
||||
# initiate value
|
||||
#save_path = save_path + '.png' if save_path[-4::] != '.png' else save_path
|
||||
img_li = [] # to store image fragment
|
||||
offset = 0 # where to start
|
||||
|
||||
# js to get height
|
||||
height = driver.execute_script('return Math.max('
|
||||
'document.documentElement.clientHeight, window.innerHeight);')
|
||||
#height = height - low_offset
|
||||
# js to get the maximum scroll height
|
||||
# Ref--> https://stackoverflow.com/questions/17688595/finding-the-maximum-scroll-position-of-a-page
|
||||
max_window_height = driver.execute_script('return Math.max('
|
||||
'document.body.scrollHeight, '
|
||||
'document.body.offsetHeight, '
|
||||
'document.documentElement.clientHeight, '
|
||||
'document.documentElement.scrollHeight, '
|
||||
'document.documentElement.offsetHeight);')
|
||||
|
||||
# looping from top to bottom, append to img list
|
||||
# Ref--> https://gist.github.com/fabtho/13e4a2e7cfbfde671b8fa81bbe9359fb
|
||||
|
||||
while offset < max_window_height:
|
||||
|
||||
# Scroll to height
|
||||
driver.execute_script("""
|
||||
window.scrollTo(0, arguments[0]);
|
||||
""", offset)
|
||||
img = Image.open(BytesIO((driver.get_screenshot_as_png())))
|
||||
|
||||
if low_offset != 0:
|
||||
img = img.crop((0, 0, img.width, img.height-low_offset)) # defines crop points
|
||||
|
||||
img_li.append(img)
|
||||
offset += height
|
||||
logger.debug('offset : %s / %s', offset, max_window_height)
|
||||
|
||||
# Stitch image into one
|
||||
# Set up the full screen frame
|
||||
img_frame_height = sum([img_frag.size[1] for img_frag in img_li])
|
||||
img_frame = Image.new('RGB', (img_li[0].size[0], img_frame_height))
|
||||
offset = 0
|
||||
for img_frag in img_li:
|
||||
img_frame.paste(img_frag, (0, offset))
|
||||
offset += img_frag.size[1]
|
||||
logger.debug('paste offset : %s ', offset)
|
||||
#img_frame.save(save_path)
|
||||
#return
|
||||
return img_frame
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
@staticmethod
|
||||
def remove_element(driver, element):
|
||||
driver.execute_script("""
|
||||
var element = arguments[0];
|
||||
element.parentNode.removeChild(element);
|
||||
""", element)
|
||||
|
||||
|
||||
|
||||
######################################################################
|
||||
@staticmethod
|
||||
def __get_downloaded_files(driver=None):
|
||||
if driver is None:
|
||||
driver = SystemLogicSelenium.get_driver()
|
||||
if not driver.current_url.startswith("chrome://downloads"):
|
||||
driver.get("chrome://downloads/")
|
||||
#driver.implicitly_wait(4)
|
||||
return driver.execute_script( \
|
||||
"return downloads.Manager.get().items_ "
|
||||
" .filter(e => e.state === 'COMPLETE') "
|
||||
" .map(e => e.filePath || e.file_path); " )
|
||||
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_file_content(path, driver=None):
|
||||
if driver is None:
|
||||
driver = SystemLogicSelenium.get_driver()
|
||||
|
||||
elem = driver.execute_script( \
|
||||
"var input = window.document.createElement('INPUT'); "
|
||||
"input.setAttribute('type', 'file'); "
|
||||
"input.hidden = true; "
|
||||
"input.onchange = function (e) { e.stopPropagation() }; "
|
||||
"return window.document.documentElement.appendChild(input); " )
|
||||
|
||||
elem._execute('sendKeysToElement', {'value': [ path ], 'text': path})
|
||||
|
||||
result = driver.execute_async_script( \
|
||||
"var input = arguments[0], callback = arguments[1]; "
|
||||
"var reader = new FileReader(); "
|
||||
"reader.onload = function (ev) { callback(reader.result) }; "
|
||||
"reader.onerror = function (ex) { callback(ex.message) }; "
|
||||
"reader.readAsDataURL(input.files[0]); "
|
||||
"input.remove(); "
|
||||
, elem)
|
||||
|
||||
if not result.startswith('data:') :
|
||||
raise Exception("Failed to get file content: %s" % result)
|
||||
|
||||
return base64.b64decode(result[result.find('base64,') + 7:])
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_downloaded_files(driver=None):
|
||||
if driver is None:
|
||||
driver = SystemLogicSelenium.get_driver()
|
||||
|
||||
#files = WebDriverWait(driver, 20, 1).until(SystemLogicSelenium.__get_downloaded_files)
|
||||
files = SystemLogicSelenium.__get_downloaded_files()
|
||||
return files
|
||||
|
||||
@staticmethod
|
||||
def waitUntilDownloadCompleted(maxTime=600, driver=None):
|
||||
if driver is None:
|
||||
driver = SystemLogicSelenium.get_driver()
|
||||
driver.execute_script("window.open()")
|
||||
# switch to new tab
|
||||
driver.switch_to.window(driver.window_handles[-1])
|
||||
# navigate to chrome downloads
|
||||
driver.get('chrome://downloads')
|
||||
# define the endTime
|
||||
endTime = time.time() + maxTime
|
||||
while True:
|
||||
try:
|
||||
# get the download percentage
|
||||
downloadPercentage = driver.execute_script(
|
||||
"return document.querySelector('downloads-manager').shadowRoot.querySelector('#downloadsList downloads-item').shadowRoot.querySelector('#progress').value")
|
||||
# check if downloadPercentage is 100 (otherwise the script will keep waiting)
|
||||
if downloadPercentage == 100:
|
||||
# exit the method once it's completed
|
||||
return downloadPercentage
|
||||
except:
|
||||
pass
|
||||
# wait for 1 second before checking the percentage next time
|
||||
time.sleep(1)
|
||||
# exit method if the download not completed with in MaxTime.
|
||||
if time.time() > endTime:
|
||||
break
|
||||
|
||||
"""
|
||||
|
||||
|
||||
driver = webdriver.Chrome(desired_capabilities=capabilities_chrome)
|
||||
#driver = webdriver.Remote('http://127.0.0.1:5555/wd/hub', capabilities_chrome)
|
||||
|
||||
# download a pdf file
|
||||
driver.get("https://www.mozilla.org/en-US/foundation/documents")
|
||||
driver.find_element_by_css_selector("[href$='.pdf']").click()
|
||||
|
||||
# list all the completed remote files (waits for at least one)
|
||||
files = WebDriverWait(driver, 20, 1).until(get_downloaded_files)
|
||||
|
||||
# get the content of the first file remotely
|
||||
content = get_file_content(driver, files[0])
|
||||
|
||||
# save the content in a local file in the working directory
|
||||
with open(os.path.basename(files[0]), 'wb') as f:
|
||||
f.write(content)
|
||||
|
||||
|
||||
capabilities_chrome = { \
|
||||
'browserName': 'chrome',
|
||||
# 'proxy': { \
|
||||
# 'proxyType': 'manual',
|
||||
# 'sslProxy': '50.59.162.78:8088',
|
||||
# 'httpProxy': '50.59.162.78:8088'
|
||||
# },
|
||||
'goog:chromeOptions': { \
|
||||
'args': [
|
||||
],
|
||||
'prefs': { \
|
||||
# 'download.default_directory': "",
|
||||
# 'download.directory_upgrade': True,
|
||||
'download.prompt_for_download': False,
|
||||
'plugins.always_open_pdf_externally': True,
|
||||
'safebrowsing_for_trusted_sources_enabled': False
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
233
lib/system/logic_site.py
Normal file
233
lib/system/logic_site.py
Normal file
@@ -0,0 +1,233 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#########################################################
|
||||
# python
|
||||
import os
|
||||
import traceback
|
||||
import logging
|
||||
import platform
|
||||
import time
|
||||
|
||||
# third-party
|
||||
from flask import Blueprint, request, Response, send_file, render_template, redirect, jsonify
|
||||
|
||||
|
||||
|
||||
from framework import F, path_app_root, path_data, socketio, scheduler
|
||||
from tool_base import d
|
||||
|
||||
|
||||
# 패키지
|
||||
from .plugin import logger, package_name
|
||||
from .model import ModelSetting
|
||||
|
||||
|
||||
class SystemLogicSite(object):
|
||||
# 매번 split 하기 머해서
|
||||
daum_cookie = None
|
||||
|
||||
@staticmethod
|
||||
def process_ajax(sub, req):
|
||||
try:
|
||||
ret = {}
|
||||
if sub == 'site_daum_test':
|
||||
site_daum_test = req.form['site_daum_test']
|
||||
ModelSetting.set('site_daum_test', site_daum_test)
|
||||
from framework.common.daum import DaumTV, MovieSearch
|
||||
ret['TV'] = DaumTV.get_daum_tv_info(site_daum_test)
|
||||
if ret['TV'] is not None and 'episode_list' in ret['TV']:
|
||||
del ret['TV']['episode_list']
|
||||
ret['MOVIE'] = MovieSearch.search_movie(site_daum_test, -1)
|
||||
return jsonify(ret)
|
||||
elif sub == 'site_daum_cookie_refresh':
|
||||
ret = SystemLogicSite.get_daum_cookie_by_selenium(notify=True)
|
||||
return jsonify(ret)
|
||||
elif sub == 'scheduler':
|
||||
go = req.form['scheduler']
|
||||
if go == 'true':
|
||||
SystemLogicSite.scheduler_start()
|
||||
else:
|
||||
SystemLogicSite.scheduler_stop()
|
||||
return jsonify(go)
|
||||
elif sub == 'tving_login':
|
||||
try:
|
||||
from support.site.tving import SupportTving
|
||||
token = SupportTving().do_login(req.form['tving_id'], req.form['tving_pw'], req.form['tving_login_type'])
|
||||
if token is None:
|
||||
ret['ret'] = False
|
||||
else:
|
||||
ret['ret'] = True
|
||||
ret['token'] = token
|
||||
return jsonify(ret)
|
||||
except Exception as e:
|
||||
logger.error('Exception:%s', e)
|
||||
logger.error(traceback.format_exc())
|
||||
elif sub == 'tving_deviceid':
|
||||
try:
|
||||
from support.site.tving import SupportTving
|
||||
device_list = SupportTving(token=req.form['tving_token']).get_device_list()
|
||||
if device_list is None:
|
||||
ret['ret'] = False
|
||||
else:
|
||||
ret['ret'] = True
|
||||
ret['device_list'] = device_list
|
||||
return jsonify(ret)
|
||||
except Exception as e:
|
||||
logger.error('Exception:%s', e)
|
||||
logger.error(traceback.format_exc())
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
ret['ret'] = False
|
||||
ret['log'] = str(traceback.format_exc())
|
||||
return jsonify(ret)
|
||||
|
||||
@staticmethod
|
||||
def process_api(sub, req):
|
||||
ret = {}
|
||||
try:
|
||||
if sub == 'daum_cookie':
|
||||
return ModelSetting.get('site_daum_cookie')
|
||||
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
ret['ret'] = 'exception'
|
||||
ret['data'] = str(exception)
|
||||
return jsonify(ret)
|
||||
##########################################################################
|
||||
|
||||
@staticmethod
|
||||
def plugin_load():
|
||||
SystemLogicSite.create_tving_instance()
|
||||
return
|
||||
SystemLogicSite.get_daum_cookies(force=True)
|
||||
if ModelSetting.get_bool('site_daum_auto_start'):
|
||||
SystemLogicSite.scheduler_start()
|
||||
|
||||
@staticmethod
|
||||
def create_tving_instance():
|
||||
from support.site.tving import SupportTving
|
||||
proxy = None
|
||||
if ModelSetting.get_bool('site_tving_use_proxy'):
|
||||
proxy = ModelSetting.get('site_tving_proxy_url')
|
||||
SupportTving.ins = SupportTving(token=ModelSetting.get('site_tving_token'), proxy=proxy, deviceid=ModelSetting.get('site_tving_deviceid'), uuid=ModelSetting.get('site_tving_uuid'))
|
||||
|
||||
|
||||
|
||||
@staticmethod
|
||||
def scheduler_start():
|
||||
job = Job(package_name, '%s_site' % package_name, ModelSetting.get('site_daum_interval'), SystemLogicSite.scheduler_function, u"Daum cookie refresh", False)
|
||||
scheduler.add_job_instance(job)
|
||||
|
||||
@staticmethod
|
||||
def scheduler_stop():
|
||||
scheduler.remove_job('%s_site' % package_name)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def scheduler_function():
|
||||
try:
|
||||
data = SystemLogicSite.get_daum_cookie_by_selenium()
|
||||
if data['ret']:
|
||||
ModelSetting.set('site_daum_cookie', data['data'])
|
||||
SystemLogicSite.get_daum_cookies(force=True)
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_daum_cookie_by_selenium(notify=False):
|
||||
try:
|
||||
ret = {}
|
||||
ret['ret'] = False
|
||||
from .logic_selenium import SystemLogicSelenium
|
||||
if notify:
|
||||
data = {'type':'success', 'msg' : u'<strong>사이트 접속중입니다.</strong>'}
|
||||
socketio.emit("notify", data, namespace='/framework', broadcast=True)
|
||||
SystemLogicSelenium.get_pagesoruce_by_selenium('https://www.daum.net', '//*[@id="daumFoot"]/div/a[1]/img')
|
||||
if notify:
|
||||
data = {'type':'success', 'msg' : u'쿠키 확인'}
|
||||
socketio.emit("notify", data, namespace='/framework', broadcast=True)
|
||||
driver = SystemLogicSelenium.get_driver()
|
||||
cookies = driver.get_cookies()
|
||||
for tmp in cookies:
|
||||
if tmp['name'] == 'TIARA':
|
||||
ret['ret'] = True
|
||||
ret['data'] = 'TIARA=%s' % tmp['value']
|
||||
return ret
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
return ret
|
||||
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_daum_cookies(force=False):
|
||||
try:
|
||||
if SystemLogicSite.daum_cookie is None or force:
|
||||
ret = {}
|
||||
tmp = ModelSetting.get('site_daum_cookie')
|
||||
tmps = tmp.split(';')
|
||||
for t in tmps:
|
||||
t2 = t.split('=')
|
||||
if len(t2) == 2:
|
||||
ret[t2[0]] = t2[1]
|
||||
SystemLogicSite.daum_cookie = ret
|
||||
return SystemLogicSite.daum_cookie
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
return {'TIARA':'gaXEIPluo-wWAFlwZN6l8gN3yzhkoo_piP.Kymhuy.6QBt4Q6.cRtxbKDaWpWajcyteRHzrlTVpJRxLjwLoMvyYLVi_7xJ1L'}
|
||||
|
||||
|
||||
daum_headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36',
|
||||
'Accept' : 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
|
||||
'Accept-Language' : 'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7',
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def get_tree_daum(cls, url, post_data=None):
|
||||
from lxml import html
|
||||
from framework import SystemModelSetting
|
||||
text = cls.get_text_daum(url, post_data=post_data)
|
||||
if text is None:
|
||||
return
|
||||
return html.fromstring(text)
|
||||
|
||||
@classmethod
|
||||
def get_text_daum(cls, url, post_data=None):
|
||||
from system.logic_site import SystemLogicSite
|
||||
from framework import SystemModelSetting
|
||||
res = cls.get_response(url, proxy_url=SystemModelSetting.get('site_daum_proxy'), headers=SystemLogicSite.daum_headers, post_data=post_data, cookies=SystemLogicSite.get_daum_cookies())
|
||||
return res.text
|
||||
|
||||
|
||||
@classmethod
|
||||
def get_response_daum(cls, url, post_data=None):
|
||||
from system.logic_site import SystemLogicSite
|
||||
from framework import SystemModelSetting
|
||||
res = cls.get_response(url, proxy_url=SystemModelSetting.get('site_daum_proxy'), headers=SystemLogicSite.daum_headers, post_data=post_data, cookies=SystemLogicSite.get_daum_cookies())
|
||||
return res
|
||||
|
||||
|
||||
@classmethod
|
||||
def get_response(cls, url, proxy_url=None, headers=None, post_data=None, cookies=None):
|
||||
import requests
|
||||
proxies = None
|
||||
if proxy_url is not None and proxy_url != '':
|
||||
proxies = {"http" : proxy_url, "https" : proxy_url}
|
||||
if headers is None:
|
||||
headers = SystemLogicSite.default_headers
|
||||
if post_data is None:
|
||||
#logger.warning(d(headers))
|
||||
#logger.warning(d(proxies))
|
||||
#logger.warning(d(cookies))
|
||||
|
||||
res = requests.get(url, headers=headers, proxies=proxies, cookies=cookies)
|
||||
else:
|
||||
res = requests.post(url, headers=headers, proxies=proxies, data=post_data, cookies=cookies)
|
||||
return res
|
||||
78
lib/system/logic_telegram_bot.py
Normal file
78
lib/system/logic_telegram_bot.py
Normal file
@@ -0,0 +1,78 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#########################################################
|
||||
# python
|
||||
import os
|
||||
import traceback
|
||||
import logging
|
||||
import platform
|
||||
import time
|
||||
|
||||
# third-party
|
||||
from flask import Blueprint, request, Response, send_file, render_template, redirect, jsonify
|
||||
|
||||
|
||||
|
||||
from framework import F, frame, app, path_app_root, path_data, scheduler
|
||||
from tool_base import ToolBaseNotify
|
||||
# 패키지
|
||||
from .plugin import logger, package_name
|
||||
from .model import ModelSetting
|
||||
|
||||
|
||||
class SystemLogicTelegramBot(object):
|
||||
@staticmethod
|
||||
def process_ajax(sub, req):
|
||||
try:
|
||||
if sub == 'telegram_test':
|
||||
ret = ToolBaseNotify.send_telegram_message(req.form['text'], bot_token=req.form['bot_token'], chat_id=req.form['chat_id'])
|
||||
return jsonify(ret)
|
||||
elif sub == 'discord_test':
|
||||
ret = ToolBaseNotify.send_discord_message(req.form['text'], webhook_url=req.form['url'])
|
||||
return jsonify(ret)
|
||||
elif sub == 'advanced_test':
|
||||
ret = ToolBaseNotify.send_advanced_message(req.form['text'], policy=req.form['policy'], message_id=req.form['message_id'])
|
||||
return jsonify(ret)
|
||||
elif sub == 'scheduler':
|
||||
go = request.form['scheduler']
|
||||
logger.debug('scheduler :%s', go)
|
||||
if go == 'true':
|
||||
SystemLogicTelegramBot.scheduler_start()
|
||||
else:
|
||||
SystemLogicTelegramBot.scheduler_stop()
|
||||
return jsonify(go)
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
return jsonify('exception')
|
||||
|
||||
@staticmethod
|
||||
def plugin_load():
|
||||
try:
|
||||
if frame.config['run_celery']:
|
||||
return
|
||||
|
||||
if ModelSetting.get_bool('telegram_bot_auto_start'):
|
||||
SystemLogicTelegramBot.scheduler_start()
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
@staticmethod
|
||||
def scheduler_start():
|
||||
try:
|
||||
interval = 60*24
|
||||
job = Job(package_name, '%s_telegram_bot' % (package_name), 9999, SystemLogicTelegramBot.scheduler_function, u"시스템 - 텔레그램 봇", False)
|
||||
scheduler.add_job_instance(job)
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
@staticmethod
|
||||
def scheduler_function():
|
||||
try:
|
||||
bot_token = ModelSetting.get('telegram_bot_token')
|
||||
from framework.common.telegram_bot import TelegramBot
|
||||
TelegramBot.start(bot_token)
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
62
lib/system/logic_terminal.py
Normal file
62
lib/system/logic_terminal.py
Normal file
@@ -0,0 +1,62 @@
|
||||
try:
|
||||
import yaml
|
||||
a = yaml.FullLoader
|
||||
except:
|
||||
from framework import app
|
||||
import os
|
||||
try: os.system(f"{app.config['config']['pip']} install --upgrade pyyaml")
|
||||
except: pass
|
||||
|
||||
import os, sys, traceback, json
|
||||
from framework import path_data
|
||||
from flask import request, render_template, redirect, jsonify
|
||||
from .plugin import logger
|
||||
|
||||
|
||||
class SystemLogicTerminal(object):
|
||||
yaml_path = os.path.join(path_data, 'db', 'terminal.yaml')
|
||||
|
||||
@classmethod
|
||||
def process_ajax(cls, sub, req):
|
||||
logger.error(sub)
|
||||
logger.error(req)
|
||||
try:
|
||||
if sub == 'get_info':
|
||||
ret = cls.get_info()
|
||||
elif sub == 'run':
|
||||
data = cls.get_info()
|
||||
idx = int(req.form['index'])
|
||||
from terminal.logic_terminal import LogicTerminal
|
||||
LogicTerminal.wait_input(data['commands'][idx]['command'])
|
||||
return jsonify({'ret':'success'})
|
||||
return jsonify(ret)
|
||||
except Exception as e:
|
||||
logger.error(f'Exception: {str(e)}')
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
@classmethod
|
||||
def get_info(cls):
|
||||
if os.path.exists(cls.yaml_path) == False:
|
||||
with open(cls.yaml_path, 'w', encoding='utf8') as f:
|
||||
f.write(yaml_templete)
|
||||
with open(cls.yaml_path, 'r', encoding='utf8') as f:
|
||||
info = yaml.load(f, Loader=yaml.FullLoader)
|
||||
return info
|
||||
|
||||
|
||||
|
||||
|
||||
yaml_templete = '''
|
||||
|
||||
commands:
|
||||
- title: SJVA 데이터 폴더별 크기 확인
|
||||
command: |
|
||||
cd ./data
|
||||
du -h -d 1
|
||||
|
||||
- title: SJVA 도커 재시작
|
||||
command: |
|
||||
ssh -i MY.pem ubuntu@172.17.0.1
|
||||
sudo docker restart sjva
|
||||
|
||||
'''
|
||||
52
lib/system/logic_tool_crypt.py
Normal file
52
lib/system/logic_tool_crypt.py
Normal file
@@ -0,0 +1,52 @@
|
||||
import traceback
|
||||
from flask import jsonify
|
||||
from framework import app
|
||||
|
||||
# 패키지
|
||||
from .plugin import package_name, logger
|
||||
from .model import ModelSetting
|
||||
|
||||
class SystemLogicToolDecrypt(object):
|
||||
@staticmethod
|
||||
def process_ajax(sub, req):
|
||||
try:
|
||||
if sub == 'crypt_test':
|
||||
ret = SystemLogicToolDecrypt.crypt_test(req)
|
||||
return jsonify(ret)
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
##########################################################################
|
||||
|
||||
@staticmethod
|
||||
def crypt_test(req):
|
||||
try:
|
||||
mode = req.form['mode']
|
||||
word = req.form['word']
|
||||
|
||||
logger.debug(mode)
|
||||
logger.debug(word)
|
||||
from tool_base import ToolAESCipher
|
||||
mykey = None
|
||||
if ModelSetting.get_bool('tool_crypt_use_user_key'):
|
||||
mykey = ModelSetting.get('tool_crypt_user_key').lower().zfill(32)
|
||||
if app.config['config']['is_py2']:
|
||||
mykey = mykey.encode('utf8')
|
||||
if len(mykey) > 32:
|
||||
mykey = mykey[:32]
|
||||
logger.debug(mykey)
|
||||
|
||||
if mode == 'encrypt':
|
||||
ModelSetting.set('tool_crypt_encrypt_word', u'%s' % word)
|
||||
ret = {'ret':'success', 'data':ToolAESCipher.encrypt(word, mykey=mykey)}
|
||||
elif mode == 'decrypt':
|
||||
ModelSetting.set('tool_crypt_decrypt_word', u'%s' % word)
|
||||
ret = {'ret':'success', 'data':ToolAESCipher.decrypt(word, mykey=mykey).decode()}
|
||||
|
||||
logger.debug(ret)
|
||||
return ret
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
return {'ret':'exception', 'data':str(exception)}
|
||||
117
lib/system/mod_home.py
Normal file
117
lib/system/mod_home.py
Normal file
@@ -0,0 +1,117 @@
|
||||
from .setup import *
|
||||
import platform
|
||||
from support.base.util import SupportUtil
|
||||
name = 'home'
|
||||
|
||||
class ModuleHome(PluginModuleBase):
|
||||
info_thread = None
|
||||
|
||||
def __init__(self, P):
|
||||
super(ModuleHome, self).__init__(P, name=name)
|
||||
default_route_socketio_module(self)
|
||||
|
||||
def process_menu(self, page, req):
|
||||
return render_template(f'{__package__}_{name}.html', info=self.get_info('static'))
|
||||
|
||||
def process_command(self, command, arg1, arg2, arg3, req):
|
||||
if command == 'recent_version':
|
||||
result = F.get_recent_version()
|
||||
if result:
|
||||
#F.config['recent_version'] = '4.0.0'
|
||||
ret = {'msg': f"최신버전 : {F.config['recent_version']}", 'type':'success'}
|
||||
else:
|
||||
ret = {'msg': f"확인 실패", 'type':'warning'}
|
||||
return jsonify(ret)
|
||||
elif command == 'get_config':
|
||||
data = {}
|
||||
for key, value in F.app.config.items():
|
||||
data[key] = str(value)
|
||||
ret = {'json':{'Framework':F.config, 'Flask':data}}
|
||||
return jsonify(ret)
|
||||
|
||||
|
||||
def socketio_connect(self):
|
||||
self.send_info()
|
||||
if self.info_thread != None:
|
||||
return
|
||||
|
||||
def func():
|
||||
while True:
|
||||
if len(self.socketio_list) == 0:
|
||||
break
|
||||
self.send_info()
|
||||
time.sleep(1)
|
||||
self.info_thread = None
|
||||
|
||||
self.info_thread = threading.Thread(target=func, args=())
|
||||
self.info_thread.daemon = True
|
||||
self.info_thread.start()
|
||||
|
||||
def send_info(self):
|
||||
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)
|
||||
|
||||
|
||||
def get_info(self, mode=''):
|
||||
info = {}
|
||||
if mode == 'static':
|
||||
info['platform'] = platform.platform()
|
||||
info['processor'] = platform.processor()
|
||||
|
||||
info['python_version'] = sys.version
|
||||
info['version'] = VERSION
|
||||
info['recent_version'] = F.config['recent_version']
|
||||
info['path_app'] = F.config['path_app']
|
||||
info['path_data'] = F.config['path_data']
|
||||
info['path_working'] = F.config['path_working']
|
||||
info['config_filepath'] = F.config['config_filepath']
|
||||
info['running_type'] = F.config['running_type']
|
||||
info['use_celery'] = '사용' if F.config['use_celery'] else '미사용'
|
||||
else:
|
||||
info['version'] = VERSION
|
||||
info['recent_version'] = F.config['recent_version']
|
||||
#info['auth'] = frame.config['member']['auth_desc']
|
||||
info['cpu_percent'] = 'not supported'
|
||||
info['memory'] = 'not supported'
|
||||
info['disk'] = 'not supported'
|
||||
if frame.config['running_type'] != 'termux':
|
||||
try:
|
||||
import psutil
|
||||
info['cpu_percent'] = '%s %%' % psutil.cpu_percent()
|
||||
tmp = psutil.virtual_memory()
|
||||
info['memory'] = [
|
||||
SupportUtil.sizeof_fmt(tmp[0], suffix='B'),
|
||||
SupportUtil.sizeof_fmt(tmp[3], suffix='B'),
|
||||
SupportUtil.sizeof_fmt(tmp[1], suffix='B'),
|
||||
tmp[2]
|
||||
]
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
if platform.system() == 'Windows':
|
||||
s = os.path.splitdrive(path_app_root)
|
||||
root = s[0]
|
||||
else:
|
||||
root = '/'
|
||||
tmp = psutil.disk_usage(root)
|
||||
info['disk'] = [
|
||||
SupportUtil.sizeof_fmt(tmp[0], suffix='B'),
|
||||
SupportUtil.sizeof_fmt(tmp[1], suffix='B'),
|
||||
SupportUtil.sizeof_fmt(tmp[2], suffix='B'),
|
||||
tmp[3], root]
|
||||
except Exception as exception:
|
||||
pass
|
||||
try:
|
||||
system_start_time = SystemModelSetting.get('system_start_time')
|
||||
timedelta = datetime.now() - datetime.strptime(system_start_time, '%Y-%m-%d %H:%M:%S')
|
||||
info['time'] = [
|
||||
system_start_time,
|
||||
str(timedelta).split('.')[0],
|
||||
F.config['arg_repeat']
|
||||
]
|
||||
except Exception as exception:
|
||||
info['time'] = str(exception)
|
||||
return info
|
||||
77
lib/system/mod_route.py
Normal file
77
lib/system/mod_route.py
Normal file
@@ -0,0 +1,77 @@
|
||||
import random, string
|
||||
|
||||
from .setup import *
|
||||
from flask_login import login_user, current_user, logout_user
|
||||
|
||||
name = 'route'
|
||||
|
||||
|
||||
class ModuleRoute(PluginModuleBase):
|
||||
def __init__(self, P):
|
||||
super(ModuleRoute, self).__init__(P, name=name)
|
||||
self.route()
|
||||
|
||||
# 일반적인 routing에서는 login_required 때문에 /system/login으로 redirect 됨.
|
||||
def route(self):
|
||||
@P.blueprint.route('/login', methods=['GET', 'POST'])
|
||||
def login():
|
||||
if F.SystemModelSetting.get_bool('use_login') == False:
|
||||
username = F.SystemModelSetting.get('web_id')
|
||||
F.users[username].authenticated = True
|
||||
login_user(frame.users[username], remember=True)
|
||||
#current_user = USERS[username]
|
||||
return redirect(request.args.get("next"))
|
||||
return render_template(f'system_login.html', next=request.args.get("next"))
|
||||
|
||||
@P.blueprint.route('/ajax/login/<cmd>', methods=['POST'])
|
||||
def command(cmd):
|
||||
if cmd == 'command':
|
||||
return self.process_command(request.form['command'], request.form.get('arg1'), request.form.get('arg2'), request.form.get('arg3'), request)
|
||||
|
||||
@P.blueprint.route('/logout', methods=['GET'])
|
||||
def logout():
|
||||
current_user.authenticated = False
|
||||
logout_user()
|
||||
return redirect('/')
|
||||
|
||||
@F.login_manager.user_loader
|
||||
def user_loader(user_id):
|
||||
return F.users[user_id]
|
||||
|
||||
|
||||
@P.blueprint.route('/restart', methods=['GET'])
|
||||
@login_required
|
||||
def restart():
|
||||
F.restart()
|
||||
return render_template('system_restart.html',sub='restart', referer=request.headers.get("Referer"))
|
||||
|
||||
@P.blueprint.route('/shutdown', methods=['GET'])
|
||||
@login_required
|
||||
def shutdown():
|
||||
F.shutdown()
|
||||
return render_template('system_restart.html',sub='shutdown', referer=request.headers.get("Referer"))
|
||||
|
||||
|
||||
@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)
|
||||
|
||||
|
||||
def process_menu(self, page, req):
|
||||
return render_template('sample.html', title=f"{__package__}/{name}/{page}")
|
||||
#return render_template(f'{__package__}_{name}.html', arg={})
|
||||
|
||||
def process_command(self, command, arg1, arg2, arg3, req):
|
||||
if command == 'login':
|
||||
username = arg1
|
||||
password = arg2
|
||||
remember = (arg3 == 'true')
|
||||
if username not in frame.users:
|
||||
return jsonify('no_id')
|
||||
elif not F.users[username].can_login(password):
|
||||
return jsonify('wrong_password')
|
||||
else:
|
||||
F.users[username].authenticated = True
|
||||
login_user(frame.users[username], remember=remember)
|
||||
return jsonify('redirect')
|
||||
|
||||
91
lib/system/mod_setting.py
Normal file
91
lib/system/mod_setting.py
Normal file
@@ -0,0 +1,91 @@
|
||||
import random, string
|
||||
|
||||
from .setup import *
|
||||
|
||||
name = 'setting'
|
||||
|
||||
class ModuleSetting(PluginModuleBase):
|
||||
db_default = {
|
||||
'db_version' : '1',
|
||||
'port' : '9999',
|
||||
'ddns' : 'http://localhost:9999',
|
||||
'use_login' : 'False',
|
||||
'web_id': 'admin',
|
||||
'web_pw': 'Vm51JgZqhpwXc/UPc9CAN1lhj4s65+4ikv7GzNmvN6c=',
|
||||
'web_title': 'Home',
|
||||
'use_apikey': 'False',
|
||||
'apikey': ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(10)),
|
||||
|
||||
f'restart_interval': f'{random.randint(0,59)} {random.randint(1,23)} * * *',
|
||||
|
||||
'theme' : 'Cerulean',
|
||||
'log_level' : '20',
|
||||
'plugin_dev_path': os.path.join(F.config['path_data'], 'dev'),
|
||||
|
||||
'system_start_time': '',
|
||||
}
|
||||
|
||||
def __init__(self, P):
|
||||
super(ModuleSetting, self).__init__(P, name=name, first_menu='basic')
|
||||
|
||||
|
||||
def process_menu(self, page, req):
|
||||
arg = P.ModelSetting.to_dict()
|
||||
try:
|
||||
return render_template(f'{__package__}_{name}_{page}.html', arg=arg)
|
||||
except Exception as e:
|
||||
P.logger.error(f'Exception:{str(e)}')
|
||||
P.logger.error(traceback.format_exc())
|
||||
return render_template('sample.html', title=f"{__package__}/{name}/{page}")
|
||||
|
||||
def process_command(self, command, arg1, arg2, arg3, req):
|
||||
if command == 'apikey_generate':
|
||||
return jsonify(''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(10)))
|
||||
|
||||
|
||||
def plugin_load(self):
|
||||
try:
|
||||
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']))
|
||||
username = SystemModelSetting.get('web_id')
|
||||
passwd = SystemModelSetting.get('web_pw')
|
||||
F.users[username] = User(username, passwd_hash=passwd)
|
||||
|
||||
self.__set_restart_scheduler()
|
||||
self.__set_scheduler_check_scheduler()
|
||||
F.get_recent_version()
|
||||
except Exception as e:
|
||||
P.logger.error(f'Exception:{str(e)}')
|
||||
P.logger.error(traceback.format_exc())
|
||||
|
||||
def setting_save_after(self, change_list):
|
||||
if 'theme' in change_list:
|
||||
F.socketio.emit("refresh", {}, namespace='/framework', broadcast=True)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def __set_restart_scheduler(self):
|
||||
name = f'{__package__}_restart'
|
||||
if F.scheduler.is_include(name):
|
||||
F.scheduler.remove_job(name)
|
||||
interval = SystemModelSetting.get('restart_interval')
|
||||
if interval != '0':
|
||||
if len(interval.split(' ')) == 1:
|
||||
interval = '%s' % (int(interval) * 60)
|
||||
job_instance = Job(__package__, name, interval, F.restart, "자동 재시작")
|
||||
F.scheduler.add_job_instance(job_instance, run=False)
|
||||
|
||||
|
||||
def __set_scheduler_check_scheduler(self):
|
||||
name = 'scheduler_check'
|
||||
if F.scheduler.is_include(name):
|
||||
F.scheduler.remove_job(name)
|
||||
|
||||
job_instance = Job(__package__, name, 2, F.scheduler.first_run_check_thread_function, "Scheduler Check")
|
||||
scheduler.add_job_instance(job_instance, run=False)
|
||||
|
||||
|
||||
|
||||
8
lib/system/model.py
Normal file
8
lib/system/model.py
Normal file
@@ -0,0 +1,8 @@
|
||||
import traceback
|
||||
from framework import db, get_logger
|
||||
from framework.util import Util
|
||||
|
||||
logger = get_logger(__package__)
|
||||
|
||||
from plugin.model_setting import get_model_setting
|
||||
ModelSetting = get_model_setting(__package__, logger)
|
||||
541
lib/system/plugin.py
Normal file
541
lib/system/plugin.py
Normal file
@@ -0,0 +1,541 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#########################################################
|
||||
# python
|
||||
import os, platform
|
||||
import traceback
|
||||
import logging
|
||||
import threading
|
||||
import time
|
||||
import json
|
||||
|
||||
# third-party
|
||||
import requests
|
||||
from flask import Blueprint, request, Response, send_file, render_template, redirect, jsonify, stream_with_context
|
||||
|
||||
# sjva 공용
|
||||
from framework import frame, app, scheduler, socketio, check_api, path_app_root, path_data, get_logger#, celery
|
||||
from support.base.util import SingletonClass
|
||||
from flask_login import login_required
|
||||
|
||||
# 로그
|
||||
package_name = __name__.split('.')[0]
|
||||
logger = get_logger(__package__)
|
||||
|
||||
# 패키지
|
||||
from .logic import SystemLogic
|
||||
from .model import ModelSetting
|
||||
from .logic_plugin import LogicPlugin
|
||||
from .logic_selenium import SystemLogicSelenium
|
||||
from .logic_command import SystemLogicCommand
|
||||
from .logic_command2 import SystemLogicCommand2
|
||||
from .logic_notify import SystemLogicNotify
|
||||
from .logic_telegram_bot import SystemLogicTelegramBot
|
||||
from .logic_auth import SystemLogicAuth
|
||||
from .logic_tool_crypt import SystemLogicToolDecrypt
|
||||
from .logic_terminal import SystemLogicTerminal
|
||||
# celery 때문에 import
|
||||
from .logic_env import SystemLogicEnv
|
||||
from .logic_site import SystemLogicSite
|
||||
|
||||
#########################################################
|
||||
|
||||
|
||||
#########################################################
|
||||
# 플러그인 공용
|
||||
#########################################################
|
||||
blueprint = Blueprint(package_name, package_name, url_prefix='/%s' % package_name, template_folder='templates')
|
||||
|
||||
menu = {
|
||||
'uri' : package_name,
|
||||
'name': '설정',
|
||||
'list': [
|
||||
{
|
||||
'uri': 'setting',
|
||||
'name': '일반설정',
|
||||
'list': [
|
||||
{'uri': 'basic', 'name': '기본'},
|
||||
{'uri': 'auth', 'name': '인증'},
|
||||
{'uri': 'env', 'name': '시스템'},
|
||||
{'uri': 'notify', 'name': '알림'},
|
||||
{'uri': 'telegram_bot', 'name': '텔레그램 봇'},
|
||||
{'uri': 'selenium', 'name': 'Selenium'},
|
||||
{'uri': 'site', 'name': 'Site'},
|
||||
{'uri': 'memo', 'name': '메모'},
|
||||
{'uri': 'terminal', 'name': 'Terminal'},
|
||||
],
|
||||
},
|
||||
{
|
||||
'uri': 'plugin',
|
||||
'name': '플러그인'
|
||||
},
|
||||
{
|
||||
'uri': 'tool',
|
||||
'name': 'Tool',
|
||||
'list': [{'uri': 'crypt', 'name': '암호화'}]
|
||||
},
|
||||
{
|
||||
'uri': 'log',
|
||||
'name': '로그'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if platform.system() == 'Windows':
|
||||
# del menu['sub2']['setting'][-1]
|
||||
|
||||
|
||||
def plugin_load():
|
||||
logger.debug('plugin_load:%s', package_name)
|
||||
SystemLogic.plugin_load()
|
||||
SystemLogicTelegramBot.plugin_load()
|
||||
SystemLogicSite.plugin_load()
|
||||
|
||||
def plugin_unload():
|
||||
logger.debug('plugin_load:%s', package_name)
|
||||
SystemLogicSelenium.plugin_unload()
|
||||
SystemLogicCommand.plugin_unload()
|
||||
SystemLogicCommand2.plugin_unload()
|
||||
|
||||
|
||||
#########################################################
|
||||
# WEB Menu
|
||||
#########################################################
|
||||
@blueprint.route('/')
|
||||
def normal():
|
||||
return redirect('/%s/setting' % package_name)
|
||||
|
||||
@login_required
|
||||
def home():
|
||||
return render_template('info.html', arg=None)
|
||||
|
||||
@blueprint.route('/<sub>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def first_menu(sub):
|
||||
#logger.debug('System SUB:%s', sub)
|
||||
arg = None
|
||||
if sub == 'home':
|
||||
return render_template('%s_%s.html' % (package_name, sub), arg=None)
|
||||
elif sub == 'setting':
|
||||
return redirect('/%s/%s/basic' % (package_name, sub))
|
||||
elif sub == 'tool':
|
||||
return redirect('/%s/%s/crypt' % (package_name, sub))
|
||||
elif sub == 'plugin':
|
||||
arg = ModelSetting.to_dict()
|
||||
arg['install'] = request.args.get('install', '')
|
||||
if arg['install'] == 'flaskfilemanager':
|
||||
arg['install'] = 'https://github.com/soju6jan/' + arg['install']
|
||||
try:
|
||||
import flaskfilemanager
|
||||
arg['install'] = ''
|
||||
except:
|
||||
pass
|
||||
elif arg['install'] == 'flaskcode':
|
||||
arg['install'] = 'https://github.com/soju6jan/' + arg['install']
|
||||
try:
|
||||
import flaskcode
|
||||
arg['install'] = ''
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
return render_template('system_plugin.html', arg=arg)
|
||||
elif sub == 'information':
|
||||
return render_template('manual.html', sub=sub, arg='system.json')
|
||||
elif sub == 'log':
|
||||
log_files=os.listdir(os.path.join(path_data, 'log'))
|
||||
log_files.sort()
|
||||
log_list = []
|
||||
arg = {'package_name' : package_name, 'sub' : sub}
|
||||
for x in log_files:
|
||||
if x.endswith('.log'):
|
||||
log_list.append(x)
|
||||
arg['log_list'] = '|'.join(log_list)
|
||||
arg['all_list'] = '|'.join(log_files)
|
||||
arg['filename'] = ''
|
||||
if 'filename' in request.form:
|
||||
arg['filename'] = request.form['filename']
|
||||
logger.debug(arg)
|
||||
return render_template('%s_%s.html' % (package_name, sub), arg=arg)
|
||||
elif sub == 'restart':
|
||||
restart()
|
||||
return render_template('system_restart.html', sub=sub, referer=request.headers.get("Referer"))
|
||||
elif sub == 'shutdown':
|
||||
shutdown()
|
||||
return render_template('system_restart.html', sub=sub, referer=request.headers.get("Referer"))
|
||||
elif sub == 'telegram':
|
||||
return redirect('/%s/%s/setting' % (package_name, sub))
|
||||
return render_template('sample.html', title='%s - %s' % (package_name, sub))
|
||||
|
||||
|
||||
@blueprint.route('/<sub>/<sub2>')
|
||||
@login_required
|
||||
def second_menu(sub, sub2):
|
||||
try:
|
||||
if sub == 'setting':
|
||||
arg = ModelSetting.to_dict()
|
||||
arg['sub'] = sub2
|
||||
if sub2 == 'basic':
|
||||
arg['point'] = SystemLogic.point
|
||||
return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg)
|
||||
elif sub2 in ['trans', 'selenium', 'notify']:
|
||||
return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg)
|
||||
elif sub2 == 'auth':
|
||||
arg['auth_result'] = SystemLogicAuth.get_auth_status()
|
||||
return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg)
|
||||
elif sub2 == 'telegram_bot':
|
||||
arg['scheduler'] = str(scheduler.is_include('%s_%s' % (package_name, sub2)))
|
||||
arg['is_running'] = str(scheduler.is_running('%s_%s' % (package_name, sub2)))
|
||||
return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg)
|
||||
elif sub2 == 'env':
|
||||
arg['export'] = SystemLogicEnv.load_export()
|
||||
if arg['export'] is None:
|
||||
arg['export'] = u'export.sh 파일이 없습니다.'
|
||||
return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg)
|
||||
elif sub2 == 'site':
|
||||
arg['scheduler'] = str(scheduler.is_include('%s_%s' % (package_name, sub2)))
|
||||
arg['is_running'] = str(scheduler.is_running('%s_%s' % (package_name, sub2)))
|
||||
from system.model import ModelSetting as SystemModelSetting
|
||||
arg['site_get_daum_cookie_url'] = '{ddns}/{package_name}/api/{sub2}/daum_cookie'.format(ddns=SystemModelSetting.get('ddns'), package_name=package_name, sub2=sub2)
|
||||
if SystemModelSetting.get_bool('auth_use_apikey'):
|
||||
arg['site_get_daum_cookie_url'] += '?apikey={apikey}'.format(apikey=SystemModelSetting.get('auth_apikey'))
|
||||
return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg)
|
||||
elif sub2 == 'memo':
|
||||
return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg)
|
||||
elif sub2 == 'terminal':
|
||||
arg['yaml_path'] = SystemLogicTerminal.yaml_path.replace(path_app_root, '')
|
||||
return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg)
|
||||
elif sub == 'tool':
|
||||
arg = ModelSetting.to_dict()
|
||||
arg['sub'] = sub2
|
||||
if sub2 == 'crypt':
|
||||
return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg)
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#########################################################
|
||||
# For UI
|
||||
#########################################################
|
||||
@blueprint.route('/ajax/<sub>/<sub2>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def second_ajax(sub, sub2):
|
||||
logger.debug('System AJAX sub:%s', sub)
|
||||
try:
|
||||
if sub == 'auth':
|
||||
from .logic_auth import SystemLogicAuth
|
||||
return SystemLogicAuth.process_ajax(sub2, request)
|
||||
elif sub == 'selenium':
|
||||
return SystemLogicSelenium.process_ajax(sub2, request)
|
||||
elif sub == 'notify':
|
||||
return SystemLogicNotify.process_ajax(sub2, request)
|
||||
elif sub == 'telegram_bot':
|
||||
return SystemLogicTelegramBot.process_ajax(sub2, request)
|
||||
elif sub == 'env':
|
||||
return SystemLogicEnv.process_ajax(sub2, request)
|
||||
elif sub == 'site':
|
||||
return SystemLogicSite.process_ajax(sub2, request)
|
||||
elif sub == 'crypt':
|
||||
return SystemLogicToolDecrypt.process_ajax(sub2, request)
|
||||
elif sub == 'terminal':
|
||||
return SystemLogicTerminal.process_ajax(sub2, request)
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
|
||||
@blueprint.route('/ajax/<sub>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def ajax(sub):
|
||||
#logger.debug('System AJAX sub:%s', sub)
|
||||
try:
|
||||
if sub == 'info':
|
||||
try:
|
||||
ret = {}
|
||||
ret['system'] = SystemLogic.get_info()
|
||||
ret['scheduler'] = scheduler.get_job_list_info()
|
||||
|
||||
#logger.debug(ret)
|
||||
return jsonify(ret)
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
return jsonify()
|
||||
elif sub == 'setting_save_system':
|
||||
try:
|
||||
ret = SystemLogic.setting_save_system(request)
|
||||
return jsonify(ret)
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
elif sub == 'setting_save':
|
||||
ret = ModelSetting.setting_save(request)
|
||||
SystemLogic.setting_save_after()
|
||||
return jsonify(ret)
|
||||
elif sub == 'ddns_test':
|
||||
try:
|
||||
url = request.form['ddns'] + '/version'
|
||||
res = requests.get(url)
|
||||
data = res.text
|
||||
#data = res.json()
|
||||
#logger.debug(data)
|
||||
return jsonify(data)
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
return jsonify('fail')
|
||||
elif sub == 'celery_test':
|
||||
try:
|
||||
#result = add_together.delay(10, 20)
|
||||
#print(result.wait())
|
||||
#return 'Welcome to my app!'
|
||||
try:
|
||||
import framework
|
||||
framework.exit_code = 1
|
||||
socketio.stop()
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
#os.environ['SJVA_REPEAT_TYPE'] = 'update'
|
||||
|
||||
|
||||
return jsonify()
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
elif sub == 'command_run':
|
||||
try:
|
||||
command_text = request.form['command_text']
|
||||
ret = SystemLogic.command_run(command_text)
|
||||
return jsonify(ret)
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
elif sub == 'get_link_list':
|
||||
try:
|
||||
link_json = SystemLogic.get_setting_value('link_json')
|
||||
j = json.loads(link_json)
|
||||
return jsonify(j)
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
elif sub == 'link_save':
|
||||
try:
|
||||
link_data_str = request.form['link_data']
|
||||
#j = json.loads(link_data)
|
||||
ret = SystemLogic.link_save(link_data_str)
|
||||
return jsonify(ret)
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
elif sub == 'plugin_list':
|
||||
try:
|
||||
return jsonify(LogicPlugin.get_plugin_list())
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
elif sub == 'plugin_install':
|
||||
try:
|
||||
#plugin_name = request.form['plugin_name']
|
||||
plugin_git = request.form['plugin_git']
|
||||
return jsonify(LogicPlugin.plugin_install_by_api(plugin_git, request.form.get('zip_url'), request.form.get('zip_filename')))
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
elif sub == 'plugin_uninstall':
|
||||
try:
|
||||
plugin_name = request.form['plugin_name']
|
||||
return jsonify(LogicPlugin.plugin_uninstall(plugin_name))
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
elif sub == 'recent_version':
|
||||
ret = SystemLogic.get_recent_version()
|
||||
ret = {'ret':ret, 'version':SystemLogic.recent_version}
|
||||
return jsonify(ret)
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
|
||||
@socketio.on('connect', namespace='/%s' % package_name)
|
||||
def connect():
|
||||
try:
|
||||
InfoProcess.instance().connect(request.sid)
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
@socketio.on('disconnect', namespace='/%s' % package_name)
|
||||
def disconnect():
|
||||
try:
|
||||
InfoProcess.instance().disconnect(request.sid)
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
@socketio.on('connect', namespace='/system_restart')
|
||||
def connect_system_restart():
|
||||
try:
|
||||
socketio.emit("on_connect", 'restart', namespace='/system_restart', broadcast=True)
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
@socketio.on('disconnect', namespace='/system_restart')
|
||||
def disconnect_system_restart():
|
||||
try:
|
||||
pass
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
|
||||
|
||||
#########################################################
|
||||
# API
|
||||
#########################################################
|
||||
|
||||
@blueprint.route('/api/<sub>', methods=['GET', 'POST'])
|
||||
@check_api
|
||||
def first_api(sub):
|
||||
try:
|
||||
if sub == 'plugin_add':
|
||||
plugin_git = request.form['plugin_git']
|
||||
from system.logic_plugin import LogicPlugin
|
||||
ret = LogicPlugin.plugin_install_by_api(plugin_git, request.form.get('zip_url'), request.form.get('zip_filename'))
|
||||
return jsonify(ret)
|
||||
elif sub == 'restart':
|
||||
logger.debug('web restart')
|
||||
import system
|
||||
system.restart()
|
||||
return jsonify({'ret':'success'})
|
||||
elif sub == 'gds':
|
||||
url = f"{app.config['DEFINE']['WEB_DIRECT_URL']}/sjva/gds2.php?type=file&id={request.args.get('id')}&user_id={ModelSetting.get('sjva_me_user_id')}&user_apikey={ModelSetting.get('auth_apikey')}"
|
||||
data = requests.get(url).json()['data']
|
||||
logger.debug(data)
|
||||
req_headers = dict(request.headers)
|
||||
headers = {}
|
||||
|
||||
if 'Range' not in req_headers or req_headers['Range'].startswith('bytes=0-'):
|
||||
headers['Range'] = "bytes=0-1048576"
|
||||
else:
|
||||
headers['Range'] = req_headers['Range']
|
||||
headers['Authorization'] = f"Bearer {data['token']}"
|
||||
headers['Connection'] = 'keep-alive'
|
||||
|
||||
r = requests.get(data['url'], headers=headers, stream=True)
|
||||
rv = Response(r.iter_content(chunk_size=1048576), r.status_code, content_type=r.headers['Content-Type'], direct_passthrough=True)
|
||||
rv.headers.add('Content-Range', r.headers.get('Content-Range'))
|
||||
return rv
|
||||
elif sub == 'gds2':
|
||||
url = f"{app.config['DEFINE']['WEB_DIRECT_URL']}/sjva/gds.php?type=file&id={request.args.get('id')}&user_id={ModelSetting.get('sjva_me_user_id')}&user_apikey={ModelSetting.get('auth_apikey')}"
|
||||
data = requests.get(url).json()['data']
|
||||
logger.debug(data)
|
||||
req_headers = dict(request.headers)
|
||||
headers = {}
|
||||
|
||||
headers['Range'] = f"bytes={request.args.get('range')}"
|
||||
headers['Authorization'] = f"Bearer {data['token']}"
|
||||
headers['Connection'] = 'keep-alive'
|
||||
logger.warning(headers)
|
||||
"""
|
||||
response = redirect(data['url'])
|
||||
headers = dict(response.headers)
|
||||
headers.update({'Authorization': f"Bearer {data['token']}"})
|
||||
response.headers = headers
|
||||
return response
|
||||
|
||||
response.headers.add('Authorization', headers['Authorization'])
|
||||
#response.headers['Location'] = data['url']
|
||||
return response
|
||||
"""
|
||||
|
||||
r = requests.get(data['url'], headers=headers, stream=True)
|
||||
logger.warning(r.history)
|
||||
#rv = Response(r.iter_content(chunk_size=10485760), r.status_code, content_type=r.headers['Content-Type'], direct_passthrough=True)
|
||||
#rv.headers.add('Content-Range', r.headers.get('Content-Range'))
|
||||
|
||||
rv = Response(r.iter_content(chunk_size=1048576), r.status_code, content_type=r.headers['Content-Type'], direct_passthrough=True)
|
||||
rv.headers.add('Content-Range', r.headers.get('Content-Range'))
|
||||
|
||||
logger.debug(rv.headers)
|
||||
return rv
|
||||
elif sub == 'gds_subtitle':
|
||||
url = f"{app.config['DEFINE']['WEB_DIRECT_URL']}/sjva/gds2.php?type=file&id={request.args.get('id')}&user_id={ModelSetting.get('sjva_me_user_id')}&user_apikey={ModelSetting.get('auth_apikey')}"
|
||||
data = requests.get(url).json()['data']
|
||||
logger.debug(data)
|
||||
req_headers = dict(request.headers)
|
||||
headers = {}
|
||||
headers['Range'] = f"bytes={request.args.get('range')}"
|
||||
headers['Authorization'] = f"Bearer {data['token']}"
|
||||
headers['Connection'] = 'keep-alive'
|
||||
logger.warning(headers)
|
||||
r = requests.get(data['url'], headers=headers, stream=True)
|
||||
logger.warning(r.history)
|
||||
if r.encoding != None:
|
||||
if r.encoding == 'ISO-8859-1': # 한글자막 인코딩 예외처리
|
||||
try:
|
||||
text = r.content.decode('utf-8', "strict")
|
||||
except Exception as e:
|
||||
logger.error('Exception:%s', e)
|
||||
logger.error(traceback.format_exc())
|
||||
text = r.content.decode('utf-8', "ignore")
|
||||
else:
|
||||
text = r.content.decode(r.encoding, "ignore")
|
||||
else:
|
||||
text = r.text
|
||||
from framework.common.util import convert_srt_to_vtt as convSrt2Vtt
|
||||
vtt = convSrt2Vtt(text)
|
||||
r.headers['Content-Type'] = "text/vtt; charset=utf-8"
|
||||
rv = Response(vtt, r.status_code, content_type=r.headers['Content-Type'])
|
||||
rv.headers.add('Content-Disposition', 'inline; filename="subtitle.vtt"')
|
||||
rv.headers.add('Content-Transfer-Encoding', 'binary')
|
||||
logger.debug(rv.headers)
|
||||
return rv
|
||||
|
||||
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
@blueprint.route('/api/<sub>/<sub2>', methods=['GET', 'POST'])
|
||||
@check_api
|
||||
def second_api(sub, sub2):
|
||||
try:
|
||||
if sub == 'trans':
|
||||
from .logic_trans import SystemLogicTrans
|
||||
return SystemLogicTrans.process_api(sub2, request)
|
||||
elif sub == 'site':
|
||||
from .logic_site import SystemLogicSite
|
||||
return SystemLogicSite.process_api(sub2, request)
|
||||
|
||||
except Exception as exception:
|
||||
logger.error('Exception:%s', exception)
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
@blueprint.route("/videojs", methods=['GET', 'POST'])
|
||||
def videojs():
|
||||
data = {}
|
||||
data['play_title'] = request.form['play_title']
|
||||
data['play_source_src'] = request.form['play_source_src']
|
||||
data['play_source_type'] = request.form['play_source_type']
|
||||
if 'play_subtitle_src' in request.form:
|
||||
data['play_subtitle_src'] = request.form['play_subtitle_src']
|
||||
#logger.warning(data)
|
||||
return render_template('videojs.html', data=data)
|
||||
61
lib/system/setup.py
Normal file
61
lib/system/setup.py
Normal file
@@ -0,0 +1,61 @@
|
||||
__menu = {
|
||||
'uri' : __package__,
|
||||
'name': '설정',
|
||||
'list': [
|
||||
{
|
||||
'uri': 'setting',
|
||||
'name': '일반설정',
|
||||
'list': [
|
||||
{'uri': 'basic', 'name': '기본'},
|
||||
{'uri': 'auth', 'name': '인증'},
|
||||
{'uri': 'web', 'name': '웹'},
|
||||
{'uri': 'env', 'name': '시스템'},
|
||||
{'uri': 'menu', 'name': '메뉴'},
|
||||
{'uri': 'notify', 'name': '알림'},
|
||||
{'uri': 'crypt', 'name': '암호화'},
|
||||
],
|
||||
},
|
||||
{
|
||||
'uri': 'plugin',
|
||||
'name': '플러그인'
|
||||
},
|
||||
{
|
||||
'uri': 'python',
|
||||
'name': 'Python'
|
||||
},
|
||||
{
|
||||
'uri': 'db',
|
||||
'name': 'DB'
|
||||
},
|
||||
{
|
||||
'uri': 'log',
|
||||
'name': '로그'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
setting = {
|
||||
'filepath' : __file__,
|
||||
'use_db': True,
|
||||
'use_default_setting': True,
|
||||
'home_module': 'setting',
|
||||
'menu': __menu,
|
||||
'setting_menu': None,
|
||||
'default_route': 'normal',
|
||||
}
|
||||
|
||||
try:
|
||||
from plugin import *
|
||||
P = create_plugin_instance(setting)
|
||||
|
||||
SystemModelSetting = P.ModelSetting
|
||||
from .mod_setting import ModuleSetting
|
||||
from .mod_home import ModuleHome
|
||||
from .mod_route import ModuleRoute
|
||||
|
||||
P.set_module_list([ModuleSetting, ModuleHome, ModuleRoute])
|
||||
|
||||
except Exception as e:
|
||||
P.logger.error(f'Exception:{str(e)}')
|
||||
P.logger.error(traceback.format_exc())
|
||||
234
lib/system/templates/system_home.html
Normal file
234
lib/system/templates/system_home.html
Normal file
@@ -0,0 +1,234 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
<script type="text/javascript">
|
||||
hideMenuModule();
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
|
||||
<h3>시스템</h3>
|
||||
<hr>
|
||||
{{ macros.info_text_and_buttons('python_version', 'Python', [['globalLinkBtn', '패키지 관리', [('url','/system/python')]]], info['python_version']) }}
|
||||
{{ macros.info_text('platform', 'Platform', info['platform']) }}
|
||||
{{ macros.info_text('processor', 'Processor', info['processor']) }}
|
||||
{{ macros.info_text_and_buttons('version_str', '버전', [['globalOpenBtn', '업데이트 내역', [('url','https://sjva.me/wiki/public/changelog')]], ['recent_version_btn', '최신버전 확인']], info['version']) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-inline-block"></div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<h3>App 환경</h3>
|
||||
<hr>
|
||||
{{ macros.info_text_and_buttons('running_type', '실행타입', [['config_show_btn', 'Config 확인']], info['running_type'] + ' → 비동기 작업 ' + info['use_celery']) }}
|
||||
{{ macros.info_text_and_buttons('config_filepath', 'Config', [['globalEditBtn', '편집', [('file',info['config_filepath'])]]], value=info['config_filepath']) }}
|
||||
{{ macros.info_text('path_app', 'Path App', info['path_app']) }}
|
||||
{{ macros.info_text('path_data', 'Path Data', info['path_data']) }}
|
||||
{{ macros.info_text('path_working', 'Path Working', info['path_working']) }}
|
||||
{{ macros.info_text('time', '실행 시간') }}
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6">
|
||||
<h3>모니터링</h3>
|
||||
<hr>
|
||||
{{ macros.info_text('cpu_percent', 'CPU 사용량') }}
|
||||
{{ macros.info_text('memory', '메모리') }}
|
||||
{{ macros.info_text('disk', '디스크') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-inline-block"></div>
|
||||
|
||||
<h3>스케쥴</h3>
|
||||
<div id="scheduler_list_div"></div>
|
||||
</div> <!--전체-->
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function(){
|
||||
var socket = io.connect(window.location.href);
|
||||
|
||||
socket.on('start', function(data){
|
||||
});
|
||||
|
||||
socket.on('status', function(data) {
|
||||
make_system(data.system);
|
||||
make_scheduler_list(data.scheduler);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$("body").on('click', '#recent_version_btn', function(e){
|
||||
e.preventDefault();
|
||||
globalSendCommand('recent_version');
|
||||
});
|
||||
|
||||
|
||||
|
||||
$("body").on('click', '#config_show_btn', function(e){
|
||||
e.preventDefault();
|
||||
globalSendCommand('get_config', null, null, null, 'Config');
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
function make_system(data) {
|
||||
str = data.version;
|
||||
if (data.version == data.recent_version) {
|
||||
str += text_color(" (최신 버전)", 'blue');
|
||||
} else {
|
||||
str += text_color(" (최신 버전 : " + data.recent_version+')', 'red');
|
||||
}
|
||||
$('#version_str').html(str);
|
||||
|
||||
str = '<table id="result_table" class="table table-sm" style="margin-bottom:0px" ><thead class=""><tr> \
|
||||
<th style="width:50%;text-align:center;font-size:11px;">시작시간</th> \
|
||||
<th style="width:30%;text-align:center;font-size:11px;">경과</th> \
|
||||
<th style="width:20%;text-align:center;font-size:11px;">재시작</th> \
|
||||
</tr></thead><tbody id="list">';
|
||||
str += '<tr class="chover">';
|
||||
str += '<td scope="col" style="width:50%;text-align:center;">' + data['time'][0] + '</td>';
|
||||
str += '<td scope="col" style="width:30%;text-align:center;">' + data['time'][1] + '</td>';
|
||||
str += '<td scope="col" style="width:20%;text-align:center;">' + data['time'][2] + '</td>';
|
||||
str += '</tr></table>';
|
||||
$('#time').html(str);
|
||||
|
||||
if (data['memory'] == 'not supported') {
|
||||
str = data['memory'];
|
||||
} else {
|
||||
str = '<table id="result_table" class="table table-sm" style="margin-bottom:0px"><thead class=""><tr> \
|
||||
<th style="width:25%;text-align:center;font-size:11px;">전체</th> \
|
||||
<th style="width:25%;text-align:center;font-size:11px;">사용량</th> \
|
||||
<th style="width:25%;text-align:center;font-size:11px;">남은량</th> \
|
||||
<th style="width:25%;text-align:center;font-size:11px;">%</th> \
|
||||
</tr></thead><tbody id="list">';
|
||||
str += '<tr class="chover">';
|
||||
str += '<td scope="col" style="text-align:center;">' + data['memory'][0] + '</td>';
|
||||
str += '<td scope="col" style="text-align:center;">' + data['memory'][1] + '</td>';
|
||||
str += '<td scope="col" style="text-align:center;">' + data['memory'][2] + '</td>';
|
||||
str += '<td scope="col" style="text-align:center;">' + data['memory'][3] + '</td>';
|
||||
str += '</tr></table>';
|
||||
}
|
||||
$('#memory').html(str);
|
||||
|
||||
if (data['disk'] == 'not supported') {
|
||||
str = data['disk'];
|
||||
} else {
|
||||
str = '<table id="result_table" class="table table-sm" style="margin-bottom:0px"><thead class=""><tr> \
|
||||
<th style="width:25%;text-align:center;font-size:11px;">전체</th> \
|
||||
<th style="width:25%;text-align:center;font-size:11px;">사용량</th> \
|
||||
<th style="width:25%;text-align:center;font-size:11px;">남은량</th> \
|
||||
<th style="width:25%;text-align:center;font-size:11px;">%</th> \
|
||||
</tr></thead><tbody id="list">';
|
||||
str += '<tr class="chover">';
|
||||
str += '<td scope="col" style="text-align:center;">' + data['disk'][0] + '</td>';
|
||||
str += '<td scope="col" style="text-align:center;">' + data['disk'][1] + '</td>';
|
||||
str += '<td scope="col" style="text-align:center;">' + data['disk'][2] + '</td>';
|
||||
str += '<td scope="col" style="text-align:center;">' + data['disk'][3] + '</td>';
|
||||
str += '</tr></table>';
|
||||
if (data['disk'][4] != '/') {
|
||||
str += '드라이브 ' + data['disk'][4];
|
||||
}
|
||||
}
|
||||
$('#disk').html(str);
|
||||
}
|
||||
|
||||
|
||||
function make_scheduler_list(data) {
|
||||
str = `
|
||||
<table id="result_table" class="table table-sm ">
|
||||
<thead class="">
|
||||
<tr>
|
||||
<th rowspan='2' style="width:10%;text-align:center;vertical-align:middle;">NO</th>
|
||||
<th style="width:10%;text-align:center;vertical-align:middle;">플러그인<br>ID</th>
|
||||
<th style="width:10%;text-align:center;vertical-align:middle;">상태</th>
|
||||
<th style="width:10%;text-align:center;vertical-align:middle;">다음 실행시간</th>
|
||||
<th style="width:10%;text-align:center;vertical-align:middle;">남은 시간</th>
|
||||
<th style="width:10%;text-align:center;vertical-align:middle;">주기</th>
|
||||
<th style="width:10%;text-align:center;vertical-align:middle;">이전소요시간<br>실행횟수</th>
|
||||
<th style="width:20%;text-align:center;vertical-align:middle;">설명</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="scheduler_list">`;
|
||||
|
||||
TD_STR = '<td scope="col" style="width:10%; text-align:center;">';
|
||||
for(var i in data) {
|
||||
if (data[i].is_running) {
|
||||
str += '<tr class="bg-light">';
|
||||
} else {
|
||||
str += '<tr>';
|
||||
}
|
||||
str += '<td scope="col" style="width:5%; text-align:center;">' + (parseInt(i)+1) + '</td>';
|
||||
str += '<td scope="col" style="width:10%; text-align:center;">' + (data[i].plugin) + '<br>' + (data[i].id) + '</td>';
|
||||
str += '<td scope="col" style="width:10%; text-align:center;">' + ((data[i].is_running) ?'실행중':'대기중') + '</td>';
|
||||
str += '<td scope="col" style="width:10%; text-align:center;">' + (data[i].next_run_time) + '</td>';
|
||||
str += '<td scope="col" style="width:10%; text-align:center;">' + (data[i].remain_time) + '</td>';
|
||||
|
||||
str += '<td scope="col" style="width:10%; text-align:center;">' + (data[i].interval) + '</td>';
|
||||
str += '<td scope="col" style="width:10%; text-align:center;">' + (data[i].running_timedelta) + '<br>' + (data[i].count) +'</td>';
|
||||
str += '<td scope="col" style="width:10%; text-align:center;">' + (data[i].description) + '</td>';
|
||||
str += '</tr>';
|
||||
}
|
||||
str += `
|
||||
</tbody>
|
||||
</table>`;
|
||||
|
||||
$("#scheduler_list_div").html(str);
|
||||
return;
|
||||
|
||||
|
||||
str = m_row_start(p='0');
|
||||
str += m_col(1, '<strong>NO</strong>');
|
||||
str += m_col(2, '<strong>플러그인 & ID</strong>');
|
||||
//str += m_col(2, '<strong>생성 & 다음 실행</strong>');
|
||||
str += m_col(2, '<strong>다음 실행 (남은시간)</strong>');
|
||||
str += m_col(1, '<strong>이전소요/횟수</strong>');
|
||||
str += m_col(2, '<strong>Interval & Cron</strong>');
|
||||
str += m_col(1, '<strong>상태</strong>');
|
||||
str += m_col(3, '<strong>설 명</strong>');
|
||||
str += m_row_end();
|
||||
str += m_hr();
|
||||
|
||||
for(var i in data) {
|
||||
if (data[i].is_running) {
|
||||
str += m_row_start_color2(0);
|
||||
} else {
|
||||
str += m_row_start(p='0');
|
||||
}
|
||||
|
||||
str += m_col(1, data[i].no);
|
||||
tmp = '<strong>'+data[i].plugin+'</strong><br>' + data[i].id;
|
||||
str += m_col(2, tmp);
|
||||
|
||||
//tmp = ''+''+'' + data[i].make_time + '<br>';
|
||||
//tmp += ''+''+'' + data[i].next_run_time + '<br>';
|
||||
tmp = ''+''+'' + data[i].next_run_time + '<br>';
|
||||
if (data[i].remain_time != '') {
|
||||
tmp += '('+data[i].remain_time+')';
|
||||
}
|
||||
str += m_col(2, tmp);
|
||||
tmp = ''+''+'' + data[i].running_timedelta + '초 / ';
|
||||
tmp += ''+''+'' + data[i].count + '회';
|
||||
str += m_col(1, tmp);
|
||||
|
||||
tmp = ''+''+'' + data[i].interval + ' <br>';
|
||||
str += m_col(2, tmp);
|
||||
tmp = ''+''+'' + ((data[i].is_running) ?'실행중':'대기중') + '';
|
||||
if (data[i].run == false) {
|
||||
tmp += '(F)'
|
||||
}
|
||||
str += m_col(1, tmp);
|
||||
str += m_col(3, data[i].description);
|
||||
str += m_row_end();
|
||||
str += m_hr();
|
||||
}
|
||||
document.getElementById("scheduler_list_div").innerHTML = str;
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
133
lib/system/templates/system_log.html
Normal file
133
lib/system/templates/system_log.html
Normal file
@@ -0,0 +1,133 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<style>
|
||||
.tab-pane {
|
||||
border-left: 1px solid #ddd;
|
||||
border-right: 1px solid #ddd;
|
||||
border-bottom: 1px solid #ddd;
|
||||
border-radius: 0px 0px 5px 5px;
|
||||
padding: 10px;
|
||||
}
|
||||
.nav-tabs { margin-bottom: 0; }
|
||||
</style>
|
||||
|
||||
<div>
|
||||
{{ macros.setting_top(left='로그 파일 선택') }}
|
||||
<div class="input-group col-sm-9">
|
||||
<div id='log_select1_div'></div>
|
||||
<div id='log_select2_div'></div>
|
||||
</div>
|
||||
{{ macros.setting_bottom() }}
|
||||
<nav>
|
||||
{{ macros.m_tab_head_start() }}
|
||||
{{ macros.m_tab_head('이전', true) }}
|
||||
{{ macros.m_tab_head('실시간', false) }}
|
||||
{{ macros.m_tab_head_end() }}
|
||||
</nav>
|
||||
<div class="tab-content" id="nav-tabContent">
|
||||
{{ macros.m_tab_content_start('이전', 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('실시간', 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>
|
||||
</div>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
var package_name = "{{arg['package_name']}}";
|
||||
var sub = "{{arg['sub']}}";
|
||||
var log_list = "{{arg['log_list']}}";
|
||||
var all_list = "{{arg['all_list']}}";
|
||||
|
||||
var protocol = window.location.protocol;
|
||||
var socket = io.connect(protocol + "//" + document.domain + ":" + location.port + "/log");
|
||||
var current_filename = '';
|
||||
var start_filename = "{{arg['filename']}}";
|
||||
|
||||
$(document).ready(function() {
|
||||
$('#main_container').attr('class', 'container-fluid');
|
||||
ResizeTextArea()
|
||||
make_form()
|
||||
if (start_filename != '')
|
||||
document.getElementById('log_select').value = start_filename;
|
||||
$('#log_select').change();
|
||||
})
|
||||
|
||||
function make_form() {
|
||||
str = '<select id="log_select" name="log_select" class="form-control form-control-sm">';
|
||||
data = log_list.split('|')
|
||||
for(var i in data) {
|
||||
str += '<option value="' + data[i] + '">' + data[i] + '</option>';
|
||||
}
|
||||
document.getElementById("log_select1_div").innerHTML = 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>';
|
||||
}
|
||||
document.getElementById("log_select2_div").innerHTML = str;
|
||||
}
|
||||
|
||||
$("body").on('change', '#log_select', function(e){
|
||||
e.preventDefault();
|
||||
filename = $(this)[0].value;
|
||||
current_filename = filename;
|
||||
$('#loading').show();
|
||||
socket.emit("start", {'filename':filename} );
|
||||
});
|
||||
|
||||
|
||||
function ResizeTextArea() {
|
||||
ClientHeight = window.innerHeight
|
||||
$("#log").height(ClientHeight-260);
|
||||
$("#add").height(ClientHeight-280);
|
||||
}
|
||||
|
||||
$(window).resize(function() {
|
||||
ResizeTextArea();
|
||||
});
|
||||
|
||||
|
||||
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';
|
||||
$('#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;
|
||||
}
|
||||
});
|
||||
|
||||
$("#clear").click(function(e) {
|
||||
e.preventDefault();
|
||||
document.getElementById("add").innerHTML = '';
|
||||
});
|
||||
|
||||
$("#auto_scroll").click(function(){
|
||||
var chk = $(this).is(":checked");//.attr('checked');
|
||||
});
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
72
lib/system/templates/system_login.html
Normal file
72
lib/system/templates/system_login.html
Normal file
@@ -0,0 +1,72 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<script type="text/javascript">
|
||||
hideMenu();
|
||||
</script>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-4"></div>
|
||||
<div class="login-form col-sm-4 border">
|
||||
<!--<form action="/login" method="post" _lpchecked="1">
|
||||
-->
|
||||
<form id="login_form">
|
||||
<input type="hidden" id="next" name="next" value="{{next}}">
|
||||
<h2 class="text-center">Log in</h2>
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon"><i class="fa fa-user"></i></span>
|
||||
<input type="text" class="form-control" name="username" id="username" placeholder="Username" required="required" autocomplete="off" >
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon"><i class="fa fa-lock"></i></span>
|
||||
<input type="password" class="form-control" name="password" id="password" placeholder="Password" required="required" autocomplete="off" >
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button id="login_btn" class="btn btn-primary login-btn btn-block">Sign in</button>
|
||||
</div>
|
||||
<div class="clearfix">
|
||||
<label class="pull-left checkbox-inline"><input type="checkbox" name='remember' id='remember' checked> Remember me</label>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
$("body").on('click', '#login_btn', function(e){
|
||||
e.preventDefault();
|
||||
|
||||
globalSendCommand('login',
|
||||
$('#username').val(),
|
||||
$('#password').val(),
|
||||
$("#remember").is(":checked"),
|
||||
'',
|
||||
function(data) {
|
||||
if (data == 'redirect') {
|
||||
next = document.getElementById("next").value;
|
||||
console.log(next)
|
||||
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>', {
|
||||
type: 'warning'
|
||||
});
|
||||
} else if (data == 'wrong_password') {
|
||||
$.notify('<strong>암호가 틀립니다.</strong>', {
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
182
lib/system/templates/system_plugin.html
Normal file
182
lib/system/templates/system_plugin.html
Normal file
@@ -0,0 +1,182 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<style type="text/css">
|
||||
.my_hover:hover{
|
||||
background-color: #ffff00;
|
||||
transition: all 0.01s ease-in-out;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div>
|
||||
<nav>
|
||||
{{ macros.m_tab_head_start() }}
|
||||
{{ macros.m_tab_head2('normal', '일반', false) }}
|
||||
{{ macros.m_tab_head2('list', '플러그인 목록', true) }}
|
||||
{{ macros.m_tab_head_end() }}
|
||||
</nav>
|
||||
|
||||
<div class="tab-content" id="nav-tabContent">
|
||||
|
||||
{{ macros.m_tab_content_start('normal', false) }}
|
||||
<form id='setting' name='setting'>
|
||||
{{ macros.setting_input_text('plugin_dev_path', '개발용 플러그인 경로', value=arg['plugin_dev_path'], desc=['플러그인을 개발할 때 사용하는 경로'], col='9') }}
|
||||
{{ macros.setting_button([['setting_save', '저장']]) }}
|
||||
|
||||
</form>
|
||||
</form>
|
||||
{{ macros.m_tab_content_end() }}
|
||||
|
||||
{{ macros.m_tab_content_start('list', true) }}
|
||||
{{ macros.setting_input_text_and_buttons('plugin_git', '플러그인 수동 설치', [['plugin_install_btn', '설치']], value='https://github.com/', desc=['SJVA.ME 플러그인 게시판에 있는 링크 주소를 입력하세요.']) }}
|
||||
|
||||
{{ macros.m_hr_head_top() }}
|
||||
{{ macros.m_row_start('0') }}
|
||||
{{ macros.m_col(3, macros.m_strong('Name')) }}
|
||||
{{ macros.m_col(1, macros.m_strong('Dev.')) }}
|
||||
{{ macros.m_col(1, macros.m_strong('Category')) }}
|
||||
{{ macros.m_col(1, macros.m_strong('Version')) }}
|
||||
{{ macros.m_col(6, macros.m_strong('Description')) }}
|
||||
{{ macros.m_row_end() }}
|
||||
{{ macros.m_hr_head_bottom() }}
|
||||
<div id="plugin_list_div"></div>
|
||||
{{ macros.m_tab_content_end() }}
|
||||
</div><!--tab-content-->
|
||||
</div> <!--전체-->
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
var package_name = 'system';
|
||||
var current_data;
|
||||
var install = "{{arg['install']}}";
|
||||
|
||||
$(document).ready(function(){
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/plugin_list',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: {},
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
current_data = data
|
||||
make_plugin_list();
|
||||
if (install != '') {
|
||||
$('#plugin_git').val(install);
|
||||
//notify('플러그인이 설치되어 있지 않습니다.', 'danger');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//설정 저장
|
||||
$("#setting_save").click(function(e) {
|
||||
e.preventDefault();
|
||||
var formData = get_formdata('#setting');
|
||||
setting_save_func(formData, true)
|
||||
//
|
||||
});
|
||||
|
||||
|
||||
function setting_save_func(formData, noti) {
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/setting_save',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: formData,
|
||||
dataType: "json",
|
||||
success: function (ret) {
|
||||
if (ret) {
|
||||
if (noti) {
|
||||
$.notify('<strong>설정을 저장하였습니다.</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
} else {
|
||||
window.location.href = "/"
|
||||
}
|
||||
} else {
|
||||
$.notify('<strong>설정 저장에 실패하였습니다.</strong>', {
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function make_plugin_list() {
|
||||
str = ''
|
||||
console.log(current_data)
|
||||
for (i in current_data) {
|
||||
console.log(i)
|
||||
console.log(current_data[i])
|
||||
str += m_row_start();
|
||||
str += m_col(3, i)
|
||||
|
||||
if (current_data[i].info != null) {
|
||||
str += m_col(1, current_data[i].info.developer);
|
||||
str += m_col(1, current_data[i].info.category);
|
||||
str += m_col(1, current_data[i].info.version);
|
||||
tmp = ''
|
||||
tmp += m_button('plugin_uninstall_btn', '삭제', [{'key':'plugin_name', 'value':current_data[i].info.name}]);
|
||||
if (current_data[i].info.local_info != null) {
|
||||
tmp += m_button('global_link_btn', 'GIT', [{'key':'url', 'value':current_data[i].info.local_info.home}]);
|
||||
if (current_data[i].info.local_info.home != current_data[i].info.local_info.more && current_data[i].info.local_info.more.startsWith('http'))
|
||||
tmp += m_button('global_link_btn', 'MORE', [{'key':'url', 'value':current_data[i].info.local_info.more}]);
|
||||
}
|
||||
|
||||
tmp = m_button_group(tmp)
|
||||
str += m_col(6, current_data[i].info.description +'<br><br>'+ tmp)
|
||||
}
|
||||
str += m_row_end();
|
||||
if (i != current_data.length -1) str += m_hr(0);
|
||||
}
|
||||
document.getElementById("plugin_list_div").innerHTML = str;
|
||||
}
|
||||
|
||||
|
||||
|
||||
$("body").on('click', '#plugin_install_btn', function(e){
|
||||
e.preventDefault();
|
||||
plugin_git = document.getElementById("plugin_git").value
|
||||
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/plugin_install',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data:{plugin_git:plugin_git},
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
t = (data.ret == 'success') ? 'success' : 'warning'
|
||||
$.notify('<strong>'+data.log+'</strong>', {
|
||||
type: t
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$("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'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
40
lib/system/templates/system_restart.html
Normal file
40
lib/system/templates/system_restart.html
Normal file
@@ -0,0 +1,40 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<script type="text/javascript">
|
||||
hideMenu();
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<h4>
|
||||
{% if sub == 'restart' %}
|
||||
시스템 재시작 중입니다. <br>
|
||||
완료시 이전 페이지로 이동합니다.
|
||||
|
||||
{% elif sub == 'shutdown' %}
|
||||
시스템이 종료되었습니다.
|
||||
{% endif %}
|
||||
</h4>
|
||||
</div>
|
||||
{% if sub == 'restart' %}
|
||||
|
||||
<script type="text/javascript">
|
||||
var referer = "{{referer}}";
|
||||
|
||||
$(document).ready(function() {
|
||||
if (MODULE_NAME == 'restart') {
|
||||
$('#loading').show();
|
||||
setTimeout(function(){
|
||||
}, 2000);
|
||||
|
||||
var protocol = window.location.protocol;
|
||||
var restartSocket = io.connect(window.location.href);
|
||||
|
||||
restartSocket.on('connect', function(data){
|
||||
console.log('접속 받음')
|
||||
window.location.href = referer;
|
||||
});
|
||||
}
|
||||
})
|
||||
</script>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
50
lib/system/templates/system_setting_auth.html
Normal file
50
lib/system/templates/system_setting_auth.html
Normal file
@@ -0,0 +1,50 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div>
|
||||
{{ macros.m_button_group([['globalSettingSaveBtn', '설정 저장']])}}
|
||||
{{ macros.m_row_start('5') }}
|
||||
{{ macros.m_row_end() }}
|
||||
{{ macros.m_hr() }}
|
||||
|
||||
<form id='setting' name='setting'>
|
||||
{{ macros.setting_checkbox('use_login', '로그인 사용', value=arg['use_login']) }}
|
||||
<div id="use_login_div" class="collapse">
|
||||
{{ macros.setting_input_text('web_id', '로그인 ID', value=arg['web_id'], desc=['초기값은 admin입니다.'], col='3') }}
|
||||
{{ macros.setting_input_text('web_pw', '로그인 암호', value=arg['web_pw'], col='3', type='password', desc=['초기값은 sjva입니다.']) }}
|
||||
</div>
|
||||
|
||||
{{ macros.m_hr() }}
|
||||
|
||||
{{ macros.setting_checkbox('use_apikey', 'APIKEY 사용', value=arg['use_apikey'], desc=['On : 모든 API 요청 시 apikey 값을 입력해야 합니다.', '없거나 틀릴 경우 에러코드 403리턴']) }}
|
||||
<div id="use_apikey_div" class="collapse">
|
||||
{{ macros.setting_input_text_and_buttons('apikey', 'APIKEY', [['apikey_generate_btn', '자동생성']], col='4', value=arg['apikey']) }}
|
||||
</div>
|
||||
{{ macros.m_hr() }}
|
||||
</form>
|
||||
</div> <!--전체-->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
$(document).ready(function(){
|
||||
use_collapse("use_login");
|
||||
use_collapse("use_apikey");
|
||||
});
|
||||
|
||||
$('#use_login').change(function() {
|
||||
use_collapse('use_login');
|
||||
});
|
||||
|
||||
$('#use_apikey').change(function() {
|
||||
use_collapse('use_apikey');
|
||||
});
|
||||
|
||||
$("body").on('click', '#apikey_generate_btn', function(e) {
|
||||
e.preventDefault();
|
||||
globalSendCommand('apikey_generate', null, null, null, null, function(ret){
|
||||
$("#apikey").val(ret);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
420
lib/system/templates/system_setting_basic copy.html
Normal file
420
lib/system/templates/system_setting_basic copy.html
Normal file
@@ -0,0 +1,420 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<style type="text/css">
|
||||
.my_hover:hover{
|
||||
background-color: #ffff00;
|
||||
transition: all 0.01s ease-in-out;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div>
|
||||
<nav>
|
||||
{{ macros.m_tab_head_start() }}
|
||||
{{ macros.m_tab_head2('normal', '일반', true) }}
|
||||
{{ macros.m_tab_head2('web', '웹', false) }}
|
||||
{{ macros.m_tab_head2('menu', '메뉴', false) }}
|
||||
{{ macros.m_tab_head2('link', '링크', false) }}
|
||||
{{ macros.m_tab_head2('download', '다운로드', false) }}
|
||||
{{ macros.m_tab_head_end() }}
|
||||
</nav>
|
||||
|
||||
<div class="tab-content" id="nav-tabContent">
|
||||
{{ macros.m_tab_content_start('normal', true) }}
|
||||
<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:// 로 시작해야합니다.', 'RSS, Plex Callback, KLive 등에서 URL생성시 사용합니다.', '테스트 버튼 클릭 후 버전을 확인 할 수 있어야 합니다.']) }}
|
||||
{{ macros.setting_input_text('auto_restart_hour', '자동 재시작 시간', value=arg['auto_restart_hour'], col='3', desc=['자동 재시작 간격(시간단위)이나 Cron 설정을 입력합니다.', '0이면 재시작 안함.']) }}
|
||||
{{ macros.setting_select('log_level', '로그 레벨', [['10', 'DEBUG'],['20', 'INFO'],['30', 'WARNING'],['40', 'ERROR'], ['50', 'CRITICAL'] ], value=arg['log_level'], col='3') }}
|
||||
{{ macros.setting_button([['setting_save', '저장']]) }}
|
||||
</form>
|
||||
</form>
|
||||
{{ macros.m_hr() }}
|
||||
{{ macros.setting_input_text_and_buttons('command_text', 'Command', [['command_run_btn', 'Run']], value='', desc='') }}
|
||||
{{ macros.m_tab_content_end() }}
|
||||
|
||||
|
||||
{{ macros.m_tab_content_start('web', false) }}
|
||||
<form id='setting2' name='setting2'>
|
||||
{{ macros.setting_select('theme', '테마 선택', [['Default','Default'], ['Cerulean','Cerulean'], ['Cosmo','Cosmo'], ['Cyborg','Cyborg'], ['Darkly','Darkly'], ['Flatly','Flatly'], ['Journal','Journal'], ['Litera','Litera'], ['Lumen','Lumen'], ['Lux','Lux'], ['Materia','Materia'], ['Minty','Minty'], ['Morph','Morph'],['Pulse','Pulse'], ['Quartz','Quartz'], ['Sandstone','Sandstone'], ['Simplex','Simplex'], ['Sketchy','Sketchy'], ['Slate','Slate'], ['Solar','Solar'], ['Spacelab','Spacelab'], ['Superhero','Superhero'], ['United','United'], ['Vapor','Vapor'], ['Yeti','Yeti'], ['Zephyr','Zephyr']], value=arg['theme'], desc=['https://bootswatch.com'], col='6') }}
|
||||
{{ macros.setting_input_text('web_title', '웹 타이틀', value=arg['web_title']) }}
|
||||
{{ macros.setting_button([['setting_save2', '저장']]) }}
|
||||
</form>
|
||||
{{ macros.m_tab_content_end() }}
|
||||
|
||||
|
||||
{{ macros.m_tab_content_start('menu', false) }}
|
||||
<form id='setting3' name='setting3'>
|
||||
{% if arg['use_category_vod'] == 'True' %}
|
||||
{{ macros.m_hr() }}
|
||||
{{ macros.setting_button_with_info([['menu_toggle_btn', 'Toggle', [{'key':'category', 'value':'vod'}]]], left='VOD', desc=None) }}
|
||||
<div id="menu_vod_div" class="collapse">
|
||||
{{ macros.setting_checkbox('use_plugin_ffmpeg', 'FFMPEG', value=arg['use_plugin_ffmpeg']) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if arg['use_category_file_process'] == 'True' %}
|
||||
{{ macros.m_hr() }}
|
||||
{{ macros.setting_button_with_info([['menu_toggle_btn', 'Toggle', [{'key':'category', 'value':'file_process'}]]], left='파일처리', desc=None) }}
|
||||
<div id="menu_file_process_div" class="collapse">
|
||||
{{ macros.setting_checkbox('use_plugin_ktv', '국내TV', value=arg['use_plugin_ktv']) }}
|
||||
{{ macros.setting_checkbox('use_plugin_fileprocess_movie', '영화', value=arg['use_plugin_fileprocess_movie']) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if arg['use_category_plex'] == 'True' %}
|
||||
{{ macros.m_hr() }}
|
||||
{{ macros.setting_button_with_info([['menu_toggle_btn', 'Toggle', [{'key':'category', 'value':'plex'}]]], left='PLEX', desc=None) }}
|
||||
<div id="menu_plex_div" class="collapse">
|
||||
{{ macros.setting_checkbox('use_plugin_plex', 'PLEX', value=arg['use_plugin_plex']) }}
|
||||
{{ macros.setting_checkbox('use_plugin_gdrive_scan', 'GDrive 스캔', value=arg['use_plugin_gdrive_scan']) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if arg['use_category_tool'] == 'True' %}
|
||||
{{ macros.m_hr() }}
|
||||
{{ macros.setting_button_with_info([['menu_toggle_btn', 'Toggle', [{'key':'category', 'value':'tool'}]]], left='툴', desc=None) }}
|
||||
<div id="menu_tool_div" class="collapse">
|
||||
{{ macros.setting_checkbox('use_plugin_rclone', 'RClone', value=arg['use_plugin_rclone']) }}
|
||||
{{ macros.setting_checkbox('use_plugin_daum_tv', 'Daum TV', value=arg['use_plugin_daum_tv']) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{{ macros.setting_button([['setting_save3', '저장']]) }}
|
||||
</form>
|
||||
{{ macros.m_tab_content_end() }}
|
||||
|
||||
|
||||
{{ macros.m_tab_content_start('link', false) }}
|
||||
{{ macros.m_button_group([['link_add_btn', '추가'], ['link_add_divider_btn', 'Divider Line 추가'], ['link_save_btn', '저장'], ['link_reset_btn', '초기화']])}}
|
||||
{{ macros.m_row_start('0') }}
|
||||
{{ macros.m_row_end() }}
|
||||
|
||||
{{ macros.m_hr_head_top() }}
|
||||
{{ macros.m_row_start('0') }}
|
||||
{{ macros.m_col(1, macros.m_strong('Idx')) }}
|
||||
{{ macros.m_col(4, macros.m_strong('Title')) }}
|
||||
{{ macros.m_col(4, macros.m_strong('URL')) }}
|
||||
{{ macros.m_col(3, macros.m_strong('Action')) }}
|
||||
{{ macros.m_row_end() }}
|
||||
{{ macros.m_hr_head_bottom() }}
|
||||
<form id="link_form" name="link_form">
|
||||
<div id="link_list_div"></div>
|
||||
</form>
|
||||
{{ macros.m_tab_content_end() }}
|
||||
|
||||
{{ macros.m_tab_content_start('download', false) }}
|
||||
{{ macros.setting_button_with_info([['global_link_btn', '다운로드', [{'key':'url', 'value':'https://github.com/soju6jan/soju6jan.github.io/blob/master/etc/hdhomerun_scan_191214.zip'}]], ['global_link_btn', '매뉴얼', [{'key':'url', 'value':'.'}]]], left='HDHomerun Scan Tool', desc=['HDHomerun 스캔하여 TVH용 프리셋 파일을 만들어주는 Windows용 프로그램', '8VSB 지원 케이블용']) }}
|
||||
<!--
|
||||
{{ macros.setting_button_with_info([['global_link_btn', '다운로드', [{'key':'url', 'value':'https://github.com/soju6jan/soju6jan.github.io/raw/master/etc/sjva_lc_0.1.1.apk'}]], ['global_link_btn', '매뉴얼', [{'key':'url', 'value':'.'}]]], left='SJVA for Live Channels', desc=['Android TV Live Channels 앱에 채널 소스를 제공하는 앱.', 'Klive, Plex 지원']) }}
|
||||
{{ macros.setting_button_with_info([['global_link_btn', '티빙 애드온', [{'key':'url', 'value':'https://github.com/soju6jan/soju6jan.github.io/blob/master/kodi_plugin/plugin.video.tving.zip'}]]], left='KODI', desc=None) }}
|
||||
-->
|
||||
{{ macros.m_tab_content_end() }}
|
||||
|
||||
</div><!--tab-content-->
|
||||
</div> <!--전체-->
|
||||
|
||||
<!-- 링크 모달 -->
|
||||
{{ macros.m_modal_start('link_edit_modal', '링크', 'modal-lg') }}
|
||||
<form id="link_form">
|
||||
<input type="hidden" id="link_edit_index" name="link_edit_index"/>
|
||||
{{ macros.setting_input_text('link_edit_title', '제목') }}
|
||||
{{ macros.setting_input_text('link_edit_url', 'URL') }}
|
||||
{{ macros.setting_button([['link_edit_confirm_btn', '확인'], ['link_edit_cancel_btn', '취소']]) }}
|
||||
</form>
|
||||
{{ macros.m_modal_end() }}
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
var package_name = 'system';
|
||||
var current_data;
|
||||
var link_data;
|
||||
|
||||
$(document).ready(function(){
|
||||
$(function() {
|
||||
});
|
||||
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/get_link_list',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: {},
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
link_data = data
|
||||
make_link_data();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function setting_save_func(formData, noti) {
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/setting_save_system',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: formData,
|
||||
dataType: "json",
|
||||
success: function (ret) {
|
||||
if (ret) {
|
||||
if (noti) {
|
||||
$.notify('<strong>설정을 저장하였습니다.</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
} else {
|
||||
window.location.href = "/"
|
||||
}
|
||||
} else {
|
||||
$.notify('<strong>설정 저장에 실패하였습니다.</strong>', {
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//설정 저장
|
||||
$("#setting_save").click(function(e) {
|
||||
e.preventDefault();
|
||||
var formData = get_formdata('#setting');
|
||||
setting_save_func(formData, true)
|
||||
});
|
||||
|
||||
//설정 저장
|
||||
$("#setting_save2").click(function(e) {
|
||||
e.preventDefault();
|
||||
var formData = get_formdata('#setting2');
|
||||
setting_save_func(formData, false)
|
||||
});
|
||||
|
||||
$("#setting_save4").click(function(e) {
|
||||
e.preventDefault();
|
||||
var formData = get_formdata('#setting4');
|
||||
setting_save_func(formData, true)
|
||||
});
|
||||
|
||||
$("#setting_save3").click(function(e) {
|
||||
e.preventDefault();
|
||||
var formData = get_formdata('#setting3');
|
||||
setting_save_func(formData, true)
|
||||
$.notify('<strong>재시작해야 적용됩니다.</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$("body").on('click', '#ddns_test_btn', function(e){
|
||||
e.preventDefault();
|
||||
ddns = document.getElementById('ddns').value;
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/ddns_test',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data:{ddns:ddns},
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
console.log(data)
|
||||
if (data == 'fail') {
|
||||
$.notify('<strong>접속에 실패하였습니다.</strong>', {
|
||||
type: 'warning'
|
||||
});
|
||||
} else {
|
||||
$.notify('<strong>Version:'+ data+'</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
$("body").on('click', '#menu_toggle_btn', function(e){
|
||||
e.preventDefault();
|
||||
category = $(this).data('category')
|
||||
var div_name = '#menu_'+category+'_div'
|
||||
$(div_name).collapse('toggle')
|
||||
});
|
||||
|
||||
$("body").on('click', '#command_run_btn', function(e){
|
||||
e.preventDefault();
|
||||
command_text = document.getElementById('command_text').value;
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/command_run',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data:{command_text:command_text},
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
if (data.ret == 'success') {
|
||||
$.notify('<strong>성공 : '+ data.log +'</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
} else {
|
||||
$.notify('<strong>실패 : ' + data.log+'</strong>', {
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// 링크
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// 화면 상단 버튼 START
|
||||
$("body").on('click', '#link_add_btn', function(e){
|
||||
e.preventDefault();
|
||||
document.getElementById("link_edit_index").value = -1;
|
||||
document.getElementById('link_edit_title').value = '';
|
||||
document.getElementById('link_edit_url').value = '';
|
||||
$('#link_edit_modal').modal();
|
||||
});
|
||||
|
||||
$("body").on('click', '#link_add_divider_btn', function(e){
|
||||
e.preventDefault();
|
||||
tmp = {}
|
||||
tmp['type'] = 'divider'
|
||||
link_data.splice(link_data.length, 0, tmp);
|
||||
make_link_data()
|
||||
});
|
||||
|
||||
$("body").on('click', '#link_save_btn', function(e){
|
||||
e.preventDefault();
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/link_save',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data:{link_data:JSON.stringify(link_data)},
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
if (data) {
|
||||
$.notify('<strong>저장 후 적용하였습니다.</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
} else {
|
||||
$.notify('<strong>실패하였습니다.</strong>', {
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("body").on('click', '#link_reset_btn', function(e){
|
||||
e.preventDefault();
|
||||
link_data = []
|
||||
make_link_data()
|
||||
});
|
||||
// 화면 상단 버튼 END
|
||||
|
||||
// 리스트 각 항목 별 버튼 START
|
||||
$("body").on('click', '#link_item_up_btn', function(e){
|
||||
e.preventDefault();
|
||||
target_id = $(this).data('index')
|
||||
target = link_data[target_id]
|
||||
if (target_id != 0) {
|
||||
link_data.splice(target_id, 1);
|
||||
link_data.splice(target_id-1, 0, target);
|
||||
}
|
||||
make_link_data()
|
||||
});
|
||||
|
||||
$("body").on('click', '#link_item_down_btn', function(e){
|
||||
e.preventDefault();
|
||||
target_id = $(this).data('index')
|
||||
target = link_data[target_id]
|
||||
if (link_data.length -1 != target_id) {
|
||||
link_data.splice(target_id, 1);
|
||||
link_data.splice(target_id+1, 0, target);
|
||||
}
|
||||
make_link_data()
|
||||
});
|
||||
|
||||
$("body").on('click', '#link_item_delete_btn', function(e){
|
||||
e.preventDefault();
|
||||
target_id = $(this).data('index')
|
||||
target = link_data[target_id]
|
||||
link_data.splice(target_id, 1);
|
||||
make_link_data()
|
||||
});
|
||||
|
||||
$("body").on('click', '#link_item_edit_btn', function(e){
|
||||
e.preventDefault();
|
||||
target_id = $(this).data('index')
|
||||
target = link_data[target_id]
|
||||
document.getElementById('link_edit_index').value = target_id
|
||||
document.getElementById('link_edit_title').value = target.title
|
||||
document.getElementById('link_edit_url').value = target.url
|
||||
$('#link_edit_modal').modal();
|
||||
});
|
||||
// 리스트 각 항목 별 버튼 END
|
||||
|
||||
// START 모달 버튼
|
||||
$("body").on('click', '#link_edit_confirm_btn', function(e){
|
||||
e.preventDefault();
|
||||
edit_index = parseInt(document.getElementById('link_edit_index').value)
|
||||
tmp = {}
|
||||
tmp['type'] = 'link'
|
||||
tmp['title'] = document.getElementById('link_edit_title').value
|
||||
tmp['url'] = document.getElementById('link_edit_url').value
|
||||
if (edit_index == -1) {
|
||||
link_data.splice(link_data.length, 0, tmp);
|
||||
} else {
|
||||
link_data.splice(target_id, 1);
|
||||
link_data.splice(target_id, 0, tmp);
|
||||
}
|
||||
make_link_data()
|
||||
$('#link_edit_modal').modal('hide');
|
||||
});
|
||||
|
||||
$("body").on('click', '#link_edit_cancel_btn', function(e){
|
||||
e.preventDefault();
|
||||
$('#link_edit_modal').modal('hide');
|
||||
});
|
||||
// END 모달 버튼
|
||||
|
||||
|
||||
|
||||
function make_link_data() {
|
||||
str = ''
|
||||
for (i in link_data) {
|
||||
//console.log(link_data[i])
|
||||
str += m_row_start_hover();
|
||||
str += m_col(1, parseInt(i)+1);
|
||||
|
||||
if (link_data[i].type == 'link') {
|
||||
str += m_col(4, link_data[i].title)
|
||||
str += m_col(4, link_data[i].url)
|
||||
} else {
|
||||
str += m_col(8, '---Divider Line---')
|
||||
}
|
||||
tmp = ''
|
||||
tmp += m_button('link_item_up_btn', 'UP', [{'key':'index', 'value':i}]);
|
||||
tmp += m_button('link_item_down_btn', 'DOWN', [{'key':'index', 'value':i}]);
|
||||
tmp += m_button('link_item_delete_btn', '삭제', [{'key':'index', 'value':i}]);
|
||||
if (link_data[i].type == 'link') {
|
||||
tmp += m_button('link_item_edit_btn', '편집', [{'key':'index', 'value':i}]);
|
||||
tmp += m_button('global_link_btn', 'Go', [{'key':'url', 'value':link_data[i].url}]);
|
||||
}
|
||||
tmp = m_button_group(tmp)
|
||||
str += m_col(3, tmp)
|
||||
str += m_row_end();
|
||||
if (i != link_data.length -1) str += m_hr(0);
|
||||
}
|
||||
document.getElementById("link_list_div").innerHTML = str;
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
$("body").on('click', '#go_filebrowser_btn', function(e){
|
||||
e.preventDefault();
|
||||
url = document.getElementById('url_filebrowser').value
|
||||
window.open(url, "_blank");
|
||||
});
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
136
lib/system/templates/system_setting_basic.html
Normal file
136
lib/system/templates/system_setting_basic.html
Normal file
@@ -0,0 +1,136 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
<div>
|
||||
{{ 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_select('log_level', '로그 레벨', [['10', 'DEBUG'],['20', 'INFO'],['30', 'WARNING'],['40', 'ERROR'], ['50', 'CRITICAL'] ], value=arg['log_level'], col='3') }}
|
||||
{{ macros.m_hr() }}
|
||||
</form>
|
||||
</div><!--전체-->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
$(document).ready(function(){
|
||||
});
|
||||
|
||||
$("body").on('click', '#ddns_test_btn', function(e){
|
||||
e.preventDefault();
|
||||
globalSendCommand('ddns_test', $('#ddns').val());
|
||||
|
||||
ddns = document.getElementById('ddns').value;
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/ddns_test',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data:{ddns:ddns},
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
console.log(data)
|
||||
if (data == 'fail') {
|
||||
$.notify('<strong>접속에 실패하였습니다.</strong>', {
|
||||
type: 'warning'
|
||||
});
|
||||
} else {
|
||||
$.notify('<strong>Version:'+ data+'</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
function setting_save_func(formData, noti) {
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/setting_save_system',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: formData,
|
||||
dataType: "json",
|
||||
success: function (ret) {
|
||||
if (ret) {
|
||||
if (noti) {
|
||||
$.notify('<strong>설정을 저장하였습니다.</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
} else {
|
||||
window.location.href = "/"
|
||||
}
|
||||
} else {
|
||||
$.notify('<strong>설정 저장에 실패하였습니다.</strong>', {
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//설정 저장
|
||||
$("#setting_save").click(function(e) {
|
||||
e.preventDefault();
|
||||
var formData = get_formdata('#setting');
|
||||
setting_save_func(formData, true)
|
||||
});
|
||||
|
||||
//설정 저장
|
||||
$("#setting_save2").click(function(e) {
|
||||
e.preventDefault();
|
||||
var formData = get_formdata('#setting2');
|
||||
setting_save_func(formData, false)
|
||||
});
|
||||
|
||||
$("#setting_save4").click(function(e) {
|
||||
e.preventDefault();
|
||||
var formData = get_formdata('#setting4');
|
||||
setting_save_func(formData, true)
|
||||
});
|
||||
|
||||
$("#setting_save3").click(function(e) {
|
||||
e.preventDefault();
|
||||
var formData = get_formdata('#setting3');
|
||||
setting_save_func(formData, true)
|
||||
$.notify('<strong>재시작해야 적용됩니다.</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$("body").on('click', '#command_run_btn', function(e){
|
||||
e.preventDefault();
|
||||
command_text = document.getElementById('command_text').value;
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/command_run',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data:{command_text:command_text},
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
if (data.ret == 'success') {
|
||||
$.notify('<strong>성공 : '+ data.log +'</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
} else {
|
||||
$.notify('<strong>실패 : ' + data.log+'</strong>', {
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
144
lib/system/templates/system_setting_env.html
Normal file
144
lib/system/templates/system_setting_env.html
Normal file
@@ -0,0 +1,144 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
<div>
|
||||
<nav>
|
||||
{{ macros.m_tab_head_start() }}
|
||||
{{ macros.m_tab_head2('system', '시스템 변수', true) }}
|
||||
{{ macros.m_tab_head2('celery', 'celery 상태', false) }}
|
||||
{{ macros.m_tab_head_end() }}
|
||||
</nav>
|
||||
|
||||
<div class="tab-content" id="nav-tabContent">
|
||||
{{ macros.m_tab_content_start('system', true) }}
|
||||
<form id='setting' name='setting'>
|
||||
{{ macros.setting_input_textarea('export', '환경변수', desc=['',
|
||||
'도커를 재시작하거나 sjva3.sh 스크립트를 재시작해야 적용됩니다.',
|
||||
'구동 환경에 따라 사용하는 변수가 다릅니다.',
|
||||
'',
|
||||
'USE_CELERY : 멀티프로세싱 작업 사용 여부 설정. true or false',
|
||||
'CELERY_WORKER_COUNT : 작업 프로세스 개수.',
|
||||
'USE_GEVENT : 비동기 라이브러리 사용 설정. true or false. 클수록 메모리를 많이 소비하는 대신 더 원할하게 동작', '',
|
||||
'REDIS_PORT : celery에서 사용하는 redis port. 특별한 경우외에는 변경하지 마세요',
|
||||
'SJVA_PORT : 이 변수가 있는 경우 DB값을 무시하고 port로 설정',
|
||||
],
|
||||
value=arg['export'], row='10') }}
|
||||
{{ macros.setting_button([['setting_save_btn', '저장'], ['shutdown_btn', '시스템 종료']]) }}
|
||||
</form>
|
||||
</form>
|
||||
{{ macros.m_tab_content_end() }}
|
||||
|
||||
{{ macros.m_tab_content_start('celery', false) }}
|
||||
{{ macros.setting_button([['celery_test_btn', 'Celery Test'], ['worker_start_btn', '워커 재시작'], ['ps_btn', '프로세스 목록']]) }}
|
||||
|
||||
{{ macros.m_tab_content_end() }}
|
||||
</div><!--tab-content-->
|
||||
</div> <!--전체-->
|
||||
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
var package_name = "{{arg['package_name']}}";
|
||||
var sub = "{{arg['sub'] }}";
|
||||
|
||||
$(document).ready(function(){
|
||||
|
||||
});
|
||||
|
||||
$("body").on('click', '#setting_save_btn', function(e){
|
||||
e.preventDefault();
|
||||
var formData = get_formdata('#setting');
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/' + sub + '/setting_save',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: formData,
|
||||
dataType: "json",
|
||||
success: function (ret) {
|
||||
if (ret) {
|
||||
$.notify('<strong>시스템 변수를 저장하였습니다.</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
} else {
|
||||
$.notify('<strong>시스템 변수 저장에 실패하였습니다.</strong>', {
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
$("body").on('click', '#shutdown_btn', function(e){
|
||||
e.preventDefault();
|
||||
shutdown_confirm();
|
||||
});
|
||||
|
||||
$("body").on('click', '#celery_test_btn', function(e){
|
||||
e.preventDefault();
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/' + sub + '/celery_test',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: {},
|
||||
dataType: "json",
|
||||
success: function (ret) {
|
||||
if (ret.ret == 'success') {
|
||||
$.notify('<strong>'+ ret.data+'</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
} else if (ret.ret == 'timeout' || ret.ret == 'no_celery') {
|
||||
$.notify('<strong>'+ ret.data+'</strong>', {
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
//m_modal(ret)
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$("body").on('click', '#ps_btn', function(e){
|
||||
e.preventDefault();
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/' + sub + '/ps',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: {},
|
||||
dataType: "json",
|
||||
success: function (ret) {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("body").on('click', '#worker_start_btn', function(e){
|
||||
e.preventDefault();
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/' + sub + '/worker_start',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: {},
|
||||
dataType: "json",
|
||||
success: function (ret) {
|
||||
if (ret.ret == 'success') {
|
||||
$.notify('<strong>'+ ret.data+'</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
} else if (ret.ret == 'timeout' || ret.ret == 'no_celery' || ret.ret == 'not_registered') {
|
||||
$.notify('<strong>'+ ret.data+'</strong>', {
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
//m_modal(ret)
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
31
lib/system/templates/system_setting_memo.html
Normal file
31
lib/system/templates/system_setting_memo.html
Normal file
@@ -0,0 +1,31 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
<div>
|
||||
{{ macros.m_button_group([['globalSettingSaveBtn', '설정 저장']])}}
|
||||
{{ macros.m_row_start('5') }}
|
||||
{{ macros.m_row_end() }}
|
||||
<nav>
|
||||
{{ macros.m_tab_head_start() }}
|
||||
{{ macros.m_tab_head2('memo', '메모', true) }}
|
||||
{{ macros.m_tab_head_end() }}
|
||||
</nav>
|
||||
<form id='setting' name='setting'>
|
||||
<div class="tab-content" id="nav-tabContent">
|
||||
{{ macros.m_tab_content_start('memo', true) }}
|
||||
<div>
|
||||
<textarea id="memo" name="memo" class="col-md-12" rows="30" charswidth="23" style="visibility:visible" value="">{{ arg['memo'] }}</textarea>
|
||||
</div>
|
||||
{{ macros.m_tab_content_end() }}
|
||||
</div><!--tab-content-->
|
||||
</form>
|
||||
</div> <!--전체-->
|
||||
|
||||
<script type="text/javascript">
|
||||
var package_name = "{{arg['package_name']}}";
|
||||
var sub = "{{arg['sub'] }}";
|
||||
|
||||
$(document).ready(function(){
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
208
lib/system/templates/system_setting_notify.html
Normal file
208
lib/system/templates/system_setting_notify.html
Normal file
@@ -0,0 +1,208 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
<div>
|
||||
{{ macros.m_button_group([['globalSettingSaveBtn', '설정 저장']])}}
|
||||
{{ macros.m_row_start('5') }}
|
||||
{{ macros.m_row_end() }}
|
||||
<nav>
|
||||
{{ macros.m_tab_head_start() }}
|
||||
{{ macros.m_tab_head2('basic', 'Basic', true) }}
|
||||
{{ macros.m_tab_head2('advanced', 'Advanced', false) }}
|
||||
{{ macros.m_tab_head_end() }}
|
||||
</nav>
|
||||
<form id='setting' name='setting'>
|
||||
<div class="tab-content" id="nav-tabContent">
|
||||
{{ macros.m_tab_content_start('basic', true) }}
|
||||
{{ macros.setting_checkbox('notify_telegram_use', '텔레그램 사용', value=arg['notify_telegram_use']) }}
|
||||
<div id="notify_telegram_use_div" class="collapse">
|
||||
{{ macros.setting_input_text('notify_telegram_token', 'Bot Token', value=arg['notify_telegram_token']) }}
|
||||
{{ macros.setting_input_text('notify_telegram_chat_id', 'My Chat ID', value=arg['notify_telegram_chat_id'], col='3') }}
|
||||
{{ macros.setting_input_text_and_buttons('tmp_text_telegram', 'Test', [['tmp_telegram_test_btn', '전송']], value='테스트 메시지입니다.', col='9', desc=['사용자가 먼저 봇과 대화를 시작하여 대화창이 생성된 상태여야 합니다.', '(대화창이 있을 경우에만 알림 수신)']) }}
|
||||
{{ macros.setting_checkbox('notify_telegram_disable_notification', '알람 Disable', value=arg['notify_telegram_disable_notification'], desc='On : 알람 소리 없이 메시지를 수신합니다.') }}
|
||||
</div>
|
||||
{{ macros.m_hr() }}
|
||||
{{ macros.setting_checkbox('notify_discord_use', '디스코드 사용', value=arg['notify_discord_use']) }}
|
||||
<div id="notify_discord_use_div" class="collapse">
|
||||
{{ 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_tab_content_end() }}
|
||||
|
||||
{{ macros.m_tab_content_start('advanced', false) }}
|
||||
{{ macros.setting_checkbox('notify_advaned_use', '사용', value=arg['notify_advaned_use'], desc=['충분히 내용 숙지하고 사용하세요.', '사용시 기본설정은 무시됩니다.']) }}
|
||||
<div id="notify_advaned_use_div" class="collapse">
|
||||
{{ macros.setting_input_textarea('notify_advaned_policy', '정책', value=arg['notify_advaned_policy'], row='30') }}
|
||||
{{ macros.setting_input_text_and_buttons('tmp_text_advanced', 'Test', [['tmp_advanced_test_btn', '전송']], value='테스트 메시지입니다.', col='9', desc=['메시지 ID = 형식', '형식의 구분자 |', '텔레그램 : bot_token,chat_id | 디스코드 : 웹훅 URL', '예) DEFAULT = 794150118:AAEAAAAAAAAAAAAAAA,186485141|https://discordapp.com/api/webhooks/626295849....', '모든 알림을 텔레그램과 디스코드에 보냄']) }}
|
||||
{{ macros.setting_input_text('tmp_message_id', 'Test Message ID', value='DEFAULT') }}
|
||||
</div>
|
||||
{{ macros.m_tab_content_end() }}
|
||||
|
||||
</div><!--tab-content-->
|
||||
</form>
|
||||
</div> <!--전체-->
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
var package_name = "{{arg['package_name']}}";
|
||||
var sub = "{{arg['sub'] }}";
|
||||
|
||||
$(document).ready(function(){
|
||||
use_collapse("notify_telegram_use");
|
||||
use_collapse("notify_discord_use");
|
||||
use_collapse("notify_advaned_use");
|
||||
});
|
||||
|
||||
$('#notify_telegram_use').change(function() {
|
||||
use_collapse('notify_telegram_use');
|
||||
});
|
||||
|
||||
$('#notify_discord_use').change(function() {
|
||||
use_collapse('notify_discord_use');
|
||||
});
|
||||
|
||||
$('#notify_advaned_use').change(function() {
|
||||
use_collapse('notify_advaned_use');
|
||||
});
|
||||
|
||||
|
||||
$("body").on('click', '#tmp_telegram_test_btn', function(e){
|
||||
e.preventDefault();
|
||||
bot_token = document.getElementById("notify_telegram_token").value;
|
||||
chat_id = document.getElementById("notify_telegram_chat_id").value;
|
||||
text = document.getElementById("tmp_text_telegram").value;
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/'+sub+'/telegram_test',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data:{bot_token:bot_token, chat_id:chat_id, text:text},
|
||||
dataType: "json",
|
||||
success: function (ret) {
|
||||
if (ret) {
|
||||
$.notify('<strong>전송 하였습니다.</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
} else {
|
||||
$.notify('<strong>전송에 실패하였습니다.<br>'+ret+'</strong>', {
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("body").on('click', '#tmp_discord_test_btn', function(e){
|
||||
e.preventDefault();
|
||||
url = document.getElementById("notify_discord_webhook").value;
|
||||
text = document.getElementById("tmp_text_discord").value;
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/'+sub+'/discord_test',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data:{url:url, text:text},
|
||||
dataType: "json",
|
||||
success: function (ret) {
|
||||
if (ret) {
|
||||
$.notify('<strong>전송 하였습니다.</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
} else {
|
||||
$.notify('<strong>전송에 실패하였습니다.<br>'+ret+'</strong>', {
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("body").on('click', '#tmp_advanced_test_btn', function(e){
|
||||
e.preventDefault();
|
||||
policy = document.getElementById("notify_advaned_policy").value;
|
||||
text = document.getElementById("tmp_text_advanced").value;
|
||||
message_id = document.getElementById("tmp_message_id").value;
|
||||
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/'+sub+'/advanced_test',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data:{policy:policy, text:text, message_id:message_id},
|
||||
dataType: "json",
|
||||
success: function (ret) {
|
||||
if (ret) {
|
||||
$.notify('<strong>전송 하였습니다.</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
} else {
|
||||
$.notify('<strong>전송에 실패하였습니다.<br>'+ret+'</strong>', {
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$("body").on('click', '#capture_btn', function(e){
|
||||
e.preventDefault();
|
||||
url = document.getElementById('tmp_go_url').value
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/'+sub+'/capture',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: {url:url},
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
if (data.ret == 'success') {
|
||||
tmp = '<img src="' + data.data + '" class="img-fluid">'
|
||||
document.getElementById("image_div").innerHTML = tmp;
|
||||
} else {
|
||||
$.notify('<strong>실패하였습니다.</strong>', {
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//, ['full_capture_btn', '전체 캡처 이미지 다운']
|
||||
$("body").on('click', '#full_capture_btn', function(e){
|
||||
e.preventDefault();
|
||||
url = document.getElementById('tmp_go_url').value
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/'+sub+'/full_capture',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: {url:url},
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
if (data.ret == 'success') {
|
||||
console.log('xxx')
|
||||
tmp = '<img src="' + data.data + '" class="img-fluid">'
|
||||
document.getElementById("image_div").innerHTML = tmp;
|
||||
} else {
|
||||
$.notify('<strong>실패하였습니다.</strong>', {
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
166
lib/system/templates/system_setting_selenium.html
Normal file
166
lib/system/templates/system_setting_selenium.html
Normal file
@@ -0,0 +1,166 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
<div>
|
||||
{{ macros.m_button_group([['globalSettingSaveBtn', '설정 저장']])}}
|
||||
{{ macros.m_row_start('5') }}
|
||||
{{ macros.m_row_end() }}
|
||||
<nav>
|
||||
{{ macros.m_tab_head_start() }}
|
||||
{{ macros.m_tab_head2('normal', '일반', true) }}
|
||||
{{ macros.m_tab_head2('test', '테스트', false) }}
|
||||
{{ macros.m_tab_head_end() }}
|
||||
</nav>
|
||||
<div class="tab-content" id="nav-tabContent">
|
||||
{{ macros.m_tab_content_start('normal', true) }}
|
||||
<form id='setting' name='setting'>
|
||||
{{ macros.setting_input_text_and_buttons('selenium_remote_url', 'Selenium Remote URL', [['selenium_go_btn', 'GO'], ['selenium_manual_go_btn', '매뉴얼']], value=arg['selenium_remote_url'], placeholder='예) http://127.0.0.1:4444/wd/hub', desc=['SJVA에서 Selenium이 필요한 경우 사용할 Remote URL', 'Docker 환경에서 필요하며, Native 환경에서는 실행파일이 SJVA Root/bin/플랫폼 안에 직접 넣어줘야합니다.', 'Native 환경에서도 이 값을 입력하는 경우는 이를 사용합니다.', 'Selenium 공식 Docker 이미지인 경우 /wd/hub를 붙여야합니다.']) }}
|
||||
{{ macros.setting_input_textarea('selenium_remote_default_option', '기본 크롬 옵션(Remote)', value=arg['selenium_remote_default_option'], row='3', desc=['구분자 | 또는 엔터']) }}
|
||||
{{ macros.setting_input_textarea('selenium_binary_default_option', '기본 크롬 옵션(Binary)', value=arg['selenium_binary_default_option'], row='3', desc=['구분자 | 또는 엔터']) }}
|
||||
</form>
|
||||
{{ macros.m_tab_content_end() }}
|
||||
|
||||
{{ macros.m_tab_content_start('test', false) }}
|
||||
{{ macros.setting_input_text_and_buttons('tmp_go_url', '테스트 URL', [['selenium_test_btn', 'GO'], ['capture_btn', '화면표시'], ['cookie_btn', '쿠키정보']], value='https://search.daum.net/search?w=tv&q=%EB%82%98%EC%81%9C%20%EB%85%80%EC%84%9D%EB%93%A4%20%3A%20%EC%95%85%EC%9D%98%20%EB%8F%84%EC%8B%9C&irk=78543&irt=tv-program&DA=TVP') }}
|
||||
{{ macros.setting_input_text_and_buttons('tmp_daum_capcha', '다음 캡챠', [['tmp_daum_capcha_btn', '캡챠 풀기']], value='') }}
|
||||
<div id="image_div"></div>
|
||||
{{ macros.m_tab_content_end() }}
|
||||
</div><!--tab-content-->
|
||||
</div> <!--전체-->
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
var package_name = "{{arg['package_name']}}";
|
||||
var sub = "{{arg['sub'] }}";
|
||||
|
||||
$(document).ready(function(){
|
||||
});
|
||||
|
||||
$("body").on('click', '#selenium_manual_go_btn', function(e){
|
||||
e.preventDefault();
|
||||
url = "https://soju6jan.com/archives/1380"
|
||||
window.open(url, "_blank");
|
||||
});
|
||||
|
||||
$("body").on('click', '#selenium_go_btn', function(e){
|
||||
e.preventDefault();
|
||||
url = document.getElementById('selenium_remote_url').value
|
||||
window.open(url, "_blank");
|
||||
});
|
||||
|
||||
$("body").on('click', '#selenium_test_btn', function(e){
|
||||
e.preventDefault();
|
||||
url = document.getElementById('tmp_go_url').value
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/'+sub+'/selenium_test_go',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: {url:url},
|
||||
dataType: "json",
|
||||
success: function (ret) {
|
||||
if (ret == 'success') {
|
||||
$.notify('<strong>로딩하였습니다.</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
} else {
|
||||
$.notify('<strong>실패하였습니다.</strong>', {
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("body").on('click', '#capture_btn', function(e){
|
||||
e.preventDefault();
|
||||
url = document.getElementById('tmp_go_url').value
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/'+sub+'/capture',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: {url:url},
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
if (data.ret == 'success') {
|
||||
tmp = '<img src="' + data.data + '" class="img-fluid">'
|
||||
document.getElementById("image_div").innerHTML = tmp;
|
||||
} else {
|
||||
$.notify('<strong>실패하였습니다.</strong>', {
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//, ['full_capture_btn', '전체 캡처 이미지 다운']
|
||||
$("body").on('click', '#full_capture_btn', function(e){
|
||||
e.preventDefault();
|
||||
url = document.getElementById('tmp_go_url').value
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/'+sub+'/full_capture',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: {url:url},
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
if (data.ret == 'success') {
|
||||
console.log('xxx')
|
||||
tmp = '<img src="' + data.data + '" class="img-fluid">'
|
||||
document.getElementById("image_div").innerHTML = tmp;
|
||||
} else {
|
||||
$.notify('<strong>실패하였습니다.</strong>', {
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$("body").on('click', '#cookie_btn', function(e){
|
||||
e.preventDefault();
|
||||
url = document.getElementById('tmp_go_url').value
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/'+sub+'/cookie',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: {url:url},
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
m_modal(data);
|
||||
return;
|
||||
if (data.ret == 'success') {
|
||||
m_modal(data);
|
||||
} else {
|
||||
$.notify('<strong>실패하였습니다.</strong>', {
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("body").on('click', '#tmp_daum_capcha_btn', function(e){
|
||||
e.preventDefault();
|
||||
daum_capcha = document.getElementById('tmp_daum_capcha').value
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/'+sub+'/daum_capcha',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: {daum_capcha:daum_capcha},
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
if (data.ret == 'success') {
|
||||
$.notify('<strong>전달 하였습니다. 페이지 다시 로딩 & 쿠키 정보 확인하여 Site Daum에 입력하세요.</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
179
lib/system/templates/system_setting_site.html
Normal file
179
lib/system/templates/system_setting_site.html
Normal file
@@ -0,0 +1,179 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
<div>
|
||||
{{ macros.m_button_group([['globalSettingSaveBtn', '설정 저장']])}}
|
||||
{{ macros.m_row_start('5') }}
|
||||
{{ macros.m_row_end() }}
|
||||
<nav>
|
||||
{{ macros.m_tab_head_start() }}
|
||||
{{ macros.m_tab_head2('daum', 'Daum', true) }}
|
||||
{{ macros.m_tab_head2('wavve', '웨이브', false) }}
|
||||
{{ macros.m_tab_head2('tving', '티빙', false) }}
|
||||
{{ macros.m_tab_head_end() }}
|
||||
</nav>
|
||||
<form id='setting' name='setting'>
|
||||
<div class="tab-content" id="nav-tabContent">
|
||||
{{ macros.m_tab_content_start('daum', true) }}
|
||||
<!--{{ macros.setting_input_text_and_buttons('site_daum_cookie', 'Cookie', [['site_daum_cookie_btn', 'Refresh']], value=arg['site_daum_cookie'], desc=['지금은 TIARA=값 만 입력하세요', 'Refresh는 Selenium 연결이 가능한 경우만 실행됩니다.']) }}-->
|
||||
{{ macros.setting_input_text('site_daum_cookie', 'Cookie', value=arg['site_daum_cookie'], desc=['TIARA=값 만 입력']) }}
|
||||
{{ macros.setting_input_text('site_daum_proxy', 'Proxy', value=arg['site_daum_proxy']) }}
|
||||
|
||||
{{ macros.m_hr() }}
|
||||
{{ macros.setting_input_text_and_buttons('site_daum_test', 'Test', [['site_daum_test_btn', 'Test']], value=arg['site_daum_test'], desc=['영화 or 방송제목']) }}
|
||||
<!--
|
||||
{{ macros.m_hr() }}
|
||||
{{ macros.info_text('', '자동', value='Cookie 값 자동으로 변경하는 스케쥴링입니다. Selenium 연결이 가능해야 합니다.') }}
|
||||
{{ macros.setting_scheduler_button(arg['scheduler'], arg['is_running']) }}
|
||||
{{ macros.setting_input_text('site_daum_interval', '스케쥴링 실행 정보', value=arg['site_daum_interval'], col='3', desc=['Inverval(minute 단위)이나 Cron 설정']) }}
|
||||
{{ macros.setting_checkbox('site_daum_auto_start', '시작시 자동실행', value=arg['site_daum_auto_start'], desc='On : 시작시 자동으로 스케쥴러에 등록됩니다.') }}
|
||||
-->
|
||||
<!--{{ macros.m_hr() }}
|
||||
{{ macros.info_text_go('site_get_daum_cookie_url', 'Daum Cookie API', value=arg['site_get_daum_cookie_url'], desc=['Plex의 SJ Daum Agent 설정에 이 값을 입력하면 검색 실패시 자동적으로 새로운 쿠키값을 가져옵니다.'] ) }}-->
|
||||
{{ macros.m_tab_content_end() }}
|
||||
{{ macros.m_tab_content_start('wavve', false) }}
|
||||
{{ macros.setting_input_textarea('site_wavve_credential', 'Credential', value=arg['site_wavve_credential'], row='3') }}
|
||||
{{ macros.setting_checkbox('site_wavve_use_proxy', 'Proxy 사용', value=arg['site_wavve_use_proxy'], desc=None) }}
|
||||
<div id="site_wavve_use_proxy_div" class="collapse">
|
||||
{{ macros.setting_input_text('site_wavve_proxy_url', 'Proxy URL', value=arg['site_wavve_proxy_url'], desc=None) }}
|
||||
</div>
|
||||
{{ macros.m_tab_content_end() }}
|
||||
|
||||
{{ macros.m_tab_content_start('tving', false) }}
|
||||
{{ macros.setting_radio('site_tving_login_type', '로그인 타입', ['CJONE', 'TVING'], value=arg['site_tving_login_type']) }}
|
||||
{{ macros.setting_input_text('site_tving_id', 'ID', value=arg['site_tving_id'], col='3') }}
|
||||
{{ macros.setting_input_text_and_buttons('site_tving_pw', '암호', [['site_tving_login_btn', '토큰 가져오기']], value=arg['site_tving_pw'], col='6', type='password') }}
|
||||
{{ macros.setting_input_text_and_buttons('site_tving_token', '토큰', [['site_tving_deviceid_btn', 'DeviceID 목록 가져오기']], value=arg['site_tving_token'], col='8', desc=['계정 정보대신 이 값을 사용합니다.', '이 값을 수동으로 넣는 경우 계정정보를 입력할 필요가 없습니다.', '_tving_token=XXXXXX 형식']) }}
|
||||
{{ macros.setting_input_text('site_tving_deviceid', 'Device ID', value=arg['site_tving_deviceid'], col='3', desc=['model이 PC인 항목의 uuid 값 입력']) }}
|
||||
{{ macros.setting_input_text('site_tving_uuid', 'UUID', value=arg['site_tving_uuid'], col='3', desc=['uuid']) }}
|
||||
{{ macros.setting_checkbox('site_tving_use_proxy', 'Proxy 사용', value=arg['site_tving_use_proxy'], desc=None) }}
|
||||
<div id="site_tving_use_proxy_div" class="collapse">
|
||||
{{ macros.setting_input_text('site_tving_proxy_url', 'Proxy URL', value=arg['site_tving_proxy_url'], desc=None) }}
|
||||
</div>
|
||||
{{ macros.m_tab_content_end() }}
|
||||
|
||||
</div><!--tab-content-->
|
||||
</form>
|
||||
</div> <!--전체-->
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
var package_name = "{{arg['package_name']}}";
|
||||
var sub = "{{arg['sub'] }}";
|
||||
|
||||
$(document).ready(function(){
|
||||
use_collapse("site_wavve_use_proxy");
|
||||
use_collapse("site_tving_use_proxy");
|
||||
});
|
||||
|
||||
$('#site_wavve_use_proxy').change(function() {
|
||||
use_collapse('site_wavve_use_proxy');
|
||||
});
|
||||
$('#site_tving_use_proxy').change(function() {
|
||||
use_collapse('site_tving_use_proxy');
|
||||
});
|
||||
|
||||
|
||||
$("body").on('click', '#site_daum_test_btn', function(e){
|
||||
e.preventDefault();
|
||||
site_daum_test = document.getElementById("site_daum_test").value;
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/'+sub+'/site_daum_test',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data:{site_daum_test:site_daum_test},
|
||||
dataType: "json",
|
||||
success: function (ret) {
|
||||
m_modal(ret);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$("body").on('click', '#site_daum_cookie_btn', function(e){
|
||||
e.preventDefault();
|
||||
$.notify('<strong>잠시 기다려 주세요</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/'+sub+'/site_daum_cookie_refresh',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data:{},
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
if (data.ret) {
|
||||
document.getElementById("site_daum_cookie").value = data.data
|
||||
$.notify('<strong>갱신하였습니다. 저장버튼을 눌러야 적용됩니다.</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
} else {
|
||||
$.notify('<strong>갱신에 실패하였습니다. Selenium 설정을 확인하세요.<br>'+ret.log+'</strong>', {
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$("body").on('change', '#scheduler', function(e){
|
||||
var ret = $(this).prop('checked');
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/'+sub+'/scheduler',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: {scheduler : ret},
|
||||
dataType: "json",
|
||||
success: function (list) {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// 티빙
|
||||
$("body").on('click', '#site_tving_login_btn', function(e) {
|
||||
e.preventDefault();
|
||||
tving_id = document.getElementById("site_tving_id").value;
|
||||
tving_pw = document.getElementById("site_tving_pw").value;
|
||||
tving_login_type = ($("#site_tving_login_type0").prop('checked')) ? '0' : '1';
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/' + sub + '/tving_login',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: {tving_id:tving_id, tving_pw:tving_pw, tving_login_type:tving_login_type},
|
||||
dataType: "json",
|
||||
success: function (ret) {
|
||||
if (ret.ret) {
|
||||
notify("토큰값을 가져왔습니다.<br>저장버튼을 눌러야 값을 저장합니다.", "success");
|
||||
document.getElementById("site_tving_token").value = ret['token'];
|
||||
} else {
|
||||
notify("로그인에 실패하였습니다.", "warning");
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("body").on('click', '#site_tving_deviceid_btn', function(e) {
|
||||
e.preventDefault();
|
||||
tving_token = document.getElementById("site_tving_token").value;
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/' + sub + '/tving_deviceid',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: {tving_token:tving_token},
|
||||
dataType: "json",
|
||||
success: function (ret) {
|
||||
if (ret.ret) {
|
||||
m_modal(ret.device_list, "Device ID");
|
||||
} else {
|
||||
notify("실패하였습니다.", "warning");
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
85
lib/system/templates/system_setting_telegram_bot.html
Normal file
85
lib/system/templates/system_setting_telegram_bot.html
Normal file
@@ -0,0 +1,85 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
<div>
|
||||
{{ macros.m_button_group([['globalSettingSaveBtn', '설정 저장']])}}
|
||||
{{ macros.m_row_start('5') }}
|
||||
{{ macros.m_row_end() }}
|
||||
<nav>
|
||||
{{ macros.m_tab_head_start() }}
|
||||
{{ macros.m_tab_head2('normal', '일반', true) }}
|
||||
{{ macros.m_tab_head_end() }}
|
||||
</nav>
|
||||
<form id='setting' name='setting'>
|
||||
<div class="tab-content" id="nav-tabContent">
|
||||
{{ macros.m_tab_content_start('normal', true) }}
|
||||
{{ macros.setting_scheduler_button(arg['scheduler'], arg['is_running']) }}
|
||||
{{ macros.setting_checkbox('telegram_bot_auto_start', '시작시 자동실행', value=arg['telegram_bot_auto_start'], desc='On : 시작시 자동으로 스케쥴러에 등록됩니다.') }}
|
||||
{{ macros.setting_input_text('telegram_bot_token', 'Bot Token', value=arg['telegram_bot_token']) }}
|
||||
|
||||
{{ macros.setting_checkbox('telegram_resend', '전달 사용', value=arg['telegram_resend'], desc=['On : 수신 받은 데이터를 전달합니다.']) }}
|
||||
<div id="telegram_resend_div" class="collapse">
|
||||
{{ macros.setting_input_textarea('telegram_resend_chat_id', '수신 받을 Chat ID', value=arg['telegram_resend_chat_id'], row='3', desc=['받은 메시지를 보낼 Chat ID', 'Chat ID 별 구분자 | 또는 엔터']) }}
|
||||
</div>
|
||||
<!--
|
||||
{{ macros.m_hr() }}
|
||||
{{ macros.setting_button([['open_url1_btn', 'BotFather'], ['open_url2_btn', 'SJVA Bot Channel'], ['open_url3_btn', 'SJVA Bot Channel 관리 봇']]) }}
|
||||
-->
|
||||
{{ macros.m_tab_content_end() }}
|
||||
</div><!--tab-content-->
|
||||
</form>
|
||||
</div> <!--전체-->
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
var package_name = "{{arg['package_name']}}";
|
||||
var sub = "{{arg['sub'] }}";
|
||||
|
||||
|
||||
$(document).ready(function(){
|
||||
use_collapse("telegram_resend");
|
||||
});
|
||||
|
||||
$('#telegram_resend').change(function() {
|
||||
use_collapse('telegram_resend');
|
||||
});
|
||||
|
||||
$("body").on('change', '#scheduler', function(e){
|
||||
var ret = $(this).prop('checked');
|
||||
if (!ret) {
|
||||
$.notify('<strong>텔레그램 봇은 중단 할 수 없습니다.</strong>', {
|
||||
type: 'warning'
|
||||
});
|
||||
$('#scheduler').bootstrapToggle('on')
|
||||
return
|
||||
}
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/'+sub+'/scheduler',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: {scheduler : ret},
|
||||
dataType: "json",
|
||||
success: function (list) {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("body").on('click', '#open_url1_btn', function(e){
|
||||
e.preventDefault();
|
||||
window.open("https://t.me/BotFather", "_blank");
|
||||
});
|
||||
|
||||
$("body").on('click', '#open_url2_btn', function(e){
|
||||
e.preventDefault();
|
||||
window.open("https://t.me/sjva_bot_channel", "_blank");
|
||||
});
|
||||
|
||||
$("body").on('click', '#open_url3_btn', function(e){
|
||||
e.preventDefault();
|
||||
window.open("https://t.me/sjva_admin_bot", "_blank");
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
112
lib/system/templates/system_setting_terminal.html
Normal file
112
lib/system/templates/system_setting_terminal.html
Normal file
@@ -0,0 +1,112 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
{{ macros.m_button_group([['yaml_edit_btn', '편집'], ['terminal_open_btn', 'Terminal 실행'], ['all_append_files_show_btn', '모두 확장'], ['all_append_files_hide_btn', '모두 축소']])}}
|
||||
{{ macros.m_row_start('5') }}
|
||||
{{ macros.m_row_end() }}
|
||||
{{ macros.m_hr_head_bottom() }}
|
||||
<div id="list_div"></div>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
var package_name = "{{arg['package_name']}}";
|
||||
var sub = "{{arg['sub']}}";
|
||||
var yaml_path = "{{arg['yaml_path']}}";
|
||||
var current_data = null;
|
||||
|
||||
$(document).ready(function(){
|
||||
reqeust_info();
|
||||
});
|
||||
|
||||
function reqeust_info() {
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/'+sub+'/get_info',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data:{},
|
||||
dataType: "json",
|
||||
success: function (ret) {
|
||||
make_list(ret);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function make_list(data) {
|
||||
current_data = data;
|
||||
data = data.commands;
|
||||
str = '';
|
||||
str = '<table id="result_table" class="table table-sm tableRowHover " ><thead class="thead-dark"><tr> \
|
||||
<th style="width:10%; text-align:center;">INDEX</th> \
|
||||
<th style="width:80%; text-align:left;">제목</th> \
|
||||
<th style="width:10%; text-align:center;">실행</th> \
|
||||
</tr></thead><tbody id="list">';
|
||||
|
||||
if (data.length == 0) str += '<tr><td colspan="3"><h4>명령이 없습니다.</h4></td></tr>';
|
||||
|
||||
for(i in data) {
|
||||
console.log(data[i]);
|
||||
str += '<tr class="chover" style="cursor: pointer;" data-toggle="collapse" data-target="#collapse_' + i + '" aria-expanded="true" >';
|
||||
str += '<td scope="col" style="width:10%; text-align:center;">'+ (parseInt(i)+1) + '</td>';
|
||||
str += '<td scope="col" style="width:80%; text-align:left;">'+ data[i].title + '</td>';
|
||||
tmp = m_button('terminal_open_btn', '실행', [{'key':'index', 'value':i}]);
|
||||
str += '<td scope="col" style="width:10%; text-align:center;">'+ tmp + '</td>';
|
||||
|
||||
str += '</tr>';
|
||||
|
||||
str += '<tr class="collapse tableRowHoverOff" style="cursor: pointer;" id="collapse_' + i + '">';
|
||||
str += '<td></td><td colspan="2">';
|
||||
str += "<pre>"+data[i].command+"</pre>";
|
||||
|
||||
str += '</td>';
|
||||
str += '</tr>'
|
||||
|
||||
}
|
||||
str += '</table>';
|
||||
document.getElementById("list_div").innerHTML = str;
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
$("body").on('click', '#yaml_edit_btn', function(e){
|
||||
url = '/flaskcode' + yaml_path;
|
||||
window.open(url, '_blank')
|
||||
});
|
||||
|
||||
|
||||
|
||||
$("body").on('click', '#terminal_open_btn', function(e){
|
||||
e.preventDefault();
|
||||
index = $(this).data('index');
|
||||
console.log(index);
|
||||
if (index == null) {
|
||||
window.open("/terminal", "_blank");
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/' + sub + '/run',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: {index:index},
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
if (data.ret == 'success') {
|
||||
window.open("/terminal", "_blank");
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$("body").on('click', '#all_append_files_show_btn', function(e){
|
||||
e.preventDefault();
|
||||
$('.collapse').collapse('show');
|
||||
|
||||
});
|
||||
|
||||
$("body").on('click', '#all_append_files_hide_btn', function(e){
|
||||
e.preventDefault();
|
||||
$('.collapse').collapse('hide');
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
21
lib/system/templates/system_setting_web.html
Normal file
21
lib/system/templates/system_setting_web.html
Normal file
@@ -0,0 +1,21 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div>
|
||||
{{ macros.m_button_group([['globalSettingSaveBtn', '설정 저장']])}}
|
||||
{{ macros.m_row_start('5') }}
|
||||
{{ macros.m_row_end() }}
|
||||
{{ macros.m_hr() }}
|
||||
|
||||
<form id='setting' name='setting'>
|
||||
{{ macros.setting_select('theme', '테마 선택', [['Default','Default'], ['Cerulean','Cerulean'], ['Cosmo','Cosmo'], ['Cyborg','Cyborg'], ['Darkly','Darkly'], ['Flatly','Flatly'], ['Journal','Journal'], ['Litera','Litera'], ['Lumen','Lumen'], ['Lux','Lux'], ['Materia','Materia'], ['Minty','Minty'], ['Morph','Morph'],['Pulse','Pulse'], ['Quartz','Quartz'], ['Sandstone','Sandstone'], ['Simplex','Simplex'], ['Sketchy','Sketchy'], ['Slate','Slate'], ['Solar','Solar'], ['Spacelab','Spacelab'], ['Superhero','Superhero'], ['United','United'], ['Vapor','Vapor'], ['Yeti','Yeti'], ['Zephyr','Zephyr']], value=arg['theme'], desc=None, col='6') }}
|
||||
{{ macros.info_text_go('', '테마 제공', 'https://bootswatch.com')}}
|
||||
{{ macros.setting_input_text('web_title', '웹 타이틀', value=arg['web_title']) }}
|
||||
|
||||
{{ macros.m_hr() }}
|
||||
</form>
|
||||
</div> <!--전체-->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
135
lib/system/templates/system_telegram_setting.html
Normal file
135
lib/system/templates/system_telegram_setting.html
Normal file
@@ -0,0 +1,135 @@
|
||||
{% extends "base.html" %}
|
||||
{% block wide_menu %}
|
||||
<ul class="nav nav-pills bg-light shadow text-dark" >
|
||||
<li class="nav-item"><span class="nav-link">시스템</span></li>
|
||||
<li class="nav-item"><a class="nav-link " href="/system/setting">설정</a></li>
|
||||
<li class="nav-item"><a class="nav-link active" href="/system/telegram">텔레그램 봇</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="/system/plugin">저장된 TV</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="/system/common">로그 확인</a></li>
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div>
|
||||
{{ macros.setting_scheduler_button(arg['is_include'], arg['is_running']) }}
|
||||
<form id='setting' name='setting'>
|
||||
{{ macros.setting_checkbox('telegram_auto_start', '시작시 자동실행', value=arg['auto_start'], desc='On : 시작시 자동으로 스케쥴러에 등록됩니다.') }}
|
||||
{{ macros.setting_checkbox('telegram_process_rss', '토렌트', value=arg['process_rss'], desc='On : 토렌트 데이터를 수신하여 저장') }}
|
||||
<div id="process_rss_div" class="collapse">
|
||||
{{ macros.setting_input_text('telegram_process_rss_type', '수신 타입', value=arg['process_rss_type'], desc=['all인 경우 모두 받음. 구분자 ,', 'TV : drama, ent, dacu, etc', '영화 : movie', 'AV : av_censored, av_uncensored, av_west', '기타 : music, user' ]) }}
|
||||
</div>
|
||||
{{ macros.setting_checkbox('telegram_send_notify', '수신정보 알림', value=arg['send_notify'], desc='On : On 상태인 데이터가 수신될 때 알림.') }}
|
||||
{{ macros.setting_checkbox('telegram_disable_notification', '알람 Disable', value=arg['disable_notification'], desc='On : 알람 소리 없이 메시지를 수신합니다.') }}
|
||||
{{ macros.m_hr() }}
|
||||
{{ macros.setting_input_text('telegram_bot_token', 'Bot Token', value=arg['bot_token']) }}
|
||||
{{ macros.setting_input_text_and_buttons('telegram_chat_id', 'My Chat ID', [['test_btn', '테스트']], value=arg['chat_id'], col='9', desc=['사용자가 먼저 봇과 대화를 시작하여야 합니다.', '(대화창이 있을 경우에만 알림 수신)']) }}
|
||||
{{ macros.setting_button([['globalSettingSaveBtn', '저장']]) }}
|
||||
</form>
|
||||
{{ macros.m_hr() }}
|
||||
{{ macros.setting_button([['open_url1_btn', 'BotFather'], ['open_url2_btn', 'SJVA Bot Channel'], ['open_url3_btn', 'SJVA Bot Channel 관리 봇']]) }}
|
||||
</div> <!--전체-->
|
||||
|
||||
<script type="text/javascript">
|
||||
var package_name = 'system';
|
||||
var current_data = null;
|
||||
|
||||
$(document).ready(function(){
|
||||
use_collapse("telegram_process_rss")
|
||||
});
|
||||
|
||||
|
||||
|
||||
$('#telegram_process_rss').change(function() {
|
||||
use_collapse('telegram_process_rss');
|
||||
});
|
||||
// 스케쥴링 on / off
|
||||
$('#scheduler').change(function() {
|
||||
var ret = $(this).prop('checked');
|
||||
if (!ret) {
|
||||
$.notify('<strong>텔레그램 봇은 중단 할 수 없습니다.</strong>', {
|
||||
type: 'warning'
|
||||
});
|
||||
$('#scheduler').bootstrapToggle('on')
|
||||
return
|
||||
}
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/scheduler',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: {scheduler : ret},
|
||||
dataType: "json",
|
||||
success: function (list) {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// 서버 목록
|
||||
$("body").on('click', '#test_btn', function(e){
|
||||
e.preventDefault();
|
||||
bot_token = document.getElementById("bot_token").value;
|
||||
chat_id = document.getElementById("chat_id").value;
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/test',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data:{bot_token:bot_token, chat_id:chat_id},
|
||||
dataType: "json",
|
||||
success: function (ret) {
|
||||
if (ret == 'success') {
|
||||
$.notify('<strong>전송 하였습니다.</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
} else {
|
||||
$.notify('<strong>전송에 실패하였습니다.<br>'+ret+'</strong>', {
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//설정 저장
|
||||
$("#setting_save_btn").click(function(e) {
|
||||
e.preventDefault();
|
||||
var formData = get_formdata('#setting');
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/setting_save',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: formData,
|
||||
dataType: "json",
|
||||
success: function (ret) {
|
||||
if (ret) {
|
||||
$.notify('<strong>설정을 저장하였습니다.</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
} else {
|
||||
$.notify('<strong>설정 저장에 실패하였습니다.</strong>', {
|
||||
type: 'warning'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("body").on('click', '#open_url1_btn', function(e){
|
||||
e.preventDefault();
|
||||
window.open("https://t.me/BotFather", "_blank");
|
||||
});
|
||||
|
||||
$("body").on('click', '#open_url2_btn', function(e){
|
||||
e.preventDefault();
|
||||
window.open("{{arg['bot_channel_url']}}", "_blank");
|
||||
});
|
||||
|
||||
$("body").on('click', '#open_url3_btn', function(e){
|
||||
e.preventDefault();
|
||||
window.open("https://t.me/sjva_admin_bot", "_blank");
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
76
lib/system/templates/system_tool_crypt.html
Normal file
76
lib/system/templates/system_tool_crypt.html
Normal file
@@ -0,0 +1,76 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div>
|
||||
{{ macros.m_button_group([['globalSettingSaveBtn', '설정 저장']])}}
|
||||
{{ macros.m_row_start('5') }}
|
||||
{{ macros.m_row_end() }}
|
||||
<nav>
|
||||
{{ macros.m_tab_head_start() }}
|
||||
{{ macros.m_tab_head2('normal', '일반', true) }}
|
||||
|
||||
{{ macros.m_tab_head_end() }}
|
||||
</nav>
|
||||
<form id='setting' name='setting'>
|
||||
<div class="tab-content" id="nav-tabContent">
|
||||
{{ macros.m_tab_content_start('normal', true) }}
|
||||
{{ macros.setting_checkbox('tool_crypt_use_user_key', '암호화 키 본인키 사용', value=arg['tool_crypt_use_user_key'], desc=['On : 본인 키 사용', 'Off : SJVA 고정 키 사용']) }}
|
||||
<div id="tool_crypt_use_user_key_div" class="collapse">
|
||||
{{ macros.setting_input_text('tool_crypt_user_key', '암호화 키', value=arg['tool_crypt_user_key'], desc=['16진수(숫자, a~e)로 이루어진 32글자. 미만시 앞을 0으로 채움. 초과시 뒤에 무시']) }}
|
||||
</div>
|
||||
|
||||
{{ macros.setting_input_text_and_buttons('tool_crypt_encrypt_word', '암호화', [['tool_crypt_encrypt_word_btn', '암호화']], value=arg['tool_crypt_encrypt_word']) }}
|
||||
{{ macros.setting_input_text('tool_crypt_encrypt_word_result', '', disabled=True) }}
|
||||
|
||||
{{ macros.setting_input_text_and_buttons('tool_crypt_decrypt_word', '평문화', [['tool_crypt_decrypt_word_btn', '평문화']], value=arg['tool_crypt_decrypt_word']) }}
|
||||
{{ macros.setting_input_text('tool_crypt_decrypt_word_result', '', disabled=True) }}
|
||||
{{ macros.m_tab_content_end() }}
|
||||
|
||||
</div><!--tab-content-->
|
||||
</form>
|
||||
</div> <!--전체-->
|
||||
|
||||
<script type="text/javascript">
|
||||
var package_name = "{{arg['package_name'] }}";
|
||||
var sub = "{{arg['sub'] }}";
|
||||
|
||||
$(document).ready(function(){
|
||||
use_collapse("tool_crypt_use_user_key");
|
||||
});
|
||||
|
||||
$("body").on('change', '#tool_crypt_use_user_key', function(e){
|
||||
use_collapse('tool_crypt_use_user_key');
|
||||
});
|
||||
|
||||
$("body").on('click', '#tool_crypt_encrypt_word_btn', function(e) {
|
||||
e.preventDefault();
|
||||
word = document.getElementById("tool_crypt_encrypt_word").value
|
||||
crypt_test('encrypt', word);
|
||||
});
|
||||
|
||||
$("body").on('click', '#tool_crypt_decrypt_word_btn', function(e) {
|
||||
e.preventDefault();
|
||||
word = document.getElementById("tool_crypt_decrypt_word").value
|
||||
crypt_test('decrypt', word);
|
||||
});
|
||||
|
||||
function crypt_test(mode, word) {
|
||||
$.ajax({
|
||||
url: '/' + package_name + '/ajax/'+sub+'/crypt_test',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: {mode:mode, word:word},
|
||||
dataType: "json",
|
||||
success: function (ret) {
|
||||
if (ret.ret == 'success') {
|
||||
if (mode == "encrypt")
|
||||
document.getElementById("tool_crypt_encrypt_word_result").value = ret.data;
|
||||
else
|
||||
document.getElementById("tool_crypt_decrypt_word_result").value = ret.data;
|
||||
} else {
|
||||
notify(ret.log, 'warning');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user