linkkf 로직수정중
This commit is contained in:
BIN
lib/framework/.DS_Store
vendored
Normal file
BIN
lib/framework/.DS_Store
vendored
Normal file
Binary file not shown.
@@ -1,25 +1,70 @@
|
||||
try:
|
||||
import yaml
|
||||
except:
|
||||
import os
|
||||
try:
|
||||
os.system("pip install pyyaml")
|
||||
except:
|
||||
pass
|
||||
|
||||
from .init_main import Framework
|
||||
from .version import VERSION
|
||||
|
||||
frame = Framework.get_instance()
|
||||
F = frame
|
||||
logger = frame.logger
|
||||
app = frame.app
|
||||
celery = frame.celery
|
||||
db = frame.db
|
||||
scheduler = frame.scheduler
|
||||
socketio = frame.socketio
|
||||
path_app_root = frame.path_app_root
|
||||
path_data = frame.path_data
|
||||
get_logger = frame.get_logger
|
||||
# 2024.06.13
|
||||
# 잘못된 설계로 인해 import 만으로 초기화 되버려 lib을 사용할 수 없다.
|
||||
# 분리.
|
||||
|
||||
F = None
|
||||
frame = None
|
||||
logger = None
|
||||
app = None
|
||||
celery = None
|
||||
db = None
|
||||
scheduler = None
|
||||
socketio = None
|
||||
rd = None
|
||||
path_app_root = None
|
||||
path_data = None
|
||||
get_logger = None
|
||||
SystemModelSetting = None
|
||||
get_cache = None
|
||||
|
||||
def initiaize():
|
||||
global F
|
||||
global frame
|
||||
global logger
|
||||
global app
|
||||
global celery
|
||||
global db
|
||||
global scheduler
|
||||
global socketio
|
||||
global path_app_root
|
||||
global path_data
|
||||
global get_logger
|
||||
global SystemModelSetting
|
||||
global get_cache
|
||||
|
||||
F = Framework.get_instance()
|
||||
frame = F
|
||||
logger = frame.logger
|
||||
app = frame.app
|
||||
celery = frame.celery
|
||||
db = frame.db
|
||||
scheduler = frame.scheduler
|
||||
socketio = frame.socketio
|
||||
rd = frame.rd
|
||||
path_app_root = frame.path_app_root
|
||||
path_data = frame.path_data
|
||||
get_logger = frame.get_logger
|
||||
|
||||
frame.initialize_system()
|
||||
from system.setup import SystemModelSetting as SS
|
||||
SystemModelSetting = SS
|
||||
frame.initialize_plugin()
|
||||
return frame
|
||||
|
||||
from flask_login import login_required
|
||||
from support import d
|
||||
|
||||
from .init_declare import User, check_api
|
||||
from .scheduler import Job
|
||||
|
||||
frame.initialize_system()
|
||||
from system.setup import SystemModelSetting
|
||||
|
||||
frame.initialize_plugin()
|
||||
|
||||
73
lib/framework/init_cache_manager.py
Normal file
73
lib/framework/init_cache_manager.py
Normal file
@@ -0,0 +1,73 @@
|
||||
import redis
|
||||
|
||||
class _RedisManager:
|
||||
_instance = None
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if not cls._instance:
|
||||
cls._instance = super().__new__(cls)
|
||||
return cls._instance
|
||||
|
||||
def __init__(self, host='localhost', port=6379):
|
||||
if hasattr(self, 'redis_client'):
|
||||
return
|
||||
|
||||
try:
|
||||
self.redis_client = redis.Redis(host=host, port=port, db=1, decode_responses=True)
|
||||
self.redis_client.ping()
|
||||
self.is_redis = True
|
||||
except redis.exceptions.ConnectionError:
|
||||
self.is_redis = False
|
||||
self.cache_backend = {} # Redis 실패 시 메모리 캐시 사용
|
||||
|
||||
def set(self, key, value, ex=None):
|
||||
if self.is_redis:
|
||||
self.redis_client.set(key, value, ex=ex)
|
||||
else:
|
||||
self.cache_backend[key] = value
|
||||
|
||||
def get(self, key):
|
||||
if self.is_redis:
|
||||
return self.redis_client.get(key)
|
||||
else:
|
||||
return self.cache_backend.get(key)
|
||||
|
||||
def delete(self, key):
|
||||
if self.is_redis:
|
||||
self.redis_client.delete(key)
|
||||
else:
|
||||
if key in self.cache_backend:
|
||||
del self.cache_backend[key]
|
||||
|
||||
|
||||
#_redis_manager_instance = _RedisManager()
|
||||
|
||||
class NamespacedCache:
|
||||
def __init__(self, namespace):
|
||||
self._manager = _RedisManager._instance
|
||||
self.namespace = namespace
|
||||
|
||||
def _make_key(self, key):
|
||||
# 'plugin_name:key' 형식으로 실제 키를 생성
|
||||
return f"{self.namespace}:{key}"
|
||||
|
||||
def set(self, key, value, ex=None):
|
||||
full_key = self._make_key(key)
|
||||
self._manager.set(full_key, value, ex=ex)
|
||||
|
||||
def get(self, key):
|
||||
full_key = self._make_key(key)
|
||||
return self._manager.get(full_key)
|
||||
|
||||
def delete(self, key):
|
||||
full_key = self._make_key(key)
|
||||
self._manager.delete(full_key)
|
||||
|
||||
|
||||
def get_cache(plugin_name: str) -> NamespacedCache:
|
||||
"""
|
||||
플러그인 이름을 기반으로 네임스페이스가 적용된 캐시 객체를 반환합니다.
|
||||
"""
|
||||
if not plugin_name:
|
||||
raise ValueError("플러그인 이름은 필수입니다.")
|
||||
return NamespacedCache(plugin_name)
|
||||
@@ -13,13 +13,13 @@ def check_api(original_function):
|
||||
#logger.warning(request.url)
|
||||
#logger.warning(request.form)
|
||||
try:
|
||||
if F.SystemModelSetting.get_bool('auth_use_apikey'):
|
||||
if request.method == 'POST':
|
||||
apikey = request.form['apikey']
|
||||
else:
|
||||
apikey = request.args.get('apikey')
|
||||
#apikey = request.args.get('apikey')
|
||||
if apikey is None or apikey != F.SystemModelSetting.get('auth_apikey'):
|
||||
if F.SystemModelSetting.get_bool('use_apikey'):
|
||||
try:
|
||||
d = request.get_json()
|
||||
except Exception:
|
||||
d = request.form.to_dict() if request.method == 'POST' else request.args.to_dict()
|
||||
apikey = d.get('apikey')
|
||||
if apikey is None or apikey != F.SystemModelSetting.get('apikey'):
|
||||
F.logger.warning('CHECK API : ABORT no match ({})'.format(apikey))
|
||||
F.logger.warning(request.environ.get('HTTP_X_REAL_IP', request.remote_addr))
|
||||
abort(403)
|
||||
@@ -31,7 +31,7 @@ def check_api(original_function):
|
||||
return original_function(*args, **kwargs) #2
|
||||
return wrapper_function
|
||||
|
||||
# Suuport를 logger 생성전에 쓰지 않기 위해 중복 선언
|
||||
# Support를 logger 생성전에 쓰지 않기 위해 중복 선언
|
||||
import logging
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ class CustomFormatter(logging.Formatter):
|
||||
# pathname filename
|
||||
#format = "[%(asctime)s|%(name)s|%(levelname)s - %(message)s (%(filename)s:%(lineno)d)"
|
||||
|
||||
__format = '[{yellow}%(asctime)s{reset}|{color}%(levelname)s{reset}|{green}%(name)s{reset} %(pathname)s:%(lineno)s] {color}%(message)s{reset}' if os.environ.get('LOGGER_PATHNAME', "False") == "True" else '[{yellow}%(asctime)s{reset}|{color}%(levelname)s{reset}|{green}%(name)s{reset} %(filename)s:%(lineno)s] {color}%(message)s{reset}'
|
||||
__format = '[{yellow}%(asctime)s{reset}|{color}%(levelname)s{reset}|{green}%(name)s{reset}|%(pathname)s:%(lineno)s] {color}%(message)s{reset}' if os.environ.get('LOGGER_PATHNAME', "False") == "True" else '[{yellow}%(asctime)s{reset}|{color}%(levelname)s{reset}|{green}%(name)s{reset}|%(filename)s:%(lineno)s] {color}%(message)s{reset}'
|
||||
|
||||
FORMATS = {
|
||||
logging.DEBUG: __format.format(color=grey, reset=reset, yellow=yellow, green=green),
|
||||
|
||||
@@ -8,14 +8,15 @@ import time
|
||||
import traceback
|
||||
from datetime import datetime
|
||||
|
||||
import redis
|
||||
import yaml
|
||||
from flask import Flask
|
||||
from flask_cors import CORS
|
||||
from flask_login import LoginManager, login_required
|
||||
from flask_socketio import SocketIO
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
from flaskext.markdown import Markdown
|
||||
from pytz import timezone, utc
|
||||
from werkzeug.middleware.proxy_fix import ProxyFix
|
||||
|
||||
from .init_declare import CustomFormatter, check_api
|
||||
|
||||
@@ -37,12 +38,15 @@ class Framework:
|
||||
self.db = None
|
||||
self.scheduler = None
|
||||
self.socketio = None
|
||||
self.rd = None
|
||||
self.path_app_root = None
|
||||
self.path_data = None
|
||||
self.users = {}
|
||||
self.get_cache = None
|
||||
|
||||
self.__level_unset_logger_list = []
|
||||
self.__logger_list = []
|
||||
self.all_log_filehandler = None
|
||||
self.__exit_code = -1
|
||||
self.login_manager = None
|
||||
#self.plugin_instance_list = {}
|
||||
@@ -59,14 +63,17 @@ class Framework:
|
||||
def __initialize(self):
|
||||
os.environ["PYTHONUNBUFFERED"] = "1"
|
||||
os.environ['FF'] = "true"
|
||||
os.environ['FF_PYTHON'] = sys.executable
|
||||
self.__config_initialize("first")
|
||||
self.__make_default_dir()
|
||||
|
||||
self.logger = self.get_logger(__package__)
|
||||
self.get_logger('support')
|
||||
import support
|
||||
|
||||
self.__prepare_starting()
|
||||
self.app = Flask(__name__)
|
||||
self.app.wsgi_app = ProxyFix(self.app.wsgi_app, x_proto=1)
|
||||
self.__config_initialize('flask')
|
||||
|
||||
self.__init_db()
|
||||
@@ -82,7 +89,6 @@ class Framework:
|
||||
self.socketio = SocketIO(self.app, cors_allowed_origins="*", async_mode='threading')
|
||||
|
||||
CORS(self.app)
|
||||
Markdown(self.app)
|
||||
|
||||
self.login_manager = LoginManager()
|
||||
self.login_manager.init_app(self.app)
|
||||
@@ -94,10 +100,11 @@ class Framework:
|
||||
self.app.config.update(
|
||||
DROPZONE_MAX_FILE_SIZE = 102400,
|
||||
DROPZONE_TIMEOUT = 5*60*1000,
|
||||
#DROPZONE_ALLOWED_FILE_CUSTOM = True,
|
||||
#DROPZONE_ALLOWED_FILE_TYPE = 'default, image, audio, video, text, app, *.*',
|
||||
DROPZONE_ALLOWED_FILE_CUSTOM = True,
|
||||
DROPZONE_ALLOWED_FILE_TYPE = "image/*, audio/*, video/*, text/*, application/*, *.*",
|
||||
)
|
||||
self.dropzone = Dropzone(self.app)
|
||||
|
||||
|
||||
|
||||
def __init_db(self):
|
||||
@@ -131,19 +138,20 @@ class Framework:
|
||||
|
||||
|
||||
def __init_celery(self):
|
||||
redis_port = 6379
|
||||
try:
|
||||
from celery import Celery
|
||||
|
||||
#if frame.config['use_celery'] == False or platform.system() == 'Windows':
|
||||
if self.config['use_celery'] == False:
|
||||
raise Exception('no celery')
|
||||
|
||||
raise Exception('use_celery=False')
|
||||
from celery import Celery
|
||||
redis_port = os.environ.get('REDIS_PORT', None)
|
||||
if redis_port == None:
|
||||
redis_port = self.config.get('redis_port', None)
|
||||
if redis_port == None:
|
||||
redis_port = '6379'
|
||||
|
||||
self.config['redis_port'] = redis_port
|
||||
self.rd = redis.StrictRedis(host='localhost', port=redis_port, db=0)
|
||||
if self.config['use_celery'] == False:
|
||||
raise Exception('no celery')
|
||||
|
||||
self.app.config['CELERY_BROKER_URL'] = 'redis://localhost:%s/0' % redis_port
|
||||
self.app.config['CELERY_RESULT_BACKEND'] = 'redis://localhost:%s/0' % redis_port
|
||||
@@ -166,6 +174,7 @@ class Framework:
|
||||
F.logger.info(f"celery running_type: {running_type}")
|
||||
#F.logger.info(f"celery running_type: {options}")
|
||||
celery.steps['worker'].add(CustomArgs)
|
||||
|
||||
except Exception as e:
|
||||
if self.config['use_celery']:
|
||||
self.logger.error('CELERY!!!')
|
||||
@@ -187,6 +196,14 @@ class Framework:
|
||||
if len(args) > 0 and type(args[0]) == type(dummy_func):
|
||||
return args[0]
|
||||
self.f(*args, **kwargs)
|
||||
try:
|
||||
from .init_cache_manager import _RedisManager, get_cache
|
||||
_RedisManager(host='localhost', port=redis_port)
|
||||
self.get_cache = get_cache
|
||||
except Exception as e:
|
||||
self.logger.error(f"get_cache import error: {str(e)}")
|
||||
self.get_cache = None
|
||||
|
||||
return celery
|
||||
|
||||
|
||||
@@ -201,11 +218,13 @@ class Framework:
|
||||
self.logger.error(f'Exception:{str(e)}')
|
||||
self.logger.error(traceback.format_exc())
|
||||
self.SystemModelSetting = SystemInstance.ModelSetting
|
||||
SystemInstance.plugin_load()
|
||||
if self.config['run_flask']:
|
||||
SystemInstance.plugin_load()
|
||||
self.app.register_blueprint(SystemInstance.blueprint)
|
||||
self.config['flag_system_loading'] = True
|
||||
self.__config_initialize('member')
|
||||
self.__config_initialize('system_loading_after')
|
||||
self.set_level(self.SystemModelSetting.get_int('log_level'))
|
||||
|
||||
|
||||
def initialize_plugin(self):
|
||||
@@ -232,6 +251,7 @@ class Framework:
|
||||
|
||||
self.__make_default_logger()
|
||||
self.__config_initialize("last")
|
||||
self.config['loading_completed'] = True
|
||||
self.logger.info('### LAST')
|
||||
self.logger.info(f"### PORT: {self.config.get('port')}")
|
||||
self.logger.info('### Now you can access App by webbrowser!!')
|
||||
@@ -248,6 +268,7 @@ class Framework:
|
||||
def __config_initialize(self, mode):
|
||||
if mode == "first":
|
||||
self.config = {}
|
||||
self.config['loading_completed'] = False
|
||||
self.config['os'] = platform.system()
|
||||
self.config['flag_system_loading'] = False
|
||||
#self.config['run_flask'] = True if sys.argv[0].endswith('main.py') else False
|
||||
@@ -263,6 +284,8 @@ class Framework:
|
||||
self.config['export_filepath'] = os.path.join(self.config['path_app'], 'export.sh')
|
||||
self.config['exist_export'] = os.path.exists(self.config['export_filepath'])
|
||||
self.config['recent_version'] = '--'
|
||||
from .version import VERSION
|
||||
self.config['version'] = VERSION
|
||||
self.__process_args()
|
||||
self.__load_config()
|
||||
self.__init_define()
|
||||
@@ -270,7 +293,7 @@ class Framework:
|
||||
self.config['notify_yaml_filepath'] = os.path.join(self.config['path_data'], 'db', 'notify.yaml')
|
||||
if 'running_type' not in self.config:
|
||||
self.config['running_type'] = 'native'
|
||||
|
||||
self.pip_install()
|
||||
elif mode == "flask":
|
||||
self.app.secret_key = os.urandom(24)
|
||||
self.app.config['TEMPLATES_AUTO_RELOAD'] = True
|
||||
@@ -295,8 +318,8 @@ class Framework:
|
||||
self.config['DEFINE'] = {}
|
||||
# 이건 필요 없음
|
||||
self.config['DEFINE']['GIT_VERSION_URL'] = 'https://raw.githubusercontent.com/flaskfarm/flaskfarm/main/lib/framework/version.py'
|
||||
self.config['DEFINE']['CHANGELOG'] = 'https://flaskfarm.github.io/posts/changelog'
|
||||
|
||||
self.config['DEFINE']['CHANGELOG'] = 'https://github.com/flaskfarm/flaskfarm'
|
||||
#self.config['DEFINE']['WEB_DIRECT_URL'] = "http://52.78.103.230:49734"
|
||||
|
||||
|
||||
def __process_args(self):
|
||||
@@ -363,6 +386,9 @@ class Framework:
|
||||
self.config['debug'] = False
|
||||
if self.config.get('plugin_update') == None:
|
||||
self.config['plugin_update'] = True
|
||||
# 2022-11-20
|
||||
if self.config['debug']:
|
||||
self.config['plugin_update'] = False
|
||||
if self.config.get('plugin_loading_only_devpath') == None:
|
||||
self.config['plugin_loading_only_devpath'] = False
|
||||
if self.config.get('plugin_loading_list') == None:
|
||||
@@ -402,8 +428,8 @@ class Framework:
|
||||
try:
|
||||
if self.config['flag_system_loading']:
|
||||
try:
|
||||
from system import SystemModelSetting
|
||||
level = SystemModelSetting.get_int('log_level')
|
||||
#from system import SystemModelSetting
|
||||
level = self.SystemModelSetting.get_int('log_level')
|
||||
except:
|
||||
level = logging.DEBUG
|
||||
if self.__level_unset_logger_list is not None:
|
||||
@@ -426,7 +452,7 @@ class Framework:
|
||||
return converted.timetuple()
|
||||
|
||||
if from_command == False:
|
||||
file_formatter = logging.Formatter(u'[%(asctime)s|%(levelname)s|%(filename)s:%(lineno)s] %(message)s')
|
||||
file_formatter = logging.Formatter(u'[%(asctime)s|%(levelname)s|%(name)s|%(filename)s:%(lineno)s] %(message)s')
|
||||
else:
|
||||
file_formatter = logging.Formatter(u'[%(asctime)s] %(message)s')
|
||||
|
||||
@@ -435,10 +461,18 @@ class Framework:
|
||||
fileHandler = logging.handlers.RotatingFileHandler(filename=os.path.join(self.path_data, 'log', f'{name}.log'), maxBytes=file_max_bytes, backupCount=5, encoding='utf8', delay=True)
|
||||
fileHandler.setFormatter(file_formatter)
|
||||
logger.addHandler(fileHandler)
|
||||
if name == 'framework' and self.all_log_filehandler == None:
|
||||
self.all_log_filehandler = logging.handlers.RotatingFileHandler(filename=os.path.join(self.path_data, 'log', f'all.log'), maxBytes=5*1024*1024, backupCount=5, encoding='utf8', delay=True)
|
||||
self.all_log_filehandler.setFormatter(file_formatter)
|
||||
|
||||
if from_command == False:
|
||||
streamHandler = logging.StreamHandler()
|
||||
streamHandler.setFormatter(CustomFormatter())
|
||||
logger.addHandler(streamHandler)
|
||||
|
||||
if self.all_log_filehandler != None:
|
||||
logger.addHandler(self.all_log_filehandler)
|
||||
|
||||
return logger
|
||||
|
||||
|
||||
@@ -459,7 +493,7 @@ class Framework:
|
||||
def set_level(self, level):
|
||||
try:
|
||||
for l in self.__logger_list:
|
||||
l.setLevel(level)
|
||||
l.setLevel(int(level))
|
||||
self.__make_default_logger()
|
||||
except:
|
||||
pass
|
||||
@@ -468,7 +502,7 @@ class Framework:
|
||||
|
||||
def start(self):
|
||||
host = '0.0.0.0'
|
||||
for i in range(5):
|
||||
for i in range(5):
|
||||
try:
|
||||
#self.logger.debug(d(self.config))
|
||||
# allow_unsafe_werkzeug=True termux nohup 실행시 필요함
|
||||
@@ -517,8 +551,8 @@ class Framework:
|
||||
PluginManager.plugin_unload()
|
||||
with self.app.test_request_context():
|
||||
self.socketio.stop()
|
||||
except Exception as exception:
|
||||
self.logger.error('Exception:%s', exception)
|
||||
except Exception as e:
|
||||
self.logger.error(f"Exception:{str(e)}")
|
||||
self.logger.error(traceback.format_exc())
|
||||
|
||||
def get_recent_version(self):
|
||||
@@ -532,3 +566,11 @@ class Framework:
|
||||
self.logger.error(traceback.format_exc())
|
||||
self.config['recent_version'] = '확인 실패'
|
||||
return False
|
||||
|
||||
|
||||
# dev 도커용. package는 setup에 포함.
|
||||
def pip_install(self):
|
||||
try:
|
||||
import json_fix
|
||||
except:
|
||||
os.system('pip install json_fix')
|
||||
|
||||
@@ -1,93 +1,144 @@
|
||||
import os
|
||||
import shutil
|
||||
import traceback
|
||||
|
||||
from framework import F, logger
|
||||
from support import SupportYaml, d
|
||||
|
||||
from framework import F
|
||||
|
||||
|
||||
class MenuManager:
|
||||
menu_map = None
|
||||
|
||||
@classmethod
|
||||
def __load_menu_yaml(cls):
|
||||
menu_yaml_filepath = os.path.join(F.config['path_data'], 'db', 'menu.yaml')
|
||||
if os.path.exists(menu_yaml_filepath) == False:
|
||||
shutil.copy(
|
||||
os.path.join(F.config['path_app'], 'files', 'menu.yaml.template'),
|
||||
menu_yaml_filepath
|
||||
)
|
||||
cls.menu_map = SupportYaml.read_yaml(menu_yaml_filepath)
|
||||
try:
|
||||
menu_yaml_filepath = os.path.join(F.config['path_data'], 'db', 'menu.yaml')
|
||||
if os.path.exists(menu_yaml_filepath) == False:
|
||||
shutil.copy(
|
||||
os.path.join(F.config['path_app'], 'files', 'menu.yaml.template'),
|
||||
menu_yaml_filepath
|
||||
)
|
||||
cls.menu_map = SupportYaml.read_yaml(menu_yaml_filepath)
|
||||
except Exception as e:
|
||||
logger.error(f"Exception:{str(e)}")
|
||||
logger.error(traceback.format_exc())
|
||||
cls.menu_map = SupportYaml.read_yaml(os.path.join(F.config['path_app'], 'files', 'menu.yaml.template'))
|
||||
|
||||
|
||||
@classmethod
|
||||
def init_menu(cls):
|
||||
cls.__load_menu_yaml()
|
||||
from .init_plugin import PluginManager
|
||||
plugin_menus = PluginManager.plugin_menus
|
||||
copy_map = []
|
||||
if cls.__init_menu() == False:
|
||||
cls.menu_map = SupportYaml.read_yaml(os.path.join(F.config['path_app'], 'files', 'menu.yaml.template'))
|
||||
cls.__init_menu()
|
||||
|
||||
for category in cls.menu_map:
|
||||
if 'uri' in category:
|
||||
copy_map.append(category)
|
||||
continue
|
||||
cate_count = 0
|
||||
@classmethod
|
||||
def __init_menu(cls):
|
||||
try:
|
||||
from .init_plugin import PluginManager
|
||||
plugin_menus = PluginManager.plugin_menus
|
||||
copy_map = []
|
||||
for category in cls.menu_map:
|
||||
if 'uri' in category:
|
||||
if category['uri'] in plugin_menus:
|
||||
plugin_menus[category['uri']]['match'] = True
|
||||
copy_map.append(plugin_menus[category['uri']]['menu'])
|
||||
else:
|
||||
copy_map.append(category)
|
||||
continue
|
||||
cate_count = 0
|
||||
|
||||
tmp_cate_list = []
|
||||
for item in category['list']:
|
||||
if item['uri'] in plugin_menus:
|
||||
plugin_menus[item['uri']]['match'] = True
|
||||
tmp_cate_list.append(plugin_menus[item['uri']]['menu'])
|
||||
cate_count += 1
|
||||
elif item['uri'].startswith('http'):
|
||||
tmp_cate_list.append({
|
||||
'uri': item['uri'],
|
||||
'name': item['name'],
|
||||
'target': item.get('target', '_blank')
|
||||
})
|
||||
cate_count += 1
|
||||
elif (len(item['uri'].split('/')) > 1 and item['uri'].split('/')[0] in plugin_menus) or item['uri'].startswith('javascript') or item['uri'] in ['-']:
|
||||
tmp_cate_list.append({
|
||||
'uri': item['uri'],
|
||||
'name': item.get('name', ''),
|
||||
})
|
||||
cate_count += 1
|
||||
elif item['uri'] == 'setting':
|
||||
if len(PluginManager.setting_menus) > 0:
|
||||
tmp_cate_list = []
|
||||
for item in category['list']:
|
||||
if item['uri'] in plugin_menus:
|
||||
plugin_menus[item['uri']]['match'] = True
|
||||
tmp_cate_list.append(plugin_menus[item['uri']]['menu'])
|
||||
cate_count += 1
|
||||
elif item['uri'].startswith('http'):
|
||||
tmp_cate_list.append({
|
||||
'uri': item['uri'],
|
||||
'name': item['name'],
|
||||
'target': item.get('target', '_blank')
|
||||
})
|
||||
cate_count += 1
|
||||
elif (len(item['uri'].split('/')) > 1 and item['uri'].split('/')[0] in plugin_menus) or item['uri'].startswith('javascript') or item['uri'] in ['-']:
|
||||
tmp_cate_list.append({
|
||||
'uri': item['uri'],
|
||||
'name': item.get('name', ''),
|
||||
'list': PluginManager.setting_menus
|
||||
})
|
||||
|
||||
if cate_count > 0:
|
||||
copy_map.append({
|
||||
'name': category['name'],
|
||||
'list': tmp_cate_list,
|
||||
'count': cate_count
|
||||
})
|
||||
cls.menu_map = copy_map
|
||||
|
||||
make_dummy_cate = False
|
||||
for name, plugin_menu in plugin_menus.items():
|
||||
#F.logger.info(d(plugin_menu))
|
||||
#if 'uri' not in plugin_menu['menu']:
|
||||
# continue
|
||||
if plugin_menu['match'] == False:
|
||||
if make_dummy_cate == False:
|
||||
make_dummy_cate = True
|
||||
cls.menu_map.insert(len(cls.menu_map)-1, {
|
||||
'name':'미분류', 'count':0, 'list':[]
|
||||
cate_count += 1
|
||||
elif item['uri'] == 'setting':
|
||||
# 2024.06.04
|
||||
# 확장설정도 메뉴 구성
|
||||
if len(PluginManager.setting_menus) > 0:
|
||||
set_tmp = item.get('list')
|
||||
if set_tmp:
|
||||
cp = PluginManager.setting_menus.copy()
|
||||
include = []
|
||||
for set_ch in set_tmp:
|
||||
if set_ch.get('uri') and (set_ch.get('uri') == '-' or set_ch.get('uri').startswith('http')):
|
||||
include.append(set_ch)
|
||||
continue
|
||||
|
||||
for i, ps in enumerate(cp):
|
||||
if set_ch.get('plugin') != None and set_ch.get('plugin') == ps.get('plugin'):
|
||||
include.append(ps)
|
||||
del cp[i]
|
||||
break
|
||||
tmp_cate_list.append({
|
||||
'uri': item['uri'],
|
||||
'name': item.get('name', ''),
|
||||
'list': include + cp
|
||||
})
|
||||
|
||||
else:
|
||||
tmp_cate_list.append({
|
||||
'uri': item['uri'],
|
||||
'name': item.get('name', ''),
|
||||
'list': PluginManager.setting_menus
|
||||
})
|
||||
|
||||
if cate_count > 0:
|
||||
copy_map.append({
|
||||
'name': category['name'],
|
||||
'list': tmp_cate_list,
|
||||
'count': cate_count
|
||||
})
|
||||
cls.menu_map = copy_map
|
||||
|
||||
make_dummy_cate = False
|
||||
for name, plugin_menu in plugin_menus.items():
|
||||
#F.logger.info(d(plugin_menu))
|
||||
#if 'uri' not in plugin_menu['menu']:
|
||||
# continue
|
||||
if plugin_menu['match'] == False:
|
||||
if make_dummy_cate == False:
|
||||
make_dummy_cate = True
|
||||
cls.menu_map.insert(len(cls.menu_map)-1, {
|
||||
'name':'미분류', 'count':0, 'list':[]
|
||||
})
|
||||
|
||||
c = cls.menu_map[-2]
|
||||
c['count'] += 1
|
||||
c['list'].append(plugin_menu['menu'])
|
||||
|
||||
c = cls.menu_map[-2]
|
||||
c['count'] += 1
|
||||
c['list'].append(plugin_menu['menu'])
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Exception:{str(e)}")
|
||||
logger.error(traceback.format_exc())
|
||||
return False
|
||||
|
||||
#F.logger.warning(d(cls.menu_map))
|
||||
|
||||
|
||||
@classmethod
|
||||
def get_menu_map(cls):
|
||||
#F.logger.warning(d(cls.menu_map))
|
||||
return cls.menu_map
|
||||
|
||||
|
||||
@classmethod
|
||||
def get_setting_menu(cls, plugin):
|
||||
from .init_plugin import PluginManager
|
||||
for tmp in PluginManager.setting_menus:
|
||||
if tmp['plugin'] == plugin:
|
||||
return tmp
|
||||
|
||||
@@ -7,9 +7,8 @@ import traceback
|
||||
import zipfile
|
||||
|
||||
import requests
|
||||
from support import SupportFile, SupportSubprocess, SupportYaml
|
||||
|
||||
from framework import F
|
||||
from support import SupportFile, SupportSubprocess, SupportYaml
|
||||
|
||||
|
||||
class PluginManager:
|
||||
@@ -30,13 +29,13 @@ class PluginManager:
|
||||
tmps = os.listdir(plugin_path)
|
||||
add_plugin_list = []
|
||||
for t in tmps:
|
||||
if not t.startswith('_') and os.path.isdir(os.path.join(plugin_path, t)):
|
||||
if t.startswith('_') == False and t.startswith('.') == False and os.path.isdir(os.path.join(plugin_path, t)) and t != 'false' and t != 'tmp':
|
||||
add_plugin_list.append(t)
|
||||
cls.all_package_list[t] = {'pos':'normal', 'path':os.path.join(plugin_path, t), 'loading':(F.config.get('plugin_loading_only_devpath', None) != True)}
|
||||
|
||||
plugins = plugins + add_plugin_list
|
||||
except Exception as exception:
|
||||
F.logger.error('Exception:%s', exception)
|
||||
except Exception as e:
|
||||
F.logger.error(f"Exception:{str(e)}")
|
||||
F.logger.error(traceback.format_exc())
|
||||
|
||||
if F.config.get('plugin_loading_only_devpath', None) == True:
|
||||
@@ -59,12 +58,12 @@ class PluginManager:
|
||||
tmps = os.listdir(__)
|
||||
add_plugin_list = []
|
||||
for t in tmps:
|
||||
if not t.startswith('_') and os.path.isdir(os.path.join(__, t)):
|
||||
if t.startswith('_') == False and t.startswith('.') == False and os.path.isdir(os.path.join(__, t)) and t != 'false' and t != 'tmp':
|
||||
add_plugin_list.append(t)
|
||||
cls.all_package_list[t] = {'pos':'dev', 'path':os.path.join(__, t), 'loading':True}
|
||||
plugins = plugins + add_plugin_list
|
||||
except Exception as exception:
|
||||
F.logger.error('Exception:%s', exception)
|
||||
except Exception as e:
|
||||
F.logger.error(f"Exception:{str(e)}")
|
||||
F.logger.error(traceback.format_exc())
|
||||
|
||||
# plugin_loading_list
|
||||
@@ -79,8 +78,8 @@ class PluginManager:
|
||||
cls.all_package_list[_]['loading'] = False
|
||||
cls.all_package_list[_]['status'] = 'not_include_loading_list'
|
||||
plugins = new_plugins
|
||||
except Exception as exception:
|
||||
F.logger.error('Exception:%s', exception)
|
||||
except Exception as e:
|
||||
F.logger.error(f"Exception:{str(e)}")
|
||||
F.logger.error(traceback.format_exc())
|
||||
|
||||
# plugin_except_list
|
||||
@@ -95,8 +94,8 @@ class PluginManager:
|
||||
cls.all_package_list[_]['loading'] = False
|
||||
cls.all_package_list[_]['status'] = 'include_except_list'
|
||||
plugins = new_plugins
|
||||
except Exception as exception:
|
||||
F.logger.error('Exception:%s', exception)
|
||||
except Exception as e:
|
||||
F.logger.error(f"Exception:{str(e)}")
|
||||
F.logger.error(traceback.format_exc())
|
||||
return plugins
|
||||
|
||||
@@ -113,43 +112,26 @@ class PluginManager:
|
||||
for plugin_name in plugins:
|
||||
F.logger.debug(f'[+] PLUGIN LOADING Start.. [{plugin_name}]')
|
||||
entity = cls.all_package_list[plugin_name]
|
||||
entity['version'] = '3'
|
||||
try:
|
||||
mod = __import__('%s' % (plugin_name), fromlist=[])
|
||||
mod_plugin_info = None
|
||||
try:
|
||||
mod_plugin_info = getattr(mod, 'plugin_info')
|
||||
entity['module'] = mod
|
||||
except Exception as exception:
|
||||
F.logger.info(f'[!] PLUGIN_INFO not exist : [{plugin_name}] - is FF')
|
||||
|
||||
if mod_plugin_info == None:
|
||||
try:
|
||||
mod = __import__(f'{plugin_name}.setup', fromlist=['setup'])
|
||||
entity['version'] = '4'
|
||||
except Exception as e:
|
||||
F.logger.error(f'Exception:{str(e)}')
|
||||
F.logger.error(traceback.format_exc())
|
||||
F.logger.warning(f'[!] NOT normal plugin : [{plugin_name}]')
|
||||
mod = __import__(f'{plugin_name}.setup', fromlist=['setup'])
|
||||
except Exception as e:
|
||||
F.logger.error(f'Exception:{str(e)}')
|
||||
F.logger.error(traceback.format_exc())
|
||||
F.logger.warning(f'[!] NOT normal plugin : [{plugin_name}]')
|
||||
continue
|
||||
|
||||
try:
|
||||
if entity['version'] != '4':
|
||||
mod_blue_print = getattr(mod, 'blueprint')
|
||||
else:
|
||||
entity['setup_mod'] = mod
|
||||
entity['P'] = getattr(mod, 'P')
|
||||
mod_blue_print = getattr(entity['P'], 'blueprint')
|
||||
entity['setup_mod'] = mod
|
||||
entity['P'] = getattr(mod, 'P')
|
||||
mod_blue_print = getattr(entity['P'], 'blueprint')
|
||||
if mod_blue_print:
|
||||
F.app.register_blueprint(mod_blue_print)
|
||||
except Exception as exception:
|
||||
#logger.error('Exception:%s', exception)
|
||||
#logger.error(traceback.format_exc())
|
||||
F.logger.warning(f'[!] BLUEPRINT not exist : [{plugin_name}]')
|
||||
cls.plugin_list[plugin_name] = entity
|
||||
#system.LogicPlugin.current_loading_plugin_list[plugin_name]['status'] = 'success'
|
||||
#system.LogicPlugin.current_loading_plugin_list[plugin_name]['info'] = mod_plugin_info
|
||||
except Exception as exception:
|
||||
F.logger.error('Exception:%s', exception)
|
||||
except Exception as e:
|
||||
F.logger.error(f"Exception:{str(e)}")
|
||||
F.logger.error(traceback.format_exc())
|
||||
F.logger.debug('no blueprint')
|
||||
cls.all_package_list[plugin_name]['loading'] = False
|
||||
@@ -157,36 +139,50 @@ class PluginManager:
|
||||
cls.all_package_list[plugin_name]['log'] = traceback.format_exc()
|
||||
|
||||
|
||||
|
||||
if not F.config['run_celery']:
|
||||
try:
|
||||
with F.app.app_context():
|
||||
F.db.create_all()
|
||||
except Exception as exception:
|
||||
F.logger.error('Exception:%s', exception)
|
||||
except Exception as e:
|
||||
F.logger.error(f"Exception:{str(e)}")
|
||||
F.logger.error(traceback.format_exc())
|
||||
F.logger.debug('db.create_all error')
|
||||
|
||||
if F.config['run_celery']:
|
||||
for key, entity in cls.plugin_list.items():
|
||||
try:
|
||||
mod_plugin_load = getattr(entity['P'], 'plugin_load_celery')
|
||||
if mod_plugin_load:
|
||||
def func(mod_plugin_load, key):
|
||||
try:
|
||||
#F.logger.debug(f'[!] plugin_load_celery threading start : [{key}]')
|
||||
mod_plugin_load()
|
||||
#F.logger.debug(f'[!] plugin_load_celery threading end : [{key}]')
|
||||
except Exception as e:
|
||||
F.logger.error(f"Exception:{str(e)}")
|
||||
F.logger.error(traceback.format_exc())
|
||||
t = threading.Thread(target=func, args=(mod_plugin_load, key))
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
except Exception as e:
|
||||
F.logger.error(f"Exception:{str(e)}")
|
||||
F.logger.error(traceback.format_exc())
|
||||
|
||||
if not F.config['run_flask']:
|
||||
return
|
||||
|
||||
for key, entity in cls.plugin_list.items():
|
||||
try:
|
||||
mod_plugin_load = None
|
||||
if entity['version'] == '3':
|
||||
mod_plugin_load = getattr(entity['module'], 'plugin_load')
|
||||
elif entity['version'] == '4':
|
||||
mod_plugin_load = getattr(entity['P'], 'plugin_load')
|
||||
mod_plugin_load = getattr(entity['P'], 'plugin_load')
|
||||
if mod_plugin_load:
|
||||
def func(mod_plugin_load, key):
|
||||
try:
|
||||
F.logger.debug(f'[!] plugin_load threading start : [{key}]')
|
||||
#mod.plugin_load()
|
||||
F.logger.info(f'[!] plugin_load threading start : [{key}]')
|
||||
mod_plugin_load()
|
||||
F.logger.debug(f'[!] plugin_load threading end : [{key}]')
|
||||
except Exception as exception:
|
||||
except Exception as e:
|
||||
F.logger.error('### plugin_load exception : %s', key)
|
||||
F.logger.error('Exception:%s', exception)
|
||||
F.logger.error(f"Exception:{str(e)}")
|
||||
F.logger.error(traceback.format_exc())
|
||||
cls.all_package_list[key]['loading'] = False
|
||||
cls.all_package_list[key]['status'] = 'plugin_load error'
|
||||
@@ -199,42 +195,29 @@ class PluginManager:
|
||||
MenuManager.init_menu()
|
||||
F.logger.info(f"플러그인 로딩 실패로 메뉴 삭제2 : {key}")
|
||||
|
||||
t = threading.Thread(target=func, args=(mod_plugin_load, key))
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
||||
# mod는 위에서 로딩
|
||||
if key != 'mod':
|
||||
t = threading.Thread(target=func, args=(mod_plugin_load, key))
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
#if key == 'mod':
|
||||
# t.join()
|
||||
except Exception as exception:
|
||||
except Exception as e:
|
||||
F.logger.debug(f'[!] PLUGIN_LOAD function not exist : [{key}]')
|
||||
#logger.error('Exception:%s', exception)
|
||||
#logger.error(traceback.format_exc())
|
||||
#logger.debug('no init_scheduler')
|
||||
|
||||
try:
|
||||
mod_menu = None
|
||||
if entity['version'] == '3':
|
||||
mod_menu = getattr(entity['module'], 'menu')
|
||||
elif entity['version'] == '4':
|
||||
mod_menu = getattr(entity['P'], 'menu')
|
||||
|
||||
mod_menu = getattr(entity['P'], 'menu')
|
||||
if mod_menu and cls.all_package_list[key]['loading'] != False:
|
||||
cls.plugin_menus[key]= {'menu':mod_menu, 'match':False}
|
||||
if entity['version'] == '4':
|
||||
setting_menu = getattr(entity['P'], 'setting_menu')
|
||||
if setting_menu != None and cls.all_package_list[key]['loading'] != False:
|
||||
F.logger.info(f"메뉴 포함 : {key}")
|
||||
cls.setting_menus.append(setting_menu)
|
||||
|
||||
|
||||
setting_menu = getattr(entity['P'], 'setting_menu')
|
||||
setting_menu['plugin'] = entity['P'].package_name
|
||||
if setting_menu != None and cls.all_package_list[key]['loading'] != False:
|
||||
F.logger.info(f"확장 설정 : {key}")
|
||||
cls.setting_menus.append(setting_menu)
|
||||
except Exception as exception:
|
||||
F.logger.debug('no menu')
|
||||
F.logger.debug('### plugin_load threading all start.. : %s ', len(cls.plugin_list))
|
||||
# 모든 모듈을 로드한 이후에 app 등록, table 생성, start
|
||||
|
||||
except Exception as exception:
|
||||
F.logger.error('Exception:%s', exception)
|
||||
except Exception as e:
|
||||
F.logger.error(f"Exception:{str(e)}")
|
||||
F.logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
@@ -243,17 +226,9 @@ class PluginManager:
|
||||
def plugin_unload(cls):
|
||||
for key, entity in cls.plugin_list.items():
|
||||
try:
|
||||
if entity['version'] == '3':
|
||||
mod_plugin_unload = getattr(entity['module'], 'plugin_unload')
|
||||
elif entity['version'] == '4':
|
||||
mod_plugin_unload = getattr(entity['P'], 'plugin_unload')
|
||||
|
||||
#if plugin_name == 'rss':
|
||||
# continue
|
||||
#mod_plugin_unload = getattr(mod, 'plugin_unload')
|
||||
mod_plugin_unload = getattr(entity['P'], 'plugin_unload')
|
||||
if mod_plugin_unload:
|
||||
mod_plugin_unload()
|
||||
#mod.plugin_unload()
|
||||
except Exception as e:
|
||||
F.logger.error('module:%s', key)
|
||||
F.logger.error(f'Exception:{str(e)}')
|
||||
@@ -267,6 +242,7 @@ class PluginManager:
|
||||
|
||||
@classmethod
|
||||
def plugin_install(cls, plugin_git, zip_url=None, zip_filename=None):
|
||||
plugin_git = plugin_git.strip()
|
||||
is_git = True if plugin_git != None and plugin_git != '' else False
|
||||
ret = {}
|
||||
try:
|
||||
@@ -381,7 +357,7 @@ class PluginManager:
|
||||
tmps = os.listdir(plugins_path)
|
||||
for t in tmps:
|
||||
plugin_path = os.path.join(plugins_path, t)
|
||||
if t.startswith('_'):
|
||||
if t.startswith('_') or t.startswith('.'):
|
||||
continue
|
||||
if os.path.exists(os.path.join(plugin_path, '.git')):
|
||||
command = ['git', '-C', plugin_path, 'reset', '--hard', 'HEAD']
|
||||
@@ -392,14 +368,15 @@ class PluginManager:
|
||||
F.logger.debug(ret)
|
||||
else:
|
||||
F.logger.debug(f"{plugin_path} not git repo")
|
||||
except Exception as exception:
|
||||
F.logger.error('Exception:%s', exception)
|
||||
except Exception as e:
|
||||
F.logger.error(f"Exception:{str(e)}")
|
||||
F.logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
@classmethod
|
||||
def get_plugin_instance(cls, package_name):
|
||||
try:
|
||||
return cls.all_package_list[package_name]['P']
|
||||
if cls.all_package_list[package_name]['loading']:
|
||||
return cls.all_package_list[package_name]['P']
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -4,7 +4,6 @@ import traceback
|
||||
from flask import (jsonify, redirect, render_template, request,
|
||||
send_from_directory)
|
||||
from flask_login import login_required
|
||||
|
||||
from framework import F
|
||||
|
||||
|
||||
@@ -86,27 +85,31 @@ def open_file(path):
|
||||
@F.app.route("/file/<path:path>")
|
||||
@F.check_api
|
||||
def file2(path):
|
||||
# 윈도우 drive 필요 없음
|
||||
import platform
|
||||
if platform.system() == 'Windows':
|
||||
path = os.path.splitdrive(path)[1][1:]
|
||||
return send_from_directory('/', path, as_attachment=True)
|
||||
|
||||
|
||||
@F.app.route("/upload", methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def upload():
|
||||
try:
|
||||
if request.method == 'POST':
|
||||
f = request.files['file']
|
||||
from werkzeug import secure_filename
|
||||
from werkzeug.utils import secure_filename
|
||||
upload_path = F.SystemModelSetting.get('path_upload')
|
||||
os.makedirs(upload_path, exist_ok=True)
|
||||
f.save(os.path.join(upload_path, secure_filename(f.filename)))
|
||||
return jsonify('success')
|
||||
except Exception as exception:
|
||||
F.logger.error('Exception:%s', exception)
|
||||
except Exception as e:
|
||||
F.logger.error(f"Exception:{str(e)}")
|
||||
F.logger.error(traceback.format_exc())
|
||||
return jsonify('fail')
|
||||
|
||||
|
||||
@F.app.route("/videojs", methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def videojs():
|
||||
data = {}
|
||||
data['play_title'] = request.form['play_title']
|
||||
@@ -116,9 +119,33 @@ def videojs():
|
||||
data['play_subtitle_src'] = request.form['play_subtitle_src']
|
||||
return render_template('videojs.html', data=data)
|
||||
|
||||
@F.app.route("/videojs_drm", methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def videojs_drm():
|
||||
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']
|
||||
return render_template('videojs_drm.html', data=data)
|
||||
|
||||
@F.app.route("/videojs_discord", methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def videojs_og():
|
||||
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']
|
||||
"""
|
||||
return render_template('videojs_discord.html', data=data)
|
||||
|
||||
|
||||
@F.app.route("/headers", methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def headers():
|
||||
from support import d
|
||||
F.logger.info(d(request.headers))
|
||||
@@ -127,6 +154,7 @@ def headers():
|
||||
|
||||
# 3.10에서 이거 필수
|
||||
@F.socketio.on('connect', namespace=f'/framework')
|
||||
@login_required
|
||||
def connect():
|
||||
pass
|
||||
|
||||
|
||||
@@ -4,6 +4,10 @@ from framework import F
|
||||
|
||||
|
||||
def get_menu(full_query):
|
||||
match = re.compile(r'\/(?P<package_name>.*?)\/(?P<module_name>.*?)\/manual\/(?P<sub2>.*?)($|\?)').match(full_query)
|
||||
if match:
|
||||
return match.group('package_name'), match.group('module_name'), f"manual/{match.group('sub2')}"
|
||||
|
||||
match = re.compile(r'\/(?P<menu>.*?)\/manual\/(?P<sub2>.*?)($|\?)').match(full_query)
|
||||
if match:
|
||||
return match.group('menu'), 'manual', match.group('sub2')
|
||||
@@ -48,12 +52,14 @@ def jinja_initialize(app):
|
||||
app.jinja_env.globals.update(get_menu=get_menu)
|
||||
app.jinja_env.globals.update(get_theme=get_theme)
|
||||
app.jinja_env.globals.update(get_menu_map=MenuManager.get_menu_map)
|
||||
app.jinja_env.globals.update(get_setting_menu=MenuManager.get_setting_menu)
|
||||
app.jinja_env.globals.update(get_web_title=get_web_title)
|
||||
app.jinja_env.globals.update(dropzone=F.dropzone)
|
||||
|
||||
app.jinja_env.filters['get_menu'] = get_menu
|
||||
app.jinja_env.filters['get_theme'] = get_theme
|
||||
app.jinja_env.filters['get_menu_map'] = MenuManager.get_menu_map
|
||||
app.jinja_env.filters['get_setting_menu'] = MenuManager.get_setting_menu
|
||||
app.jinja_env.filters['get_web_title'] = get_web_title
|
||||
|
||||
app.jinja_env.auto_reload = True
|
||||
|
||||
@@ -4,17 +4,18 @@ import time
|
||||
import traceback
|
||||
|
||||
from flask import request
|
||||
from support import SingletonClass
|
||||
|
||||
from framework import F
|
||||
from support import SingletonClass
|
||||
|
||||
namespace = 'log'
|
||||
|
||||
@F.socketio.on('connect', namespace='/%s' % namespace)
|
||||
@F.login_required
|
||||
def socket_connect():
|
||||
F.logger.debug('log connect')
|
||||
|
||||
@F.socketio.on('start', namespace='/%s' % namespace)
|
||||
@F.login_required
|
||||
def socket_file(data):
|
||||
try:
|
||||
package = filename = None
|
||||
@@ -24,8 +25,8 @@ def socket_file(data):
|
||||
filename = data['filename']
|
||||
LogViewer.instance().start(package, filename, request.sid)
|
||||
F.logger.debug('start package:%s filename:%s sid:%s', package, filename, request.sid)
|
||||
except Exception as exception:
|
||||
F.logger.error('Exception:%s', exception)
|
||||
except Exception as e:
|
||||
F.logger.error(f"Exception:{str(e)}")
|
||||
F.logger.error(traceback.format_exc())
|
||||
|
||||
@F.socketio.on('disconnect', namespace='/%s' % namespace)
|
||||
@@ -33,8 +34,8 @@ def disconnect():
|
||||
try:
|
||||
LogViewer.instance().disconnect(request.sid)
|
||||
F.logger.debug('disconnect sid:%s', request.sid)
|
||||
except Exception as exception:
|
||||
F.logger.error('Exception:%s', exception)
|
||||
except Exception as e:
|
||||
F.logger.error(f"Exception:{str(e)}")
|
||||
F.logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
@@ -62,18 +63,17 @@ class WatchThread(threading.Thread):
|
||||
key = 'filename'
|
||||
value = self.filename
|
||||
if os.path.exists(logfile):
|
||||
with open(logfile, 'r') as f:
|
||||
with open(logfile, 'r', encoding='utf8') as f:
|
||||
f.seek(0, os.SEEK_END)
|
||||
while not self.stop_flag:
|
||||
line = f.readline()
|
||||
if not line:
|
||||
time.sleep(0.1) # Sleep briefly
|
||||
continue
|
||||
F.socketio.emit("add", {key : value, 'data': line}, namespace='/log', broadcast=True)
|
||||
F.socketio.emit("add", {key : value, 'data': line}, namespace='/log')
|
||||
F.logger.debug('WatchThread.. End %s', value)
|
||||
else:
|
||||
F.socketio.emit("add", {key : value, 'data': 'not exist logfile'}, namespace='/log', broadcast=True)
|
||||
|
||||
F.socketio.emit("add", {key : value, 'data': 'not exist logfile'}, namespace='/log')
|
||||
|
||||
|
||||
class LogViewer(SingletonClass):
|
||||
|
||||
@@ -49,8 +49,8 @@ class Scheduler(object):
|
||||
if flag_exit:
|
||||
self.remove_job("scheduler_check")
|
||||
#time.sleep(30)
|
||||
except Exception as exception:
|
||||
self.logger.error('Exception:%s', exception)
|
||||
except Exception as e:
|
||||
self.logger.error(f"Exception:{str(e)}")
|
||||
self.logger.error(traceback.format_exc())
|
||||
|
||||
def shutdown(self):
|
||||
@@ -233,21 +233,21 @@ class Job(object):
|
||||
if self.args is None:
|
||||
self.thread = threading.Thread(target=self.target_function, args=())
|
||||
else:
|
||||
self.thread = threading.Thread(target=self.target_function, args=(self.args,))
|
||||
self.thread = threading.Thread(target=self.target_function, args=self.args)
|
||||
self.thread.daemon = True
|
||||
self.thread.start()
|
||||
F.socketio.emit('notify', {'type':'success', 'msg':f"{self.description}<br>작업을 시작합니다." }, namespace='/framework', broadcast=True)
|
||||
F.socketio.emit('notify', {'type':'success', 'msg':f"{self.description}<br>작업을 시작합니다." }, namespace='/framework')
|
||||
self.thread.join()
|
||||
F.socketio.emit('notify', {'type':'success', 'msg':f"{self.description}<br>작업이 종료되었습니다." }, namespace='/framework', broadcast=True)
|
||||
F.socketio.emit('notify', {'type':'success', 'msg':f"{self.description}<br>작업이 종료되었습니다." }, namespace='/framework')
|
||||
self.end_time = datetime.now(timezone('Asia/Seoul'))
|
||||
self.running_timedelta = self.end_time - self.start_time
|
||||
self.status = 'success'
|
||||
if not F.scheduler.is_include(self.job_id):
|
||||
F.scheduler.remove_job_instance(self.job_id)
|
||||
self.count += 1
|
||||
except Exception as exception:
|
||||
except Exception as e:
|
||||
self.status = 'exception'
|
||||
F.logger.error('Exception:%s', exception)
|
||||
F.logger.error(f"Exception:{str(e)}")
|
||||
F.logger.error(traceback.format_exc())
|
||||
finally:
|
||||
self.is_running = False
|
||||
|
||||
BIN
lib/framework/static/.DS_Store
vendored
Normal file
BIN
lib/framework/static/.DS_Store
vendored
Normal file
Binary file not shown.
@@ -106,3 +106,5 @@ background-color: #ffff0080 !important;
|
||||
.dropdown-menu {
|
||||
margin:-2px;
|
||||
}
|
||||
|
||||
.modal { overflow: scroll !important; }
|
||||
160
lib/framework/static/css/showdown.css
Normal file
160
lib/framework/static/css/showdown.css
Normal file
@@ -0,0 +1,160 @@
|
||||
h3 {
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.top-bar {
|
||||
height: 45px;
|
||||
min-height: 45px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.bars-lnk {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.bars-lnk i {
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
.bars-lnk img {
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
margin-top: -15px;
|
||||
margin-right: 15px;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
.lateral-menu {
|
||||
background-color: #333;
|
||||
color: rgb(144, 144, 144);
|
||||
width: 300px;
|
||||
|
||||
}
|
||||
|
||||
.lateral-menu label {
|
||||
color: rgb(144, 144, 144);
|
||||
}
|
||||
|
||||
.lateral-menu-content {
|
||||
padding-left: 10px;
|
||||
height: 100%;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-variant: normal;
|
||||
font-weight: bold;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.lateral-menu-content .title{
|
||||
padding-top: 15px;
|
||||
font-size: 2em;
|
||||
height: 45px;
|
||||
}
|
||||
|
||||
.lateral-menu-content-inner {
|
||||
overflow-y: auto;
|
||||
height: 100%;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 50px;
|
||||
padding-right: 10px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#preview {
|
||||
height: 97%;
|
||||
max-height: 97%;
|
||||
border: 1px solid #eee;
|
||||
overflow-y: scroll;
|
||||
width: 55%;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
pre {
|
||||
white-space: pre-wrap; /* css-3 */
|
||||
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
|
||||
white-space: -pre-wrap; /* Opera 4-6 */
|
||||
white-space: -o-pre-wrap; /* Opera 7 */
|
||||
word-wrap: break-word; /* Internet Explorer 5.5+ */
|
||||
background-color: #f8f8f8;
|
||||
border: 1px solid #dfdfdf;
|
||||
margin-top: 1.5em;
|
||||
margin-bottom: 1.5em;
|
||||
padding: 0.125rem 0.3125rem 0.0625rem;
|
||||
}
|
||||
|
||||
pre code {
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
.modal-wrapper {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 999;
|
||||
background-color: rgba(51,51,51,0.5);
|
||||
}
|
||||
|
||||
.modal-inner {
|
||||
margin-top: 200px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 600px;
|
||||
height: 225px;
|
||||
background-color: #fff;
|
||||
opacity: 1;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.modal-close-btn {
|
||||
float: right;
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
color: #ff4336;
|
||||
}
|
||||
|
||||
.modal-close-btn:hover {
|
||||
float: right;
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
color: #8d0002;
|
||||
}
|
||||
|
||||
.modal-topbar {
|
||||
clear: both;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
.modal-inner .link-area {
|
||||
margin: 10px;
|
||||
height: 170px;
|
||||
|
||||
}
|
||||
|
||||
.modal-inner textarea {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.version {
|
||||
color: white;
|
||||
font-size: 0.8em !important;
|
||||
}
|
||||
9
lib/framework/static/img/loader.svg
Normal file
9
lib/framework/static/img/loader.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin: auto; background: none; display: block; shape-rendering: auto;" width="100px" height="100px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
|
||||
<circle cx="50" cy="50" r="31" stroke-width="4" stroke="#e15b64" stroke-dasharray="48.69468613064179 48.69468613064179" fill="none" stroke-linecap="round">
|
||||
<animateTransform attributeName="transform" type="rotate" dur="2.6315789473684212s" repeatCount="indefinite" keyTimes="0;1" values="0 50 50;360 50 50"></animateTransform>
|
||||
</circle>
|
||||
<circle cx="50" cy="50" r="26" stroke-width="4" stroke="#f8b26a" stroke-dasharray="40.840704496667314 40.840704496667314" stroke-dashoffset="40.840704496667314" fill="none" stroke-linecap="round">
|
||||
<animateTransform attributeName="transform" type="rotate" dur="2.6315789473684212s" repeatCount="indefinite" keyTimes="0;1" values="0 50 50;-360 50 50"></animateTransform>
|
||||
</circle>
|
||||
<!-- [ldio] generated by https://loading.io/ --></svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
3845
lib/framework/static/js/chartjs-utils.js
Normal file
3845
lib/framework/static/js/chartjs-utils.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ if (tmp.length == 2) {
|
||||
var PACKAGE_NAME = tmp[1];
|
||||
var MODULE_NAME = tmp[2];
|
||||
var PAGE_NAME = "";
|
||||
} else if (tmp.length == 4){
|
||||
} else if (tmp.length > 3){
|
||||
var PACKAGE_NAME = tmp[1];
|
||||
var MODULE_NAME = tmp[2];
|
||||
var PAGE_NAME = tmp[3];
|
||||
@@ -23,8 +23,6 @@ $(window).on("load resize", function (event) {
|
||||
});
|
||||
|
||||
$('#command_modal').on('show.bs.modal', function (event) {
|
||||
console.log('111111111')
|
||||
console.log(event);
|
||||
})
|
||||
|
||||
///////////////////////////////////////
|
||||
@@ -113,7 +111,6 @@ function showModal(data='EMPTY', title='JSON', json=true) {
|
||||
data = JSON.stringify(data, null, 2);
|
||||
}
|
||||
document.getElementById("modal_body").innerHTML = '<pre style="white-space: pre-wrap;">' +data + '</pre>';
|
||||
|
||||
$("#large_modal").modal();
|
||||
}
|
||||
|
||||
@@ -168,7 +165,22 @@ function use_collapse(div, reverse=false) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// jquery extend function
|
||||
// post로 요청하면서 리다이렉트
|
||||
$.extend(
|
||||
{
|
||||
redirectPost: function(location, args)
|
||||
{
|
||||
var form = '';
|
||||
$.each( args, function( key, value ) {
|
||||
console.log(key);
|
||||
console.log(value);
|
||||
value = value.split('"').join('\"')
|
||||
form += '<input type="hidden" name="'+key+'" value="'+value+'">';
|
||||
});
|
||||
$('<form action="' + location + '" method="POST">' + form + '</form>').appendTo($(document.body)).submit();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -282,20 +294,3 @@ function pad(n, width) {
|
||||
return n.length >= width ? n : new Array(width - n.length + 1).join('0') + n;
|
||||
}
|
||||
|
||||
// jquery extend function
|
||||
// post로 요청하면서 리다이렉트
|
||||
// 푹 자동에서 푹 기본 검색할때 사용
|
||||
$.extend(
|
||||
{
|
||||
redirectPost: function(location, args)
|
||||
{
|
||||
var form = '';
|
||||
$.each( args, function( key, value ) {
|
||||
console.log(key);
|
||||
console.log(value);
|
||||
value = value.split('"').join('\"')
|
||||
form += '<input type="hidden" name="'+key+'" value="'+value+'">';
|
||||
});
|
||||
$('<form action="' + location + '" method="POST">' + form + '</form>').appendTo($(document.body)).submit();
|
||||
}
|
||||
});
|
||||
@@ -15,11 +15,10 @@ $(document).ready(function(){
|
||||
|
||||
var protocol = window.location.protocol;
|
||||
var frameSocket = io.connect(protocol + "//" + document.domain + ":" + location.port + "/framework");
|
||||
console.log(frameSocket);
|
||||
|
||||
frameSocket.on('notify', function(data){
|
||||
$.notify({
|
||||
message : data['msg'],
|
||||
message : '<strong>' + data['msg'] + '</strong>',
|
||||
url: data['url'],
|
||||
target: '_self'
|
||||
},{
|
||||
@@ -29,7 +28,7 @@ frameSocket.on('notify', function(data){
|
||||
});
|
||||
|
||||
frameSocket.on('modal', function(data){
|
||||
m_modal(data.data, data.title, false);
|
||||
showModal(data.data, data.title, false);
|
||||
});
|
||||
|
||||
frameSocket.on('loading_hide', function(data){
|
||||
@@ -37,14 +36,12 @@ frameSocket.on('loading_hide', function(data){
|
||||
});
|
||||
|
||||
frameSocket.on('refresh', function(data){
|
||||
console.log('data')
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
|
||||
$('#command_modal').on('hide.bs.modal', function (e) {
|
||||
//e.preventDefault(); 있으면 동작 안함.
|
||||
console.log("ff global command_modal hide.bs.modal CATCH")
|
||||
$.ajax({
|
||||
url: `/global/ajax/command_modal_hide`,
|
||||
type: 'POST',
|
||||
@@ -74,13 +71,27 @@ $("body").on('click', '#globalLinkBtn', function(e) {
|
||||
window.location.href = url;
|
||||
});
|
||||
|
||||
$("body").on('click', '#globalReloadBtn', function(e) {
|
||||
e.preventDefault();
|
||||
location.reload();
|
||||
});
|
||||
// global_link_btn 모두 찾아 변경
|
||||
|
||||
$("body").on('click', '#globalSettingSaveBtn', function(e){
|
||||
e.preventDefault();
|
||||
globalSettingSave();
|
||||
if (globalSettingSaveBefore()) {
|
||||
globalSettingSave();
|
||||
}
|
||||
});
|
||||
|
||||
function globalSettingSaveBefore() {
|
||||
return true;
|
||||
}
|
||||
|
||||
function globalSettingSaveAfter() {
|
||||
return true;
|
||||
}
|
||||
|
||||
function globalSettingSave() {
|
||||
var formData = getFormdata('#setting');
|
||||
$.ajax({
|
||||
@@ -94,6 +105,7 @@ function globalSettingSave() {
|
||||
$.notify('<strong>설정을 저장하였습니다.</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
globalSettingSaveAfter();
|
||||
} else {
|
||||
$.notify('<strong>설정 저장에 실패하였습니다.</strong>', {
|
||||
type: 'warning'
|
||||
@@ -106,7 +118,10 @@ function globalSettingSave() {
|
||||
$("body").on('click', '#globalEditBtn', function(e) {
|
||||
e.preventDefault();
|
||||
file = $(this).data('file');
|
||||
console.log(file);
|
||||
if (file == null) {
|
||||
var tag = $(this).data('tag');
|
||||
file = $('#' + tag).val();
|
||||
}
|
||||
$.ajax({
|
||||
url: '/global/ajax/is_available_edit',
|
||||
type: "POST",
|
||||
@@ -236,107 +251,188 @@ $("body").on('click', '#globalImmediatelyExecutePageBtn', function(e){
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
$("body").on('click', '#globalDbDeleteDayBtn', function(e){
|
||||
e.preventDefault();
|
||||
var tag_id = $(this).data('tag_id');
|
||||
var day = $('#' + tag_id).val();
|
||||
globalConfirmModal('DB 삭제', "최근 " + day + "일 이내 데이터를 제외하고 삭제 하시겠습니까?", function() {
|
||||
globalDbDelete(day);
|
||||
});
|
||||
});
|
||||
|
||||
$("body").on('click', '#globalDbDeleteBtn', function(e){
|
||||
e.preventDefault();
|
||||
document.getElementById("confirm_title").innerHTML = "DB 삭제";
|
||||
document.getElementById("confirm_body").innerHTML = "전체 목록을 삭제 하시겠습니까?";
|
||||
$('#confirm_button').attr('onclick', "globalDbDelete();");
|
||||
$("#confirm_modal").modal();
|
||||
return;
|
||||
globalConfirmModal('DB 삭제', "전체 목록을 삭제 하시겠습니까?", function() {
|
||||
globalDbDelete(0);
|
||||
});
|
||||
});
|
||||
|
||||
function globalDbDelete() {
|
||||
function globalDbDelete(day) {
|
||||
$.ajax({
|
||||
url: '/'+PACKAGE_NAME+'/ajax/' + MODULE_NAME + '/reset_db',
|
||||
url: '/'+PACKAGE_NAME+'/ajax/' + MODULE_NAME + '/db_delete',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: {},
|
||||
data: {day:day},
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
if (data) {
|
||||
$.notify('<strong>삭제하였습니다.</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
} else {
|
||||
if (data == -1) {
|
||||
$.notify('<strong>삭제에 실패하였습니다.</strong>',{
|
||||
type: 'warning'
|
||||
});
|
||||
} else {
|
||||
$.notify('<strong>'+data+'개를 삭제하였습니다.</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
globalRequestSearch('1');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
$("body").on('click', '#globalDbDeleteDayPageBtn', function(e){
|
||||
e.preventDefault();
|
||||
var tag_id = $(this).data('tag_id');
|
||||
var day = $('#' + tag_id).val();
|
||||
globalConfirmModal('DB 삭제', day + "일 제외 목록을 삭제 하시겠습니까?", function() {
|
||||
globalDbDeletePage(day);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$("body").on('click', '#globalDbDeletePageBtn', function(e){
|
||||
e.preventDefault();
|
||||
document.getElementById("confirm_title").innerHTML = "DB 삭제";
|
||||
document.getElementById("confirm_body").innerHTML = "전체 목록을 삭제 하시겠습니까?";
|
||||
$('#confirm_button').attr('onclick', "globalDbDeletePage();");
|
||||
$("#confirm_modal").modal();
|
||||
return;
|
||||
globalConfirmModal('DB 삭제', "최근 " + day + "일 이내 데이터를 제외하고 삭제 하시겠습니까?", function() {
|
||||
globalDbDeletePage(0);
|
||||
});
|
||||
});
|
||||
|
||||
function globalDbDeletePage() {
|
||||
function globalDbDeletePage(day) {
|
||||
$.ajax({
|
||||
url: '/'+PACKAGE_NAME+'/ajax/' + MODULE_NAME + '/' + PAGE_NAME + '/reset_db',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: {sub:sub},
|
||||
data: {day:day},
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
if (data) {
|
||||
$.notify('<strong>삭제하였습니다.</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
} else {
|
||||
if (data == -1) {
|
||||
$.notify('<strong>삭제에 실패하였습니다.</strong>',{
|
||||
type: 'warning'
|
||||
});
|
||||
} else {
|
||||
$.notify('<strong>'+data+'개를 삭제하였습니다.</strong>', {
|
||||
type: 'success'
|
||||
});
|
||||
globalRequestSearch('1');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
$("body").on('click', '#globalDbDeleteItemBtn', function(e){
|
||||
e.preventDefault();
|
||||
var db_id = $(this).data('id');
|
||||
$.ajax({
|
||||
url: '/'+PACKAGE_NAME+'/ajax/' + MODULE_NAME + '/db_delete_item',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: {db_id:db_id},
|
||||
dataType: "json",
|
||||
success: function (ret) {
|
||||
if (ret) {
|
||||
notify('삭제하였습니다.', 'success');
|
||||
globalRequestSearch(current_page);
|
||||
} else {
|
||||
notify('삭제에 실패하였습니다.', 'warning');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("body").on('click', '#globalDbDeleteItemPageBtn', function(e){
|
||||
e.preventDefault();
|
||||
var db_id = $(this).data('id');
|
||||
$.ajax({
|
||||
url: '/'+PACKAGE_NAME+'/ajax/' + MODULE_NAME + '/' + PAGE_NAME + '/db_delete_item',
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data: {db_id:db_id},
|
||||
dataType: "json",
|
||||
success: function (ret) {
|
||||
if (ret) {
|
||||
notify('삭제하였습니다.', 'success');
|
||||
globalRequestSearch(current_page);
|
||||
} else {
|
||||
notify('삭제에 실패하였습니다.', 'warning');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$("body").on('click', '#globalJsonBtn', function(e){
|
||||
e.preventDefault();
|
||||
showModal(current_data.list[$(this).data('idx')]);
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////
|
||||
// Global - 함수
|
||||
///////////////////////////////////////
|
||||
|
||||
function globalSendCommand(command, arg1, arg2, arg3, modal_title, callback) {
|
||||
console.log("globalSendCommand [" + command + '] [' + arg1 + '] [' + arg2 + '] [' + arg3 + '] [' + modal_title + '] [' + callback + ']');
|
||||
console.log('/' + PACKAGE_NAME + '/ajax/' + MODULE_NAME + '/command');
|
||||
function globalSendCommand(command, arg1, arg2, arg3, callback) {
|
||||
var url = '/' + PACKAGE_NAME + '/ajax/' + MODULE_NAME + '/command';
|
||||
return globalSendCommandByUrl(url, command, arg1, arg2, arg3, callback);
|
||||
}
|
||||
|
||||
function globalSendCommandByUrl(url, command, arg1, arg2, arg3, callback) {
|
||||
$.ajax({
|
||||
url: '/' + PACKAGE_NAME + '/ajax/' + MODULE_NAME + '/command',
|
||||
url: url,
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data:{command:command, arg1:arg1, arg2:arg2, arg3},
|
||||
dataType: "json",
|
||||
success: function (ret) {
|
||||
console.log(ret)
|
||||
if (ret.msg != null) notify(ret.msg, ret.ret);
|
||||
if (ret.modal != null) showModal(ret.modal, modal_title, false);
|
||||
if (ret.json != null) showModal(ret.json, modal_title, true);
|
||||
if (ret.modal != null) showModal(ret.modal, ret.title, false);
|
||||
if (ret.json != null) showModal(ret.json, ret.title, true);
|
||||
if (callback != null) callback(ret);
|
||||
if (ret.reload) location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function globalSendCommandPage(command, arg1, arg2, arg3, modal_title, callback) {
|
||||
console.log("globalSendCommandPage [" + command + '] [' + arg1 + '] [' + arg2 + '] [' + arg3 + '] [' + modal_title + '] [' + callback + ']');
|
||||
console.log('/' + PACKAGE_NAME + '/ajax/' + MODULE_NAME + '/command');
|
||||
function globalSendCommandPage(command, arg1, arg2, arg3, callback) {
|
||||
var url = '/' + PACKAGE_NAME + '/ajax/' + MODULE_NAME + '/' + PAGE_NAME + '/command';
|
||||
return globalSendCommandPageByUrl(url, command, arg1, arg2, arg3, callback);
|
||||
}
|
||||
|
||||
function globalSendCommandPageByUrl(url, command, arg1, arg2, arg3, callback) {
|
||||
$.ajax({
|
||||
url: '/' + PACKAGE_NAME + '/ajax/' + MODULE_NAME + '/' + PAGE_NAME + '/command',
|
||||
url: url,
|
||||
type: "POST",
|
||||
cache: false,
|
||||
data:{command:command, arg1:arg1, arg2:arg2, arg3},
|
||||
dataType: "json",
|
||||
success: function (ret) {
|
||||
if (ret.msg != null) notify(ret.msg, ret.ret);
|
||||
if (ret.modal != null) m_modal(ret.modal, modal_title, false);
|
||||
if (ret.json != null) m_modal(ret.json, modal_title, true);
|
||||
if (ret.modal != null) showModal(ret.modal, ret.title, false);
|
||||
if (ret.json != null) showModal(ret.json, ret.title, true);
|
||||
if (callback != null) callback(ret);
|
||||
if (ret.reload) location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -400,6 +496,10 @@ function make_page_html(data) {
|
||||
str += '<button id="gloablSearchPageBtn" data-page="' + (data.last_page+1) + '" type="button" class="btn btn-secondary">»</button>'
|
||||
}
|
||||
|
||||
if (data.last_page != data.total_page) {
|
||||
str += '<button id="gloablSearchPageBtn" data-page="' + (data.total_page) + '" type="button" class="btn btn-secondary">'+data.total_page+'</button>'
|
||||
}
|
||||
|
||||
str += '</div> \
|
||||
</div> \
|
||||
</div> \
|
||||
@@ -431,6 +531,22 @@ $("body").on('click', '#globalSearchResetBtn', function(e){
|
||||
});
|
||||
|
||||
|
||||
$("body").on('change', '#option1', function(e){
|
||||
e.preventDefault();
|
||||
globalRequestSearch(1);
|
||||
});
|
||||
|
||||
$("body").on('change', '#option2', function(e){
|
||||
e.preventDefault();
|
||||
globalRequestSearch(1);
|
||||
});
|
||||
|
||||
$("body").on('change', '#order', function(e){
|
||||
e.preventDefault();
|
||||
globalRequestSearch(1);
|
||||
});
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////
|
||||
// 파일 선택 모달
|
||||
@@ -483,7 +599,6 @@ let listdir = (path = '/', only_dir = true) => {
|
||||
},
|
||||
dataType: 'json'
|
||||
}).done((datas) => {
|
||||
console.log(datas)
|
||||
if (datas.length == 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -510,8 +625,6 @@ let listdir = (path = '/', only_dir = true) => {
|
||||
} else {
|
||||
//new_path = (path !== path_spliter) ? path + path_spliter + $(evt.currentTarget).text() : path + $(evt.currentTarget).text();
|
||||
new_path = $(evt.currentTarget).data('value');
|
||||
console.log(new_path)
|
||||
console.log(evt)
|
||||
|
||||
}
|
||||
*/
|
||||
@@ -587,3 +700,23 @@ function ResizeTextArea() {
|
||||
|
||||
///////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////
|
||||
// Confirm MODAL
|
||||
///////////////////////////////////////
|
||||
|
||||
function globalConfirmModal(title, body, func) {
|
||||
$("#confirm_title").html(title);
|
||||
$("#confirm_body").html(body);
|
||||
//$('#confirm_button').attr('onclick', func);
|
||||
$("body").on('click', '#confirm_button', function(e){
|
||||
e.stopImmediatePropagation();
|
||||
e.preventDefault();
|
||||
func();
|
||||
});
|
||||
$("#confirm_modal").modal();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
14
lib/framework/static/js/ff_global_plugin.js
Normal file
14
lib/framework/static/js/ff_global_plugin.js
Normal file
@@ -0,0 +1,14 @@
|
||||
///////////////////////////////////////
|
||||
// 자주 사용하는 플러그인에 전용 명령
|
||||
|
||||
function pluginRcloneLs(remote_path) {
|
||||
var url = '/rclone/ajax/config/command';
|
||||
globalSendCommandByUrl(url, "ls", remote_path);
|
||||
}
|
||||
|
||||
function pluginRcloneSize(remote_path) {
|
||||
var url = '/rclone/ajax/config/command';
|
||||
globalSendCommandByUrl(url, "size", remote_path);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,12 +10,13 @@ function j_button_group(h) {
|
||||
}
|
||||
|
||||
// primary, secondary, success, danger, warning, info, light, dark, white
|
||||
function j_button(id, text, data={}, color='primary', outline=true, small=false) {
|
||||
function j_button(id, text, data={}, color='primary', outline=true, small=false, _class='') {
|
||||
var str = '<button id="'+id+'" name="'+id+'" class="btn btn-sm btn';
|
||||
if (outline) {
|
||||
str += '-outline';
|
||||
}
|
||||
str += '-' + color+'';
|
||||
str += ' ' + _class;
|
||||
if (small) {
|
||||
str += ' py-0" style="font-size: 0.8em;"';
|
||||
} else {
|
||||
@@ -35,9 +36,14 @@ function j_button_small(id, text, data={}, color='primary', outline=true) {
|
||||
|
||||
|
||||
function j_row_start(padding='10', align='center') {
|
||||
var str = '<div class="row" style="padding-top: '+padding+'px; padding-bottom:'+padding+'px; align-items:'+align+';">';
|
||||
var str = '<div class="row chover" style="padding-top: '+padding+'px; padding-bottom:'+padding+'px; align-items:'+align+';">';
|
||||
return str;
|
||||
}
|
||||
function j_row_start_hover(padding='10', align='center') {
|
||||
var str = '<div class="row my_hover" style="padding-top: '+padding+'px; padding-bottom:'+padding+'px; align-items:'+align+';">';
|
||||
return str;
|
||||
}
|
||||
|
||||
function j_col(w, h, align='left') {
|
||||
var str = '<div class="col-sm-' + w + ' " style="text-align: '+align+'; word-break:break-all;">';
|
||||
str += h;
|
||||
@@ -45,6 +51,13 @@ function j_col(w, h, align='left') {
|
||||
return str;
|
||||
}
|
||||
|
||||
function j_col_with_class(w, h, align='left', _class='context_menu') {
|
||||
var str = '<div class="col-sm-' + w + ' '+_class+'" style="text-align: '+align+'; word-break:break-all;">';
|
||||
str += h;
|
||||
str += '</div>';
|
||||
return str;
|
||||
}
|
||||
|
||||
function j_col_wide(w, h, align='left') {
|
||||
var str = '<div class="col-sm-' + w + ' " style="padding:0px; margin:0px; text-align: '+align+'; word-break:break-all;">';
|
||||
str += h;
|
||||
@@ -87,57 +100,101 @@ function j_row_info(left, right, l=2, r=8) {
|
||||
function j_progress(id, width, label) {
|
||||
var str = '';
|
||||
str += '<div class="progress" style="height: 25px;">'
|
||||
str += '<div id="'+id+'" class="progress-bar" style="background-color:yellow;width:'+width+'%"></div>';
|
||||
str += '<div id="'+id+'_label" class="justify-content-center d-flex w-100 " style="margin-top:2px">'+label+'</div>';
|
||||
str += '<div id="'+id+'" class="progress-bar bg-success" style="width:'+width+'%"></div>';
|
||||
str += '<div id="'+id+'_label" class="justify-content-center d-flex w-100 position-absolute" style="margin-top:2px">'+label+'</div>';
|
||||
str += '</div>'
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
function j_td(text, width='10', align='center', colspan='1') {
|
||||
str = '<td scope="col" colspan="'+colspan+'" style="width:'+width+'%; text-align:'+align+';">'+ text + '</td>';
|
||||
return str;
|
||||
}
|
||||
|
||||
function j_th(text, width='10', align='center', colspan='1') {
|
||||
str = '<th scope="col" colspan="'+colspan+'" style="width:'+width+'%; text-align:'+align+';">'+ text + '</td>';
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function make_log(key, value, left=2, right=10) {
|
||||
row = m_col(left, key, aligh='right');
|
||||
row += m_col(right, value, aligh='left');
|
||||
function j_info_text(key, value, left=2, right=10) {
|
||||
row = j_row_start(0);
|
||||
row += j_col(left, '<strong>' + key + '</strong>', aligh='right');
|
||||
row += j_col(right, value, aligh='left');
|
||||
row += j_row_end();
|
||||
return row;
|
||||
}
|
||||
|
||||
function j_info_text_left(key, value, left=3, right=9) {
|
||||
row = j_row_start(0);
|
||||
row += j_col(left, '<strong>' + key + '</strong>', aligh='left');
|
||||
row += j_col(right, value, aligh='left');
|
||||
row += j_row_end();
|
||||
return row;
|
||||
}
|
||||
|
||||
|
||||
function j_tab_make(data) {
|
||||
str = '<nav><div class="nav nav-tabs" id="nav-tab" role="tablist">';
|
||||
for (i in data) {
|
||||
if (data[i][2]) {
|
||||
str += '<a class="nav-item nav-link active" id="tab_head_'+data[i][0]+'" data-toggle="tab" href="#tab_content_'+data[i][0]+'" role="tab">'+data[i][1]+'</a>';
|
||||
} else {
|
||||
str += '<a class="nav-item nav-link" id="tab_head_'+data[i][0]+'" data-toggle="tab" href="#tab_content_'+data[i][0]+'" role="tab">'+data[i][1]+'</a>';
|
||||
}
|
||||
}
|
||||
str += '</div></nav>';
|
||||
str += '<div class="tab-content" id="nav-tabContent">';
|
||||
for (i in data) {
|
||||
if (data[i][2]) {
|
||||
str += '<div class="tab-pane fade show active" id="tab_content_'+data[i][0]+'" role="tabpanel" ></div>';
|
||||
} else {
|
||||
str += '<div class="tab-pane fade show" id="tab_content_'+data[i][0]+'" role="tabpanel" ></div>';
|
||||
}
|
||||
}
|
||||
str += '</div>';
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
// javascript에서 화면 생성
|
||||
function text_color(text, color='red') {
|
||||
return '<span style="color:'+color+'; font-weight:bold">' + text + '</span>';
|
||||
}
|
||||
|
||||
|
||||
function j_pre(text) {
|
||||
return '<pre style="word-wrap: break-word;white-space: pre-wrap;white-space: -moz-pre-wrap;white-space: -pre-wrap;white-space: -o-pre-wrap;word-break:break-all;">'+text+'</pre>';
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -277,10 +334,7 @@ document.addEventListener("DOMContentLoaded", function(){
|
||||
|
||||
|
||||
|
||||
function m_row_start_hover(padding='10', align='center') {
|
||||
var str = '<div class="row my_hover" style="padding-top: '+padding+'px; padding-bottom:'+padding+'px; align-items:'+align+';">';
|
||||
return str;
|
||||
}
|
||||
|
||||
function m_row_start_top(padding='10') {
|
||||
return m_row_start(padding, 'top');
|
||||
}
|
||||
@@ -309,46 +363,5 @@ function m_row_start_color2(padding='10', align='center') {
|
||||
|
||||
|
||||
|
||||
function m_tab_head(name, active) {
|
||||
if (active) {
|
||||
var str = '<a class="nav-item nav-link active" id="id_'+name+'" data-toggle="tab" href="#'+name+'" role="tab">'+name+'</a>';
|
||||
} else {
|
||||
var str = '<a class="nav-item nav-link" id="id_'+name+'" data-toggle="tab" href="#'+name+'" role="tab">'+name+'</a>';
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
function m_tab_content(name, content, active) {
|
||||
if (active) {
|
||||
var str = '<div class="tab-pane fade show active" id="'+name+'" role="tabpanel" >';
|
||||
} else {
|
||||
var str = '<div class="tab-pane fade show" id="'+name+'" role="tabpanel" >';
|
||||
}
|
||||
str += content;
|
||||
str += '</div>'
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function m_progress2(id, width, label) {
|
||||
var str = '';
|
||||
str += '<div class="progress" style="height: 25px;">'
|
||||
str += '<div id="'+id+'" class="progress-bar" style="background-color:yellow;width:'+width+'%"></div>';
|
||||
str += '<div id="'+id+'_label" class="justify-content-center d-flex w-100 position-absolute" style="margin:0px; margin-top:2px">'+label+'</div>';
|
||||
str += '</div>'
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
35
lib/framework/static/js/showdown-prettify.js
Normal file
35
lib/framework/static/js/showdown-prettify.js
Normal file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// Google Prettify
|
||||
// A showdown extension to add Google Prettify (http://code.google.com/p/google-code-prettify/)
|
||||
// hints to showdown's HTML output.
|
||||
//
|
||||
|
||||
(function () {
|
||||
|
||||
var prettify = function () {
|
||||
return [
|
||||
{
|
||||
type: 'output',
|
||||
filter: function (source) {
|
||||
return source.replace(/(<pre[^>]*>)?[\n\s]?<code([^>]*)>/gi, function (match, pre, codeClass) {
|
||||
if (pre) {
|
||||
return '<pre class="prettyprint linenums"><code' + codeClass + '>';
|
||||
} else {
|
||||
return ' <code class="prettyprint">';
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
// Client-side export
|
||||
if (typeof window !== 'undefined' && window.showdown && window.showdown.extensions) {
|
||||
window.showdown.extensions.prettify = prettify;
|
||||
}
|
||||
// Server-side export
|
||||
if (typeof module !== 'undefined') {
|
||||
module.exports = prettify;
|
||||
}
|
||||
|
||||
}());
|
||||
3
lib/framework/static/js/showdown_2.1.0.js
Normal file
3
lib/framework/static/js/showdown_2.1.0.js
Normal file
File diff suppressed because one or more lines are too long
@@ -35,6 +35,12 @@
|
||||
<script src="https://cdn.jsdelivr.net/gh/gitbrent/bootstrap4-toggle@3.4.0/js/bootstrap4-toggle.min.js"></script>
|
||||
<!-- end 토글 -->
|
||||
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.8.0/jquery.contextMenu.min.css">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.8.0/jquery.contextMenu.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.8.0/jquery.ui.position.js"></script>
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body class="body ">
|
||||
@@ -50,7 +56,8 @@
|
||||
</div>
|
||||
</main>
|
||||
<div class="loading" id="loading">
|
||||
<img src="/static/img/loading.gif" />
|
||||
<!-- <img src="/static/img/loading.gif" /> -->
|
||||
<img src="/static/img/loader.svg" />
|
||||
</div>
|
||||
{{ modals() }}
|
||||
</body>
|
||||
@@ -59,3 +66,5 @@
|
||||
<!-- 글로벌 버튼이 모두 나오고 처리-->
|
||||
<script src="{{ url_for('static', filename='js/sjva_global1.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/ff_global1.js') }}"></script>
|
||||
|
||||
<script src="{{ url_for('static', filename='js/ff_global_plugin.js') }}"></script>
|
||||
|
||||
@@ -8,13 +8,13 @@
|
||||
{{ macros.m_tab_head_end() }}
|
||||
</nav>
|
||||
<div class="tab-content" id="nav-tabContent">
|
||||
{{ macros.m_tab_content_start('이전', true) }}
|
||||
{{ macros.m_tab_content_start('old', true) }}
|
||||
<div>
|
||||
<textarea id="log" class="col-md-12" rows="30" charswidth="23" disabled style="background-color:#ffffff;visibility:hidden"></textarea>
|
||||
</div>
|
||||
{{ macros.m_tab_content_end() }}
|
||||
|
||||
{{ macros.m_tab_content_start('실시간', false) }}
|
||||
{{ macros.m_tab_content_start('new', false) }}
|
||||
<div>
|
||||
<textarea id="add" class="col-md-12" rows="30" charswidth="23" disabled style="background-color:#ffffff;visibility:visible"></textarea>
|
||||
</div>
|
||||
@@ -52,6 +52,7 @@ $(window).resize(function() {
|
||||
|
||||
var protocol = window.location.protocol;
|
||||
var socket = io.connect(protocol + "//" + document.domain + ":" + location.port + "/log");
|
||||
|
||||
socket.emit("start", {'package':'{{package}}'} );
|
||||
socket.on('on_start', function(data){
|
||||
document.getElementById("log").innerHTML += data.data;
|
||||
|
||||
@@ -25,11 +25,11 @@
|
||||
|
||||
<!-- 탭 -->
|
||||
{% macro m_tab_head_start() %}
|
||||
<div class="nav nav-tabs" id="nav-tab" role="tablist">
|
||||
<div class="nav nav-tabs" id="nav-tab" role="tablist">
|
||||
{% endmacro %}
|
||||
|
||||
{% macro m_tab_head_end() %}
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro m_tab_head(name, title, active) %}
|
||||
@@ -39,12 +39,25 @@
|
||||
<a class="nav-item nav-link" id="tab_{{name}}" data-toggle="tab" href="#{{name}}" role="tab">{{title}}</a>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
<!----------------------------------------------------------------->
|
||||
|
||||
|
||||
<!-- SETTING -->
|
||||
<!-- SETTING -->
|
||||
<!-- SETTING -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!------------------------------------------------------------------>
|
||||
<!-- 설정 -->
|
||||
|
||||
<!-- SETTING 기본 틀-->
|
||||
{% macro setting_top(left='', padding='10') %}
|
||||
@@ -57,6 +70,16 @@
|
||||
<div class='col-sm-9'>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro setting_top_big(left='', padding='10') %}
|
||||
<div class='row' style="padding-top: {{padding}}px; padding-bottom:{{padding}}px; align-items: center;">
|
||||
<div class='col-sm-3 set-left'>
|
||||
{% if left != '' %}
|
||||
<strong><h4>{{ left }}</h4></strong>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class='col-sm-9'>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro setting_bottom(desc=None, padding_top='5') %}
|
||||
{% if desc is not none %}
|
||||
<div style="padding-left:20px; padding-top:{{padding_top}}px;">
|
||||
@@ -247,18 +270,39 @@
|
||||
|
||||
|
||||
<!-- 스케쥴링 작동 버튼-->
|
||||
{% macro setting_global_scheduler_button(is_include, is_running, id='scheduler', left='스케쥴링 작동', desc=['On : 스케쥴링 시작','Off : 스케쥴링 중지']) %}
|
||||
{% macro global_setting_scheduler_button(is_include, is_running, id='scheduler', left='스케쥴링 작동', desc=['On : 스케쥴링 시작','Off : 스케쥴링 중지']) %}
|
||||
{{ setting_top(left) }}
|
||||
<div class="input-group col-sm-3">
|
||||
{% if is_include == True %}
|
||||
{% if is_include == True or is_include == "True" %}
|
||||
<input id="globalSchedulerSwitchBtn" name="globalSchedulerSwitchBtn" class="form-control form-control-sm" type="checkbox" data-toggle="toggle" checked>
|
||||
{% else %}
|
||||
<input id="globalSchedulerSwitchBtn" name="globalSchedulerSwitchBtn" class="form-control form-control-sm" type="checkbox" data-toggle="toggle">
|
||||
{% endif %}
|
||||
{% if is_running == True %}
|
||||
{% if is_running == True or is_running == "True" %}
|
||||
<span style="padding-left:10px; padding-top: 8px; font-weight: bold;">실행중</span>
|
||||
{% else %}
|
||||
{% if is_include == True %}
|
||||
{% if is_include == True or is_include == "True" %}
|
||||
<span style="padding-left:10px; padding-top: 8px; ">대기중</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{{ setting_bottom(desc) }}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
<!-- 스케쥴링 작동 버튼 페이지 -->
|
||||
{% macro global_setting_scheduler_button_page(is_include, is_running, id='scheduler', left='스케쥴링 작동', desc=['On : 스케쥴링 시작','Off : 스케쥴링 중지']) %}
|
||||
{{ setting_top(left) }}
|
||||
<div class="input-group col-sm-3">
|
||||
{% if is_include == True or is_include == "True" %}
|
||||
<input id="globalSchedulerSwitchPageBtn" name="globalSchedulerSwitchPageBtn" class="form-control form-control-sm" type="checkbox" data-toggle="toggle" checked>
|
||||
{% else %}
|
||||
<input id="globalSchedulerSwitchPageBtn" name="globalSchedulerSwitchPageBtn" class="form-control form-control-sm" type="checkbox" data-toggle="toggle">
|
||||
{% endif %}
|
||||
{% if is_running == True or is_running == "True" %}
|
||||
<span style="padding-left:10px; padding-top: 8px; font-weight: bold;">실행중</span>
|
||||
{% else %}
|
||||
{% if is_include == True or is_include == "True" %}
|
||||
<span style="padding-left:10px; padding-top: 8px; ">대기중</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
@@ -268,13 +312,116 @@
|
||||
|
||||
|
||||
|
||||
setting_gole
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- NOT SETTING -->
|
||||
<!-- NOT SETTING -->
|
||||
<!-- NOT SETTING -->
|
||||
<!-- SELECT Dummy
|
||||
option을 script로 넣을 때 사용
|
||||
예: 시스템 - 전체로그
|
||||
-->
|
||||
{% macro setting_select_empty(id, title, col='9', desc=None, value=None) %}
|
||||
{{ setting_top(title) }}
|
||||
<div class="input-group col-sm-{{col}}">
|
||||
<div id="{{id}}_div" name="{{id}}_div"></div>
|
||||
</div>
|
||||
{{ setting_bottom(desc) }}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
|
||||
{% macro setting_input_int(id, left, value='', min='', max='', placeholder='', desc=None) %}
|
||||
{{ setting_top(left) }}
|
||||
<div class="input-group col-sm-3">
|
||||
<input id="{{ id }}" name="{{ id }}" type="number" class="form-control form-control-sm"
|
||||
{% if min != '' %}
|
||||
min="{{ min }}"
|
||||
{% endif %}
|
||||
{% if max != '' %}
|
||||
max="{{ max }}"
|
||||
{% endif %}
|
||||
{% if placeholder != '' %}
|
||||
placeholder="{{ placeholder }}"
|
||||
{% endif %}
|
||||
value="{{ value }}">
|
||||
</div>
|
||||
{{ setting_bottom(desc) }}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
|
||||
<!-- 토글버튼형식 -->
|
||||
{% macro setting_checkbox(id, left, value, desc='') %}
|
||||
{{ setting_top(left) }}
|
||||
<div class="input-group col-sm-3">
|
||||
{% if value == True or value == 'True' or value == 'true' or value == 'On' %}
|
||||
<input id="{{ id }}" name="{{ id }}" class="form-control form-control-sm" type="checkbox" data-toggle="toggle" checked>
|
||||
{% else %}
|
||||
<input id="{{ id }}" name="{{ id }}" class="form-control form-control-sm" type="checkbox" data-toggle="toggle">
|
||||
{% endif %}
|
||||
</div>
|
||||
{{ setting_bottom(desc) }}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!------------------------------------------------------------------>
|
||||
<!-- 설정 외 -->
|
||||
|
||||
<!-- 리스트 div로 꾸밀때 헤드 -->
|
||||
{% macro m_hr_head_top() %}
|
||||
<div class="d-inline-block"></div>
|
||||
<hr style="width: 100%; margin:0px; background-color:#808080;">
|
||||
{% endmacro %}
|
||||
|
||||
{% macro m_hr_head_bottom() %}
|
||||
<hr style="width: 100%; margin:0px; margin-bottom:10px; margin-top:2px; background-color:#808080; height:2px" />
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
<!-- 버튼 그룹 -->
|
||||
{% macro m_button_group(buttons) %}
|
||||
<div class="btn-group btn-group-sm flex-wrap mr-2" role="group">
|
||||
@@ -304,6 +451,14 @@
|
||||
{{ setting_bottom(desc, padding_top='-5') }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro info_text_big(id, left, value='', desc=None) %}
|
||||
{{ setting_top_big(left) }}
|
||||
<div style="padding-left:20px; padding-top:-5px;">
|
||||
<span id={{id}}><h4>{{value}}</h4></span>
|
||||
</div>
|
||||
{{ setting_bottom(desc, padding_top='-5') }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro info_text_go(id, left, value='', desc=None, padding=10) %}
|
||||
{{ setting_top(left, padding) }}
|
||||
<div style="padding-left:20px; padding-top:-5px;">
|
||||
@@ -354,219 +509,208 @@
|
||||
|
||||
|
||||
|
||||
<!-- SELECT Dummy
|
||||
option을 script로 넣을 때 사용
|
||||
예: 시스템 - 전체로그
|
||||
-->
|
||||
{% macro setting_select_empty(id, title, col='9', desc=None, value=None) %}
|
||||
{{ setting_top(title) }}
|
||||
<div class="input-group col-sm-{{col}}">
|
||||
<div id="{{id}}_div" name="{{id}}_div"></div>
|
||||
</div>
|
||||
{{ setting_bottom(desc) }}
|
||||
|
||||
|
||||
{% macro m_modal_start(id, title, size) %}
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="{{id}}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog {{size}}">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title" id="{{id}}_title">{{title}}</h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
</div>
|
||||
<div class="modal-body" id="{{id}}_modal_body" style="word-break:break-all;">
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 삭제해야함 --------------------------------------------------------->
|
||||
<!--
|
||||
{% macro setting_radio(id, title, radios, value=None, desc=None, disabled=False) %}
|
||||
{{ setting_top(title) }}
|
||||
<div class="input-group col-sm-9">
|
||||
{% for r in radios %}
|
||||
<div class="custom-control custom-radio custom-control-inline">
|
||||
{% if value|int == loop.index0 %}
|
||||
<input id="{{id}}{{loop.index0}}" type="radio" class="custom-control-input" name="{{id}}" value="{{loop.index0}}" checked {% if disabled %} disabled {% endif %}>
|
||||
{% else %}
|
||||
<input id="{{id}}{{loop.index0}}" type="radio" class="custom-control-input" name="{{id}}" value="{{loop.index0}}" {% if disabled %} disabled {% endif %}>
|
||||
{% endif %}
|
||||
<label class="custom-control-label" for="{{id}}{{loop.index0}}">{{r}}</label>
|
||||
{% macro m_modal_end() %}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-warning" data-dismiss="modal">닫기 (취소)</button>
|
||||
</div>
|
||||
<div class="loading" id="modal_loading">
|
||||
<img src="/static/img/loading.gif" />
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{{ setting_bottom(desc) }}
|
||||
</div>
|
||||
</div>
|
||||
<!-- Modal end -->
|
||||
{% endmacro %}
|
||||
-->
|
||||
|
||||
<!-- 그룹화 하지 않음.. 삭제-->
|
||||
<!--
|
||||
{% macro setting_button(buttons, left='', desc='') %}
|
||||
{{ setting_top(left) }}
|
||||
<div class="input-group col-sm-9">
|
||||
{% for b in buttons %}
|
||||
{% if not loop.first %}
|
||||
<span class='text-left' style="padding-left:5px; padding-top:0px">
|
||||
{% endif %}
|
||||
<button id="{{b[0]}}" class="btn btn-sm btn-outline-primary">{{b[1]}}</button>
|
||||
</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{{ setting_bottom(desc) }}
|
||||
{% endmacro %}
|
||||
-->
|
||||
<!----------------------------------------------------------------->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{% macro setting_input_int(id, left, value='', min='', max='', placeholder='', desc=None) %}
|
||||
{{ setting_top(left) }}
|
||||
<div class="input-group col-sm-3">
|
||||
<input id="{{ id }}" name="{{ id }}" type="number" class="form-control form-control-sm"
|
||||
{% if min != '' %}
|
||||
min="{{ min }}"
|
||||
{% endif %}
|
||||
{% if max != '' %}
|
||||
max="{{ max }}"
|
||||
{% endif %}
|
||||
{% if placeholder != '' %}
|
||||
placeholder="{{ placeholder }}"
|
||||
{% endif %}
|
||||
value="{{ value }}">
|
||||
{% macro m_modal_end_with_button(buttons) %}
|
||||
</div>
|
||||
{{ setting_bottom(desc) }}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
|
||||
<!-- 토글버튼형식 -->
|
||||
{% macro setting_checkbox(id, left, value, desc='') %}
|
||||
{{ setting_top(left) }}
|
||||
<div class="input-group col-sm-3">
|
||||
{% if value == 'True' or value == 'true' or value == 'On' %}
|
||||
<input id="{{ id }}" name="{{ id }}" class="form-control form-control-sm" type="checkbox" data-toggle="toggle" checked>
|
||||
{% else %}
|
||||
<input id="{{ id }}" name="{{ id }}" class="form-control form-control-sm" type="checkbox" data-toggle="toggle">
|
||||
{% endif %}
|
||||
<div class="modal-footer">
|
||||
<div class="btn-group btn-group-sm flex-wrap mr-2" role="group">
|
||||
{% for b in buttons %}
|
||||
<button id="{{b[0]}}" class="btn btn-sm btn-outline-primary"
|
||||
{% if b|length > 2 %}
|
||||
{% for d in b[2] %}
|
||||
data-{{d[0]}}="{{d[1]}}""
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
>{{b[1]}}</button>
|
||||
{% endfor %}
|
||||
<button type="button" class="btn btn-sm btn-warning" data-dismiss="modal">닫기 (취소)</button>
|
||||
</div>
|
||||
</div>
|
||||
{{ setting_bottom(desc) }}
|
||||
<div class="loading" id="modal_loading">
|
||||
<img src="/static/img/loading.gif" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Modal end -->
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
|
||||
|
||||
{% macro print_md(id, text) %}
|
||||
<div id="{{id}}_div" data-text="{{text}}"></div>
|
||||
<script type="text/javascript">
|
||||
ret = converter.makeHtml($('#{{id}}_div').data('text'));
|
||||
$('#{{id}}_div').html(ret);
|
||||
</script>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro print_md1(id, text) %}
|
||||
|
||||
<script type="text/javascript">
|
||||
ret = converter.makeHtml($('#{{id}}_div').data('text'));
|
||||
</script>
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
|
||||
<!----------------------------------------------------------->
|
||||
<!----------------------------------------------------------->
|
||||
<!----------------------------------------------------------->
|
||||
<!----------------------------------------------------------->
|
||||
<!----------------------------------------------------------->
|
||||
<!--이하 정리 필요------------------------>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 일반적인 체크박스 -->
|
||||
{% macro setting_default_checkbox(id, left, label, value, desc='') %}
|
||||
@@ -584,31 +728,6 @@ option을 script로 넣을 때 사용
|
||||
{{ setting_bottom(desc) }}
|
||||
{% endmacro %}
|
||||
|
||||
<!-- 스케쥴러 스위치 체크박스 전용-->
|
||||
{% macro setting_scheduler_switch(left='스케쥴링 작동', desc=['On : 스케쥴링 시작','Off : 스케쥴링 중지'], is_include='False', is_running='False') %}
|
||||
{{ setting_top(left) }}
|
||||
<div class="input-group col-sm-3">
|
||||
{% if is_include == 'True' %}
|
||||
<input id="scheduler_swtich_btn" name="scheduler_swtich_btn" class="form-control form-control-sm" type="checkbox" data-toggle="toggle" checked>
|
||||
{% else %}
|
||||
<input id="scheduler_swtich_btn" name="scheduler_swtich_btn" class="form-control form-control-sm" type="checkbox" data-toggle="toggle">
|
||||
{% endif %}
|
||||
{% if is_running == 'True' %}
|
||||
<span style="padding-left:10px; padding-top: 8px;">동작중</span>
|
||||
{% else %}
|
||||
{% if is_include == 'True' %}
|
||||
<span style="padding-left:10px; padding-top: 8px;">대기중</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{{ setting_bottom(desc) }}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
@@ -637,6 +756,26 @@ macros.setting_button_with_info([['toggle_btn', 'Toggle', [{'key':'category', 'v
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{% macro select(id, options, col='3', value=None) %}
|
||||
<div class="input-group col-sm-{{col}}" style="padding-left:0px; padding-top:0px">
|
||||
|
||||
<select id="{{id}}" name="{{id}}" class="form-control form-control-sm">
|
||||
{% for item in options %}
|
||||
{% if value is not none and value == item[0] %}
|
||||
<option value="{{ item[0] }}" selected>{{item[1]}}</option>
|
||||
{% else %}
|
||||
<option value="{{ item[0] }}">{{item[1]}}</option>
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
|
||||
<!-- select -->
|
||||
{% macro setting_select(id, title, options, col='9', desc=None, value=None) %}
|
||||
{{ setting_top(title) }}
|
||||
@@ -655,21 +794,6 @@ macros.setting_button_with_info([['toggle_btn', 'Toggle', [{'key':'category', 'v
|
||||
{{ setting_bottom(desc) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro select(id, options, col='3', value=None) %}
|
||||
<div class="input-group col-sm-{{col}}" style="padding-left:0px; padding-top:0px">
|
||||
|
||||
<select id="{{id}}" name="{{id}}" class="form-control form-control-sm">
|
||||
{% for item in options %}
|
||||
{% if value is not none and value == item[0] %}
|
||||
<option value="{{ item[0] }}" selected>{{item[1]}}</option>
|
||||
{% else %}
|
||||
<option value="{{ item[0] }}">{{item[1]}}</option>
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
<!-- select + 버튼 -->
|
||||
@@ -703,15 +827,6 @@ macros.setting_button_with_info([['toggle_btn', 'Toggle', [{'key':'category', 'v
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!--progress-bar-striped progress-bar-animated-->
|
||||
{% macro setting_progress(id, left='', desc='') %}
|
||||
{{ setting_top(left) }}
|
||||
@@ -725,66 +840,6 @@ macros.setting_button_with_info([['toggle_btn', 'Toggle', [{'key':'category', 'v
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
<!-- 스케쥴링 작동 버튼-->
|
||||
{% macro setting_scheduler_button(is_include, is_running, id='scheduler', left='스케쥴링 작동', desc=['On : 스케쥴링 시작','Off : 스케쥴링 중지']) %}
|
||||
{{ setting_top(left) }}
|
||||
<div class="input-group col-sm-3">
|
||||
{% if is_include == 'True' %}
|
||||
<input id="scheduler" name="scheduler" class="form-control form-control-sm" type="checkbox" data-toggle="toggle" checked>
|
||||
{% else %}
|
||||
<input id="scheduler" name="scheduler" class="form-control form-control-sm" type="checkbox" data-toggle="toggle">
|
||||
{% endif %}
|
||||
{% if is_running == 'True' %}
|
||||
<span style="padding-left:10px; padding-top: 8px;">동작중</span>
|
||||
{% else %}
|
||||
{% if is_include == 'True' %}
|
||||
<span style="padding-left:10px; padding-top: 8px;">대기중</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{{ setting_bottom(desc) }}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
|
||||
|
||||
{% macro setting_global_scheduler_sub_button(is_include, is_running, id='scheduler', left='스케쥴링 작동', desc=['On : 스케쥴링 시작','Off : 스케쥴링 중지']) %}
|
||||
{{ setting_top(left) }}
|
||||
<div class="input-group col-sm-3">
|
||||
{% if is_include == 'True' %}
|
||||
<input id="global_scheduler_sub" name="global_scheduler_sub" class="form-control form-control-sm" type="checkbox" data-toggle="toggle" checked>
|
||||
{% else %}
|
||||
<input id="global_scheduler_sub" name="global_scheduler_sub" class="form-control form-control-sm" type="checkbox" data-toggle="toggle">
|
||||
{% endif %}
|
||||
{% if is_running == 'True' %}
|
||||
<span style="padding-left:10px; padding-top: 8px;">동작중</span>
|
||||
{% else %}
|
||||
{% if is_include == 'True' %}
|
||||
<span style="padding-left:10px; padding-top: 8px;">대기중</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{{ setting_bottom(desc) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro setting_global_scheduler_sublogic_button(is_include, is_running, id='scheduler', left='스케쥴링 작동', desc=['On : 스케쥴링 시작','Off : 스케쥴링 중지']) %}
|
||||
{{ setting_top(left) }}
|
||||
<div class="input-group col-sm-3">
|
||||
{% if is_include == 'True' %}
|
||||
<input id="global_scheduler_sublogic" name="global_scheduler_sublogic" class="form-control form-control-sm" type="checkbox" data-toggle="toggle" checked>
|
||||
{% else %}
|
||||
<input id="global_scheduler_sublogic" name="global_scheduler_sublogic" class="form-control form-control-sm" type="checkbox" data-toggle="toggle">
|
||||
{% endif %}
|
||||
{% if is_running == 'True' %}
|
||||
<span style="padding-left:10px; padding-top: 8px;">동작중</span>
|
||||
{% else %}
|
||||
{% if is_include == 'True' %}
|
||||
<span style="padding-left:10px; padding-top: 8px;">대기중</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{{ setting_bottom(desc) }}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
|
||||
@@ -803,14 +858,7 @@ macros.setting_button_with_info([['toggle_btn', 'Toggle', [{'key':'category', 'v
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{% macro m_hr_head_top() %}
|
||||
<div class="d-inline-block"></div>
|
||||
<hr style="width: 100%; margin:0px; background-color:#808080;">
|
||||
{% endmacro %}
|
||||
|
||||
{% macro m_hr_head_bottom() %}
|
||||
<hr style="width: 100%; margin:0px; margin-bottom:10px; margin-top:2px; background-color:#808080; height:2px" />
|
||||
{% endmacro %}
|
||||
|
||||
{% macro m_button(id, text) %}
|
||||
<button id="{{id}}" name="{{id}}" class="btn btn-sm btn-outline-primary">{{text}}</button>
|
||||
@@ -836,59 +884,6 @@ macros.setting_button_with_info([['toggle_btn', 'Toggle', [{'key':'category', 'v
|
||||
|
||||
|
||||
|
||||
{% macro m_modal_start(id, title, size) %}
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="{{id}}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog {{size}}">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title" id="{{id}}_title">{{title}}</h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
</div>
|
||||
<div class="modal-body" id="modal_body" style="word-break:break-all;">
|
||||
{% endmacro %}
|
||||
|
||||
{% macro m_modal_end() %}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">닫기</button>
|
||||
</div>
|
||||
<div class="loading" id="modal_loading">
|
||||
<img src="/static/img/loading.gif" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Modal end -->
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{% macro m_modal_start2(id, title, size) %}
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="{{id}}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog {{size}}">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title" id="{{id}}_title">{{title}}</h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
</div>
|
||||
<div class="loading" id="modal_loading">
|
||||
<img src="/static/img/loading.gif" />
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro m_modal_end2() %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Modal end -->
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{% macro row_start(padding='10') %}
|
||||
<div class='row' style="padding-top: {{padding}}px; padding-bottom:{{padding}}px; align-items: center;">
|
||||
@@ -1002,16 +997,3 @@ macros.setting_button_with_info([['toggle_btn', 'Toggle', [{'key':'category', 'v
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 다른이름으로 정의함. 나중에 삭제 -->
|
||||
{% macro buttons(buttons, left='', desc='') %}
|
||||
{{ setting_top(left) }}
|
||||
<div class="input-group col-sm-9">
|
||||
<div class="btn-group btn-group-sm flex-wrap mr-2" role="group">
|
||||
{% for b in buttons %}
|
||||
<button id="{{b[0]}}" class="btn btn-sm btn-outline-primary">{{b[1]}}</button>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{{ setting_bottom(desc) }}
|
||||
{% endmacro %}
|
||||
@@ -14,7 +14,7 @@
|
||||
<div class="modal-body" id="modal_body" style="word-break:break-all;">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">닫기</button>
|
||||
<button type="button" class="btn btn-warning" data-dismiss="modal">닫기</button>
|
||||
<!--<button type="button" class="btn btn-primary">Save changes</button>-->
|
||||
</div>
|
||||
</div>
|
||||
@@ -70,7 +70,7 @@
|
||||
<div class="modal-footer">
|
||||
<button type="button" id='select_local_file_modal_confirm_btn' class="btn btn-success" data-dismiss="modal">선택
|
||||
</button>
|
||||
<button type="button" id='select_local_file_modal_cancel_btn' class="btn btn-default" data-dismiss="modal">닫기
|
||||
<button type="button" id='select_local_file_modal_cancel_btn' class="btn btn-warning" data-dismiss="modal">닫기
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
{% if 'uri' in category and category['uri'].startswith('http') %}
|
||||
<li class="nav-item"> <a class="nav-link" href="{{ category['uri']}}" target="_blank">{{category['name']}}</a></li>
|
||||
{% elif 'uri' in category and category['uri'].startswith('http') == False %}
|
||||
<li class="nav-item"> <a class="nav-link" href="{{ category['uri']}}">{{category['name']}}</a></li>
|
||||
<li class="nav-item"> <a class="nav-link" href="/{{ category['uri']}}">{{category['name']}}</a></li>
|
||||
{% else %}
|
||||
<!--{{ category }}-->
|
||||
<li class="nav-item dropdown">
|
||||
@@ -134,10 +134,11 @@
|
||||
{% if current_menu[0] == plugin['uri'] and 'list' in plugin %}
|
||||
{% for module in plugin['list'] %}
|
||||
{% if module['uri'] == current_menu[1] and 'list' in module%}
|
||||
<!--{{ module }}-->
|
||||
<!-- {{ module }} -->
|
||||
<ul class="nav nav-pills bg-light shadow text-dark">
|
||||
{% for page in module['list'] %}
|
||||
{% if current_menu[2] == page['uri'] %}
|
||||
<!--{{ current_menu }}-->
|
||||
{% if current_menu[2]!= None and page['uri'].startswith(current_menu[2]) %}
|
||||
<li class="nav-item"><a class="nav-link active" href="/{{ current_menu[0] }}/{{ current_menu[1] }}/{{ page['uri'] }}">{{page['name']}}</a></li>
|
||||
{% else %}
|
||||
<li class="nav-item"><a class="nav-link" href="/{{ current_menu[0] }}/{{ current_menu[1] }}/{{ page['uri'] }}">{{page['name']}}</a></li>
|
||||
|
||||
@@ -1,30 +1,32 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
{% filter markdown %}
|
||||
{{ data }}
|
||||
{% endfilter %}
|
||||
<script src="https://cdn.jsdelivr.net/gh/google/code-prettify@master/loader/run_prettify.js?autorun=true&lang=css&lang=python&skin=sunburst"></script>
|
||||
|
||||
|
||||
<style type="text/css">
|
||||
img{
|
||||
<script src="{{ url_for('static', filename='js/showdown_2.1.0.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/showdown-prettify.js') }}"></script>
|
||||
<link href="{{ url_for('static', filename='css/showdown.css') }}" rel="stylesheet">
|
||||
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div id="md_div" data-url="{{ arg }}"></div>
|
||||
<div id="content_div" data-url="{{ arg }}"></div>
|
||||
|
||||
<meta id="text" data-text="{{data}}">
|
||||
<div id="text_div"></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function(){
|
||||
//$('#main_container').attr('class', 'container-fluid');
|
||||
});
|
||||
$(document).ready(function(){
|
||||
var converter = new showdown.Converter({extensions: ['prettify']});
|
||||
converter.setOption('tables', true);
|
||||
converter.setOption('strikethrough', true);
|
||||
converter.setOption('ghCodeBlocks',true);
|
||||
|
||||
text = $('#text').data('text');
|
||||
if (window.location.href.endsWith('.yaml')) {
|
||||
text = "```" + text + "```";
|
||||
}
|
||||
html = converter.makeHtml(text);
|
||||
$('#text_div').html(html);
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
30
lib/framework/templates/manual_old.html
Normal file
30
lib/framework/templates/manual_old.html
Normal file
@@ -0,0 +1,30 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
|
||||
{% filter markdown %}
|
||||
{{ data }}
|
||||
{% endfilter %}
|
||||
|
||||
|
||||
<style type="text/css">
|
||||
img{
|
||||
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div id="md_div" data-url="{{ arg }}"></div>
|
||||
<div id="content_div" data-url="{{ arg }}"></div>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function(){
|
||||
//$('#main_container').attr('class', 'container-fluid');
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
|
||||
<html>
|
||||
<title>{{data['play_title']}}</title>
|
||||
<script src="https://vjs.zencdn.net/7.11.4/video.min.js"></script>
|
||||
<link href="https://vjs.zencdn.net/7.11.4/video-js.css" rel="stylesheet" />
|
||||
@@ -63,3 +65,4 @@ player.ready(function(){
|
||||
|
||||
player.play();
|
||||
</script>
|
||||
</html>
|
||||
|
||||
90
lib/framework/templates/videojs_discord.html
Normal file
90
lib/framework/templates/videojs_discord.html
Normal file
@@ -0,0 +1,90 @@
|
||||
<title>aaaa</title>
|
||||
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" name="viewport">
|
||||
<meta content="ie=edge" http-equiv="X-UA-Compatible">
|
||||
<meta content="width=device-width, initial-scale=1" name="viewport">
|
||||
<link href="/media/avatar.png" rel="icon" type="image/jpeg">
|
||||
<link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" rel="stylesheet" />
|
||||
<link href="https://unpkg.com/aos@2.3.1/dist/aos.css" rel="stylesheet" />
|
||||
<link href="https://unpkg.com/swiper@7/swiper-bundle.min.css" rel="stylesheet" />
|
||||
<link href='https://unpkg.com/boxicons@2.1.2/css/boxicons.min.css' rel='stylesheet'>
|
||||
<link href="/css/style.css" rel="stylesheet" />
|
||||
<link href="/css/style_dark.css" rel="stylesheet" />
|
||||
<link href="/media/favicon.png" rel="icon" type="image/jpeg">
|
||||
<meta property="og:site_name" content="aaaaaaaaaaaaaaaaa" />
|
||||
<meta property="og:url" content="https://ff.soju6jan.synology.me/gds_tool/api/route/streaming.mp4?apikey=ooo5298ooo&type=file&id=1gtpG7CAUKTWu6wxWtCKx-XN01PMz70v8" />
|
||||
<meta property="og:type" content="video.other" />
|
||||
<meta property="og:title" content="Mini rengar xD" />
|
||||
<meta property="og:image" content="https://outplays.eu/Q5THkfY3/thumbnail.png" />
|
||||
<meta property="og:video" content="https://ff.soju6jan.synology.me/gds_tool/api/route/streaming.mp4?apikey=ooo5298ooo&type=file&id=1gtpG7CAUKTWu6wxWtCKx-XN01PMz70v8" />
|
||||
<meta property="og:video:type" content="video/mp4" />
|
||||
<meta property="og:video:secure_url" content="https://ff.soju6jan.synology.me/gds_tool/api/route/streaming.mp4?apikey=ooo5298ooo&type=file&id=1gtpG7CAUKTWu6wxWtCKx-XN01PMz70v8" />
|
||||
<meta property="og:video:height" content="1080" />
|
||||
<meta property="og:video:width" content="1920" />
|
||||
<meta property="og:image:height" content="1080" />
|
||||
<meta property="og:image:width" content="1920" />
|
||||
|
||||
|
||||
|
||||
<script src="https://vjs.zencdn.net/7.11.4/video.min.js"></script>
|
||||
<link href="https://vjs.zencdn.net/7.11.4/video-js.css" rel="stylesheet" />
|
||||
|
||||
<body bgcolor='black'>
|
||||
<video id=player width=960 height=540 class="video-js vjs-default-skin vjs-16-9" autoplay controls>
|
||||
<source
|
||||
src="https://ff.soju6jan.synology.me/gds_tool/api/route/streaming.mp4?apikey=ooo5298ooo&type=file&id=1gtpG7CAUKTWu6wxWtCKx-XN01PMz70v8"
|
||||
type="application/x-mpegURL" />
|
||||
</video>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
var subtitle_src = "aaaa";
|
||||
let options = {
|
||||
html5: {
|
||||
nativeTextTracks: false
|
||||
},
|
||||
playbackRates: [.5, .75, 1, 1.5, 2],
|
||||
controls: true,
|
||||
preload: "auto",
|
||||
controlBar: {
|
||||
playToggle: false,
|
||||
pictureInPictureToggle: false,
|
||||
remainingTimeDisplay: true,
|
||||
qualitySelector: true,
|
||||
}
|
||||
};
|
||||
let player = videojs('player', options);
|
||||
|
||||
player.ready(function(){
|
||||
// set subtitle track
|
||||
if (subtitle_src != "") {
|
||||
var suburl = subtitle_src.replace(/&/g, '&');
|
||||
let captionOption = {
|
||||
kind: 'captions',
|
||||
srclang: 'ko',
|
||||
label: 'Korean',
|
||||
src: suburl,
|
||||
mode: 'showing'
|
||||
};
|
||||
player.addRemoteTextTrack(captionOption);
|
||||
|
||||
var settings = this.textTrackSettings;
|
||||
settings.setValues({
|
||||
"backgroundColor": "#000",
|
||||
"backgroundOpacity": "0",
|
||||
"edgeStyle": "uniform",
|
||||
});
|
||||
settings.updateDisplay();
|
||||
}
|
||||
else {
|
||||
var tracks = player.textTracks();
|
||||
for (var i = 0; i < tracks.length; i++) {
|
||||
var track = tracks[i];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
player.play();
|
||||
</script>
|
||||
@@ -34,8 +34,8 @@ class Util(object):
|
||||
paging['count'] = count
|
||||
F.logger.debug('paging : c:%s %s %s %s %s %s', count, paging['total_page'], paging['prev_page'], paging['next_page'] , paging['start_page'], paging['last_page'])
|
||||
return paging
|
||||
except Exception as exception:
|
||||
F.logger.debug('Exception:%s', exception)
|
||||
except Exception as e:
|
||||
F.logger.debug(f"Exception:{str(e)}")
|
||||
F.logger.debug(traceback.format_exc())
|
||||
|
||||
|
||||
@@ -60,8 +60,8 @@ class Util(object):
|
||||
ret['dirname'] = max_filename.replace('/%s' % ret['filename'], '')
|
||||
ret['max_size'] = max_size
|
||||
return ret
|
||||
except Exception as exception:
|
||||
F.logger.error('Exception:%s', exception)
|
||||
except Exception as e:
|
||||
F.logger.error(f"Exception:{str(e)}")
|
||||
F.logger.error(traceback.format_exc())
|
||||
|
||||
|
||||
@@ -81,8 +81,8 @@ class Util(object):
|
||||
import shutil
|
||||
shutil.rmtree(zip_path)
|
||||
return True
|
||||
except Exception as exception:
|
||||
F.logger.error('Exception:%s', exception)
|
||||
except Exception as e:
|
||||
F.logger.error(f"Exception:{str(e)}")
|
||||
F.logger.error(traceback.format_exc())
|
||||
return False
|
||||
|
||||
@@ -92,12 +92,12 @@ class Util(object):
|
||||
def make_apikey(url):
|
||||
from framework import SystemModelSetting
|
||||
url = url.format(ddns=SystemModelSetting.get('ddns'))
|
||||
if SystemModelSetting.get_bool('auth_use_apikey'):
|
||||
if SystemModelSetting.get_bool('use_apikey'):
|
||||
if url.find('?') == -1:
|
||||
url += '?'
|
||||
else:
|
||||
url += '&'
|
||||
url += 'apikey=%s' % SystemModelSetting.get('auth_apikey')
|
||||
url += 'apikey=%s' % SystemModelSetting.get('apikey')
|
||||
return url
|
||||
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
VERSION="4.0.47"
|
||||
VERSION="4.1.40"
|
||||
Reference in New Issue
Block a user