mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2024-08-30 18:23:09 +00:00
Add unzip/dir request handler to api v2
This commit is contained in:
parent
d9e405e56c
commit
27f6c4c926
@ -325,3 +325,12 @@ class FileHelpers:
|
|||||||
else:
|
else:
|
||||||
return "false"
|
return "false"
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def unzip_server(self, zip_path, user_id):
|
||||||
|
if Helpers.check_file_perms(zip_path):
|
||||||
|
temp_dir = tempfile.mkdtemp()
|
||||||
|
with zipfile.ZipFile(zip_path, "r") as zip_ref:
|
||||||
|
# extracts archive to temp directory
|
||||||
|
zip_ref.extractall(temp_dir)
|
||||||
|
if user_id:
|
||||||
|
return temp_dir
|
||||||
|
@ -1135,17 +1135,6 @@ class Helpers:
|
|||||||
</input></div><li>"""
|
</input></div><li>"""
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def unzip_server(self, zip_path, user_id):
|
|
||||||
if Helpers.check_file_perms(zip_path):
|
|
||||||
temp_dir = tempfile.mkdtemp()
|
|
||||||
with zipfile.ZipFile(zip_path, "r") as zip_ref:
|
|
||||||
# extracts archive to temp directory
|
|
||||||
zip_ref.extractall(temp_dir)
|
|
||||||
if user_id:
|
|
||||||
self.websocket_helper.broadcast_user(
|
|
||||||
user_id, "send_temp_path", {"path": temp_dir}
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def unzip_backup_archive(backup_path, zip_name):
|
def unzip_backup_archive(backup_path, zip_name):
|
||||||
zip_path = os.path.join(backup_path, zip_name)
|
zip_path = os.path.join(backup_path, zip_name)
|
||||||
|
@ -41,10 +41,10 @@ scheduler_intervals = {
|
|||||||
class TasksManager:
|
class TasksManager:
|
||||||
controller: Controller
|
controller: Controller
|
||||||
|
|
||||||
def __init__(self, helper, controller):
|
def __init__(self, helper, controller, file_helper):
|
||||||
self.helper: Helpers = helper
|
self.helper: Helpers = helper
|
||||||
self.controller: Controller = controller
|
self.controller: Controller = controller
|
||||||
self.tornado: Webserver = Webserver(helper, controller, self)
|
self.tornado: Webserver = Webserver(helper, controller, self, file_helper)
|
||||||
try:
|
try:
|
||||||
self.tz = get_localzone()
|
self.tz = get_localzone()
|
||||||
except ZoneInfoNotFoundError as e:
|
except ZoneInfoNotFoundError as e:
|
||||||
|
@ -9,7 +9,7 @@ import bleach
|
|||||||
import tornado.web
|
import tornado.web
|
||||||
import tornado.escape
|
import tornado.escape
|
||||||
|
|
||||||
from app.classes.shared.console import Console
|
from app.classes.shared.file_helpers import FileHelpers
|
||||||
from app.classes.shared.helpers import Helpers
|
from app.classes.shared.helpers import Helpers
|
||||||
from app.classes.shared.server import ServerOutBuf
|
from app.classes.shared.server import ServerOutBuf
|
||||||
from app.classes.web.base_handler import BaseHandler
|
from app.classes.web.base_handler import BaseHandler
|
||||||
@ -148,32 +148,6 @@ class AjaxHandler(BaseHandler):
|
|||||||
self.controller.cached_login = "login_1.jpg"
|
self.controller.cached_login = "login_1.jpg"
|
||||||
return
|
return
|
||||||
|
|
||||||
elif page == "unzip_server":
|
|
||||||
path = urllib.parse.unquote(self.get_argument("path", ""))
|
|
||||||
if not path:
|
|
||||||
path = os.path.join(
|
|
||||||
self.controller.project_root,
|
|
||||||
"imports",
|
|
||||||
urllib.parse.unquote(self.get_argument("file", "")),
|
|
||||||
)
|
|
||||||
if Helpers.check_file_exists(path):
|
|
||||||
self.helper.unzip_server(path, exec_user["user_id"])
|
|
||||||
else:
|
|
||||||
user_id = exec_user["user_id"]
|
|
||||||
if user_id:
|
|
||||||
time.sleep(5)
|
|
||||||
user_lang = self.controller.users.get_user_lang_by_id(user_id)
|
|
||||||
self.helper.websocket_helper.broadcast_user(
|
|
||||||
user_id,
|
|
||||||
"send_start_error",
|
|
||||||
{
|
|
||||||
"error": self.helper.translation.translate(
|
|
||||||
"error", "no-file", user_lang
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
elif page == "jar_cache":
|
elif page == "jar_cache":
|
||||||
if not superuser:
|
if not superuser:
|
||||||
self.redirect("/panel/error?error=Not a super user")
|
self.redirect("/panel/error?error=Not a super user")
|
||||||
@ -208,25 +182,3 @@ class AjaxHandler(BaseHandler):
|
|||||||
new_dir = urllib.parse.unquote(self.get_argument("server_dir"))
|
new_dir = urllib.parse.unquote(self.get_argument("server_dir"))
|
||||||
self.controller.update_master_server_dir(new_dir, exec_user["user_id"])
|
self.controller.update_master_server_dir(new_dir, exec_user["user_id"])
|
||||||
return
|
return
|
||||||
|
|
||||||
def check_server_id(self, server_id, page_name):
|
|
||||||
if server_id is None:
|
|
||||||
logger.warning(
|
|
||||||
f"Server ID not defined in {page_name} ajax call ({server_id})"
|
|
||||||
)
|
|
||||||
Console.warning(
|
|
||||||
f"Server ID not defined in {page_name} ajax call ({server_id})"
|
|
||||||
)
|
|
||||||
return
|
|
||||||
server_id = bleach.clean(server_id)
|
|
||||||
|
|
||||||
# does this server id exist?
|
|
||||||
if not self.controller.servers.server_id_exists(server_id):
|
|
||||||
logger.warning(
|
|
||||||
f"Server ID not found in {page_name} ajax call ({server_id})"
|
|
||||||
)
|
|
||||||
Console.warning(
|
|
||||||
f"Server ID not found in {page_name} ajax call ({server_id})"
|
|
||||||
)
|
|
||||||
return
|
|
||||||
return True
|
|
||||||
|
@ -8,6 +8,7 @@ import tornado.web
|
|||||||
from app.classes.models.crafty_permissions import EnumPermissionsCrafty
|
from app.classes.models.crafty_permissions import EnumPermissionsCrafty
|
||||||
from app.classes.models.users import ApiKeys
|
from app.classes.models.users import ApiKeys
|
||||||
from app.classes.shared.helpers import Helpers
|
from app.classes.shared.helpers import Helpers
|
||||||
|
from app.classes.shared.file_helpers import FileHelpers
|
||||||
from app.classes.shared.main_controller import Controller
|
from app.classes.shared.main_controller import Controller
|
||||||
from app.classes.shared.translation import Translation
|
from app.classes.shared.translation import Translation
|
||||||
from app.classes.models.management import DatabaseShortcuts
|
from app.classes.models.management import DatabaseShortcuts
|
||||||
@ -24,15 +25,22 @@ class BaseHandler(tornado.web.RequestHandler):
|
|||||||
helper: Helpers
|
helper: Helpers
|
||||||
controller: Controller
|
controller: Controller
|
||||||
translator: Translation
|
translator: Translation
|
||||||
|
file_helper: FileHelpers
|
||||||
|
|
||||||
# noinspection PyAttributeOutsideInit
|
# noinspection PyAttributeOutsideInit
|
||||||
def initialize(
|
def initialize(
|
||||||
self, helper=None, controller=None, tasks_manager=None, translator=None
|
self,
|
||||||
|
helper=None,
|
||||||
|
controller=None,
|
||||||
|
tasks_manager=None,
|
||||||
|
translator=None,
|
||||||
|
file_helper=None,
|
||||||
):
|
):
|
||||||
self.helper = helper
|
self.helper = helper
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
self.tasks_manager = tasks_manager
|
self.tasks_manager = tasks_manager
|
||||||
self.translator = translator
|
self.translator = translator
|
||||||
|
self.file_helper = file_helper
|
||||||
|
|
||||||
def set_default_headers(self) -> None:
|
def set_default_headers(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -51,6 +51,7 @@ from app.classes.web.routes.api.users.user.pfp import ApiUsersUserPfpHandler
|
|||||||
from app.classes.web.routes.api.users.user.public import ApiUsersUserPublicHandler
|
from app.classes.web.routes.api.users.user.public import ApiUsersUserPublicHandler
|
||||||
from app.classes.web.routes.api.crafty.config.index import ApiCraftyConfigIndexHandler
|
from app.classes.web.routes.api.crafty.config.index import ApiCraftyConfigIndexHandler
|
||||||
from app.classes.web.routes.api.crafty.clogs.index import ApiCraftyLogIndexHandler
|
from app.classes.web.routes.api.crafty.clogs.index import ApiCraftyLogIndexHandler
|
||||||
|
from app.classes.web.routes.api.crafty.imports.index import ApiImportFilesIndexHandler
|
||||||
|
|
||||||
|
|
||||||
def api_handlers(handler_args):
|
def api_handlers(handler_args):
|
||||||
@ -76,6 +77,11 @@ def api_handlers(handler_args):
|
|||||||
ApiCraftyLogIndexHandler,
|
ApiCraftyLogIndexHandler,
|
||||||
handler_args,
|
handler_args,
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
r"/api/v2/import/file/unzip/?",
|
||||||
|
ApiImportFilesIndexHandler,
|
||||||
|
handler_args,
|
||||||
|
),
|
||||||
# User routes
|
# User routes
|
||||||
(
|
(
|
||||||
r"/api/v2/users/?",
|
r"/api/v2/users/?",
|
||||||
|
123
app/classes/web/routes/api/crafty/imports/index.py
Normal file
123
app/classes/web/routes/api/crafty/imports/index.py
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
import os
|
||||||
|
import logging
|
||||||
|
import json
|
||||||
|
import html
|
||||||
|
from jsonschema import validate
|
||||||
|
from jsonschema.exceptions import ValidationError
|
||||||
|
from app.classes.models.crafty_permissions import EnumPermissionsCrafty
|
||||||
|
from app.classes.shared.helpers import Helpers
|
||||||
|
from app.classes.web.base_api_handler import BaseApiHandler
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
files_get_schema = {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"page": {"type": "string", "minLength": 1},
|
||||||
|
"folder": {"type": "string"},
|
||||||
|
"unzip": {"type": "boolean", "default": "True"},
|
||||||
|
},
|
||||||
|
"additionalProperties": False,
|
||||||
|
"minProperties": 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ApiImportFilesIndexHandler(BaseApiHandler):
|
||||||
|
def post(self):
|
||||||
|
auth_data = self.authenticate_user()
|
||||||
|
if not auth_data:
|
||||||
|
return
|
||||||
|
|
||||||
|
if (
|
||||||
|
EnumPermissionsCrafty.SERVER_CREATION
|
||||||
|
not in self.controller.crafty_perms.get_crafty_permissions_list(
|
||||||
|
auth_data[4]["user_id"]
|
||||||
|
)
|
||||||
|
and not auth_data[4]["superuser"]
|
||||||
|
):
|
||||||
|
# if the user doesn't have Files or Backup permission, return an error
|
||||||
|
return self.finish_json(400, {"status": "error", "error": "NOT_AUTHORIZED"})
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = json.loads(self.request.body)
|
||||||
|
except json.decoder.JSONDecodeError as e:
|
||||||
|
return self.finish_json(
|
||||||
|
400, {"status": "error", "error": "INVALID_JSON", "error_data": str(e)}
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
validate(data, files_get_schema)
|
||||||
|
except ValidationError as e:
|
||||||
|
return self.finish_json(
|
||||||
|
400,
|
||||||
|
{
|
||||||
|
"status": "error",
|
||||||
|
"error": "INVALID_JSON_SCHEMA",
|
||||||
|
"error_data": str(e),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
# TODO: limit some columns for specific permissions?
|
||||||
|
folder = data["folder"]
|
||||||
|
user_id = auth_data[4]["user_id"]
|
||||||
|
root_path = False
|
||||||
|
if data["unzip"]:
|
||||||
|
if Helpers.check_file_exists(folder):
|
||||||
|
folder = self.file_helper.unzip_server(folder, user_id)
|
||||||
|
root_path = True
|
||||||
|
else:
|
||||||
|
if user_id:
|
||||||
|
user_lang = self.controller.users.get_user_lang_by_id(user_id)
|
||||||
|
self.helper.websocket_helper.broadcast_user(
|
||||||
|
user_id,
|
||||||
|
"send_start_error",
|
||||||
|
{
|
||||||
|
"error": self.helper.translation.translate(
|
||||||
|
"error", "no-file", user_lang
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
if not self.helper.check_path_exists(folder):
|
||||||
|
if user_id:
|
||||||
|
user_lang = self.controller.users.get_user_lang_by_id(user_id)
|
||||||
|
self.helper.websocket_helper.broadcast_user(
|
||||||
|
user_id,
|
||||||
|
"send_start_error",
|
||||||
|
{
|
||||||
|
"error": self.helper.translation.translate(
|
||||||
|
"error", "no-file", user_lang
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
return_json = {
|
||||||
|
"root_path": {
|
||||||
|
"path": folder,
|
||||||
|
"top": root_path,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dir_list = []
|
||||||
|
unsorted_files = []
|
||||||
|
file_list = os.listdir(folder)
|
||||||
|
for item in file_list:
|
||||||
|
if os.path.isdir(os.path.join(folder, item)):
|
||||||
|
dir_list.append(item)
|
||||||
|
else:
|
||||||
|
unsorted_files.append(item)
|
||||||
|
file_list = sorted(dir_list, key=str.casefold) + sorted(
|
||||||
|
unsorted_files, key=str.casefold
|
||||||
|
)
|
||||||
|
for raw_filename in file_list:
|
||||||
|
filename = html.escape(raw_filename)
|
||||||
|
rel = os.path.join(folder, raw_filename)
|
||||||
|
dpath = os.path.join(folder, filename)
|
||||||
|
dpath = self.helper.wtol_path(dpath)
|
||||||
|
if os.path.isdir(rel):
|
||||||
|
return_json[filename] = {
|
||||||
|
"path": dpath,
|
||||||
|
"dir": True,
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
return_json[filename] = {
|
||||||
|
"path": dpath,
|
||||||
|
"dir": False,
|
||||||
|
}
|
||||||
|
self.finish_json(200, {"status": "ok", "data": return_json})
|
@ -48,13 +48,14 @@ class Webserver:
|
|||||||
controller: Controller
|
controller: Controller
|
||||||
helper: Helpers
|
helper: Helpers
|
||||||
|
|
||||||
def __init__(self, helper, controller, tasks_manager):
|
def __init__(self, helper, controller, tasks_manager, file_helper):
|
||||||
self.ioloop = None
|
self.ioloop = None
|
||||||
self.http_server = None
|
self.http_server = None
|
||||||
self.https_server = None
|
self.https_server = None
|
||||||
self.helper = helper
|
self.helper = helper
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
self.tasks_manager = tasks_manager
|
self.tasks_manager = tasks_manager
|
||||||
|
self.file_helper = file_helper
|
||||||
self._asyncio_patch()
|
self._asyncio_patch()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -146,6 +147,7 @@ class Webserver:
|
|||||||
"controller": self.controller,
|
"controller": self.controller,
|
||||||
"tasks_manager": self.tasks_manager,
|
"tasks_manager": self.tasks_manager,
|
||||||
"translator": self.helper.translation,
|
"translator": self.helper.translation,
|
||||||
|
"file_helper": self.file_helper,
|
||||||
}
|
}
|
||||||
handlers = [
|
handlers = [
|
||||||
(r"/", DefaultHandler, handler_args),
|
(r"/", DefaultHandler, handler_args),
|
||||||
|
@ -18,12 +18,18 @@ class SocketHandler(tornado.websocket.WebSocketHandler):
|
|||||||
io_loop = None
|
io_loop = None
|
||||||
|
|
||||||
def initialize(
|
def initialize(
|
||||||
self, helper=None, controller=None, tasks_manager=None, translator=None
|
self,
|
||||||
|
helper=None,
|
||||||
|
controller=None,
|
||||||
|
tasks_manager=None,
|
||||||
|
translator=None,
|
||||||
|
file_helper=None,
|
||||||
):
|
):
|
||||||
self.helper = helper
|
self.helper = helper
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
self.tasks_manager = tasks_manager
|
self.tasks_manager = tasks_manager
|
||||||
self.translator = translator
|
self.translator = translator
|
||||||
|
self.file_helper = file_helper
|
||||||
self.io_loop = tornado.ioloop.IOLoop.current()
|
self.io_loop = tornado.ioloop.IOLoop.current()
|
||||||
|
|
||||||
def get_remote_ip(self):
|
def get_remote_ip(self):
|
||||||
|
2
main.py
2
main.py
@ -171,7 +171,7 @@ if __name__ == "__main__":
|
|||||||
Console.info("Remote change complete.")
|
Console.info("Remote change complete.")
|
||||||
|
|
||||||
import3 = Import3(helper, controller)
|
import3 = Import3(helper, controller)
|
||||||
tasks_manager = TasksManager(helper, controller)
|
tasks_manager = TasksManager(helper, controller, file_helper)
|
||||||
tasks_manager.start_webserver()
|
tasks_manager.start_webserver()
|
||||||
|
|
||||||
def signal_handler(signum, _frame):
|
def signal_handler(signum, _frame):
|
||||||
|
Loading…
Reference in New Issue
Block a user